@runfusion/fusion 0.77.0-beta.12 → 0.77.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +1636 -903
- package/dist/child-process-worker.js +1064 -466
- package/dist/client/.vite/manifest.json +260 -260
- package/dist/client/assets/AgentDetailView-DPoh46Ym.css +1 -0
- package/dist/client/assets/{AgentDetailView-BZfDgV8f.js → AgentDetailView-DwCr9HOY.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-8yBqnwbx.js → AgentPermissionPolicyEditor-CXRP1R7V.js} +1 -1
- package/dist/client/assets/{AgentsView-BjMOtIMq.js → AgentsView-DEVhP_Ad.js} +3 -3
- package/dist/client/assets/CommandCenter-BshTzOtB.css +1 -0
- package/dist/client/assets/{CommandCenter-CDuO3HPd.js → CommandCenter-sNTR0N1L.js} +22 -22
- package/dist/client/assets/{DevServerView-C96RV0QJ.js → DevServerView-X1Ncu9x-.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-iRielXf7.js → DirectoryPicker-UrDTGJYj.js} +1 -1
- package/dist/client/assets/{DocumentsView-DhAUnUD_.js → DocumentsView-DyyfLF1R.js} +1 -1
- package/dist/client/assets/{EvalsView--n1p2Bt0.js → EvalsView-DgMdhmj1.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-DraglCCV.js → ExperimentalAgentOnboardingModal-DqETOMkr.js} +1 -1
- package/dist/client/assets/{GoalsView-BOWOua5t.js → GoalsView-Cai1_q1j.js} +1 -1
- package/dist/client/assets/{InsightsView-C5YcJZSc.js → InsightsView-DN9i_pr2.js} +1 -1
- package/dist/client/assets/{MemoryView-DsCuGVGx.js → MemoryView-DpVhI_BB.js} +1 -1
- package/dist/client/assets/{PatchnodeView-CzgChkJV.js → PatchnodeView-C9glaWoU.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-qYbmaigE.js → PiExtensionsManager-DkJ3I9ur.js} +1 -1
- package/dist/client/assets/{PluginManager-Cklj4Smo.js → PluginManager-C3BKqDE-.js} +1 -1
- package/dist/client/assets/{PullRequestView-C6vozTTI.js → PullRequestView-BCPolzJY.js} +1 -1
- package/dist/client/assets/{ReportModal-B0LU4E4L.js → ReportModal-CBc5lSf3.js} +1 -1
- package/dist/client/assets/{ResearchView-CpESx46e.js → ResearchView-BInIb1tK.js} +1 -1
- package/dist/client/assets/{SecretsView-8ZdH9Yzs.js → SecretsView-Db2mKOcp.js} +1 -1
- package/dist/client/assets/SettingsModal-BEULP2a7.css +1 -0
- package/dist/client/assets/SettingsModal-Dn9vcqW7.js +21 -0
- package/dist/client/assets/{SettingsModal-BJXu-dhz.js → SettingsModal-tnr4Y2cG.js} +1 -1
- package/dist/client/assets/{SettingsTextareaRow-th-q0_2k.js → SettingsTextareaRow-DDIEo7kX.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-CBElxrRA.js → SetupWizardModal-BgpCpOJi.js} +2 -2
- package/dist/client/assets/{SkillsView-BuoicLbJ.js → SkillsView-C4_dPxaH.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-BDw0LpWM.js → WorkflowNodeEditor-BRIoMtdz.js} +1 -1
- package/dist/client/assets/{agent-import-generation-CNridJHO.js → agent-import-generation-DZjrAuLD.js} +1 -1
- package/dist/client/assets/{agentsOrgChartLayout-BopFGp0r.js → agentsOrgChartLayout-T3vfKGm-.js} +1 -1
- package/dist/client/assets/{app-DKzqBaeH.js → app-BUPxz3_I.js} +1 -1
- package/dist/client/assets/{app-y8x9KYqa.js → app-Bsb-vSJ2.js} +3 -3
- package/dist/client/assets/{app-DkJZhePX.js → app-CDMzhkVk.js} +1 -1
- package/dist/client/assets/{app-BtBMuy2Z.js → app-Ca3_7roP.js} +3 -3
- package/dist/client/assets/{app-JnrgtY9I.js → app-CaiQxtA9.js} +3 -3
- package/dist/client/assets/{app-LrO9EOLE.js → app-D7N3gRgK.js} +3 -3
- package/dist/client/assets/{app-Cv-4fcPl.js → app-Du0s0Xs8.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-2_yoUOD5.js → architectureDiagram-3BPJPVTR-CG7lqp3T.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-ueBSwDJh.js → blockDiagram-GPEHLZMM-CCQyln9-.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-D0cUU3pE.js → c4Diagram-AAUBKEIU-DgTWfMuv.js} +1 -1
- package/dist/client/assets/channel-DQn8tAbt.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-DKJnGdD6.js → chunk-2J33WTMH-DbvgPKWu.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-BUrgUtvt.js → chunk-4BX2VUAB-Jeug78io.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DHy2hCYz.js → chunk-55IACEB6-wSkfWEqo.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-Dgbhllem.js → chunk-727SXJPM-o-cSBR4a.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-tPbicvl-.js → chunk-AQP2D5EJ-9iL_Co48.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-BpHFGFmo.js → chunk-FMBD7UC4-HKJKjpLt.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-DUTQ63ld.js → chunk-ND2GUHAM-DZUdY7Yv.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-ChCf_usL.js → chunk-QZHKN3VN-AFzlVJep.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BVZs0DmH.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BVZs0DmH.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-DgWzHtF9.js → cose-bilkent-S5V4N54A-vhimfYza.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-gQ1C1xHJ.js → dagre-BM42HDAG-wPz2jgXD.js} +1 -1
- package/dist/client/assets/{dashboard-view-BtFepPos.js → dashboard-view-BJVPfjWI.js} +1 -1
- package/dist/client/assets/{dashboard-view-BXtoQ9a4.js → dashboard-view-BN6as5aN.js} +1 -1
- package/dist/client/assets/{dashboard-view-AQmzkBNb.js → dashboard-view-ByLTU9KO.js} +1 -1
- package/dist/client/assets/{dashboard-view-BLenRoXu.js → dashboard-view-HiX6AOAw.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-Dv96I1MI.js → diagram-2AECGRRQ-DvPGnzo9.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-BRyhjYes.js → diagram-5GNKFQAL-CUD0xVXq.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-Bmj3ihjc.js → diagram-KO2AKTUF-p88av64o.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-BYHVCFK2.js → diagram-LMA3HP47-B2V_VFOf.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-0WZBLayt.js → diagram-OG6HWLK6-CO02xKJJ.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Cu-yj8hA.js → erDiagram-TEJ5UH35-LiIZMOks.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BSetu6oh.js → flowDiagram-I6XJVG4X-BMgU0xdB.js} +1 -1
- package/dist/client/assets/{folder-open-CkswT0lE.js → folder-open-Bfz0pfA0.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-B5qn0KFQ.js → ganttDiagram-6RSMTGT7-C-DNnJ7F.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-BVB3wm46.js → gitGraphDiagram-PVQCEYII-BKnH_s4c.js} +1 -1
- package/dist/client/assets/index-D6zw4rNc.js +2937 -0
- package/dist/client/assets/index-lxhrCjd_.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-ZBNKOBSK.js → infoDiagram-5YYISTIA-DrFgtiS_.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CbNKgenI.js → ishikawaDiagram-YF4QCWOH-cXcVkWVR.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BLc2FHIF.js → journeyDiagram-JHISSGLW-2rAR6JrI.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-B08tij8f.js → kanban-definition-UN3LZRKU-uaIVKg6k.js} +1 -1
- package/dist/client/assets/{mermaid.core-QX5z7w8Z.js → mermaid.core-Bl1eKb-3.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-C1md8M3c.js → mindmap-definition-RKZ34NQL-C_ZfL855.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-BoQbn3Xp.js → pieDiagram-4H26LBE5-B-GWMxe6.js} +1 -1
- package/dist/client/assets/{puzzle-DCqPnWPE.js → puzzle--EYtEUHj.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DPvNcVK-.js → quadrantDiagram-W4KKPZXB-C4yu-vxx.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-KfdYf15t.js → requirementDiagram-4Y6WPE33-CmsMO-mZ.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-D1Eyoanf.js → sankeyDiagram-5OEKKPKP-DKXXMJDr.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CmODsbCf.js → sequenceDiagram-3UESZ5HK-DbpptsX5.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-D_mPaGcG.js → standing-instructions-template-bCcrFYtU.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-Blbw_21G.js → stateDiagram-AJRCARHV-DDwdEj_k.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-DwMgvYO8.js → stateDiagram-v2-BHNVJYJU-CjOnclTc.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-DDtndgLc.js → timeline-definition-PNZ67QCA-Q8Appf3Z.js} +1 -1
- package/dist/client/assets/{upload-DGCjJkMH.js → upload-Ka3GrAEL.js} +1 -1
- package/dist/client/assets/{users-CbWZvFZP.js → users-B7a_oi7v.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-B6Sx0OqW.js → vennDiagram-CIIHVFJN-ZsuVN3Hk.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-_SQFYU4g.js → wardley-L42UT6IY-Eh9WyxS2.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Ce5igv6s.js → wardleyDiagram-YWT4CUSO-CG1fl8Sj.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-zI0zyvDP.js → xychartDiagram-2RQKCTM6-BnZAlrGh.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/extension.js +1479 -798
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/plugin-sdk/index.d.ts +1 -1
- package/dist/plugin-sdk/index.js +25 -14
- package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
- package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
- package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
- package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-linear-import/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
- package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-quality/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-quality/package.json +1 -1
- package/dist/plugins/fusion-plugin-reports/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-reports/package.json +1 -1
- package/dist/plugins/fusion-plugin-roadmap/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
- package/dist/plugins/fusion-plugin-todos/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-todos/package.json +1 -1
- package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +25 -14
- package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/AgentDetailView-jzgy1BAS.css +0 -1
- package/dist/client/assets/CommandCenter-ilm-DbtI.css +0 -1
- package/dist/client/assets/SettingsModal-B1UCDc_h.js +0 -21
- package/dist/client/assets/SettingsModal-C5ic1ls7.css +0 -1
- package/dist/client/assets/channel-DfvbdnTK.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-CkMyClXV.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CkMyClXV.js +0 -1
- package/dist/client/assets/index-BgE915SE.js +0 -2937
- package/dist/client/assets/index-e2yEk7y4.css +0 -1
|
@@ -1592,6 +1592,199 @@ Be specific: cite the plan section or file path for every finding and explain th
|
|
|
1592
1592
|
}
|
|
1593
1593
|
});
|
|
1594
1594
|
|
|
1595
|
+
// ../core/src/workflows/workflow-merge-region.ts
|
|
1596
|
+
function isMergeRegionNode(node) {
|
|
1597
|
+
return MERGE_REGION_ENTRY_NODE_KINDS.has(node.kind) || node.config?.seam === "merge";
|
|
1598
|
+
}
|
|
1599
|
+
function classifyWorkflowNodeMergeRegion(ir2, nodeId) {
|
|
1600
|
+
if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return "unknown";
|
|
1601
|
+
const node = ir2.nodes.find((candidate) => candidate.id === nodeId);
|
|
1602
|
+
if (!node) return "unknown";
|
|
1603
|
+
return isMergeRegionNode(node) ? "merge-region" : "outside-merge-region";
|
|
1604
|
+
}
|
|
1605
|
+
var MERGE_REGION_ENTRY_NODE_KINDS;
|
|
1606
|
+
var init_workflow_merge_region = __esm({
|
|
1607
|
+
"../core/src/workflows/workflow-merge-region.ts"() {
|
|
1608
|
+
"use strict";
|
|
1609
|
+
MERGE_REGION_ENTRY_NODE_KINDS = /* @__PURE__ */ new Set([
|
|
1610
|
+
"merge-gate",
|
|
1611
|
+
"merge-attempt",
|
|
1612
|
+
"manual-merge-hold",
|
|
1613
|
+
"retry-backoff",
|
|
1614
|
+
"recovery-router",
|
|
1615
|
+
"branch-group-member-integration",
|
|
1616
|
+
"branch-group-promotion",
|
|
1617
|
+
"pr-create",
|
|
1618
|
+
"pr-respond",
|
|
1619
|
+
"pr-merge"
|
|
1620
|
+
]);
|
|
1621
|
+
}
|
|
1622
|
+
});
|
|
1623
|
+
|
|
1624
|
+
// ../core/src/workflows/workflow-optional-steps.ts
|
|
1625
|
+
function isWorkflowOptionalGroupEnabled(enabledWorkflowSteps, groupId, defaultOn = false) {
|
|
1626
|
+
return Array.isArray(enabledWorkflowSteps) ? enabledWorkflowSteps.includes(groupId) : defaultOn;
|
|
1627
|
+
}
|
|
1628
|
+
function isOptionalGroupNode(node) {
|
|
1629
|
+
return node.kind === "optional-group";
|
|
1630
|
+
}
|
|
1631
|
+
function computeNodeExecutionRanks(ir2) {
|
|
1632
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
1633
|
+
if (ir2.version !== "v2" || !Array.isArray(ir2.nodes) || !Array.isArray(ir2.edges)) {
|
|
1634
|
+
return ranks;
|
|
1635
|
+
}
|
|
1636
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
1637
|
+
for (const edge of ir2.edges) {
|
|
1638
|
+
if (!outgoing.has(edge.from)) outgoing.set(edge.from, []);
|
|
1639
|
+
outgoing.get(edge.from)?.push(edge.to);
|
|
1640
|
+
}
|
|
1641
|
+
const queue = [];
|
|
1642
|
+
for (const node of ir2.nodes) {
|
|
1643
|
+
if (node.kind === "start" || node.id === "start") {
|
|
1644
|
+
queue.push({ id: node.id, rank: 0 });
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
while (queue.length > 0) {
|
|
1648
|
+
const next = queue.shift();
|
|
1649
|
+
if (!next) continue;
|
|
1650
|
+
const current = ranks.get(next.id);
|
|
1651
|
+
if (current !== void 0 && current <= next.rank) continue;
|
|
1652
|
+
ranks.set(next.id, next.rank);
|
|
1653
|
+
for (const target of outgoing.get(next.id) ?? []) {
|
|
1654
|
+
queue.push({ id: target, rank: next.rank + 1 });
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return ranks;
|
|
1658
|
+
}
|
|
1659
|
+
function resolveWorkflowOptionalSteps(ir2, _pluginTemplates = []) {
|
|
1660
|
+
if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return [];
|
|
1661
|
+
const ranks = computeNodeExecutionRanks(ir2);
|
|
1662
|
+
const resolved = [];
|
|
1663
|
+
for (const [nodeIndex, node] of ir2.nodes.entries()) {
|
|
1664
|
+
if (!isOptionalGroupNode(node)) continue;
|
|
1665
|
+
const config3 = node.config ?? {};
|
|
1666
|
+
resolved.push({
|
|
1667
|
+
// Keyed by the group node id (documented above); field name preserved.
|
|
1668
|
+
templateId: node.id,
|
|
1669
|
+
name: typeof config3.name === "string" && config3.name.trim() ? config3.name : node.id,
|
|
1670
|
+
description: "",
|
|
1671
|
+
/*
|
|
1672
|
+
FNXC:WorkflowOptionalSteps 2026-06-29-12:47:
|
|
1673
|
+
Post-merge verification is now a graph-native optional group. Task creation and detail surfaces need the resolver to preserve `config.phase` so post-merge toggles do not look like pre-merge gates.
|
|
1674
|
+
*/
|
|
1675
|
+
phase: config3.phase === "post-merge" ? "post-merge" : "pre-merge",
|
|
1676
|
+
defaultOn: config3.defaultOn === true,
|
|
1677
|
+
reportingOnly: config3.reportingOnly === true,
|
|
1678
|
+
/*
|
|
1679
|
+
FNXC:WorkflowDefinitionSteps 2026-06-29-00:41:
|
|
1680
|
+
Definition/task creation surfaces must order optional groups by graph execution position, not raw node-array order. Derived built-ins can insert Plan Review between planning and parse while appending its node object, and operators still need the step list to show Plan Review before execution.
|
|
1681
|
+
*/
|
|
1682
|
+
rank: ranks.get(node.id) ?? Number.MAX_SAFE_INTEGER,
|
|
1683
|
+
nodeIndex
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
return resolved.sort((a, b3) => a.rank - b3.rank || a.nodeIndex - b3.nodeIndex).map(({ rank: _rank, nodeIndex: _nodeIndex, ...step }) => step);
|
|
1687
|
+
}
|
|
1688
|
+
function resolveDefaultOnOptionalGroupIds(ir2) {
|
|
1689
|
+
return resolveWorkflowOptionalSteps(ir2).filter((step) => step.defaultOn).map((step) => step.templateId);
|
|
1690
|
+
}
|
|
1691
|
+
function resolveAllOptionalGroupIds(ir2) {
|
|
1692
|
+
return resolveWorkflowOptionalSteps(ir2).map((step) => step.templateId);
|
|
1693
|
+
}
|
|
1694
|
+
function isReportingOnlyOptionalGroup(ir2, nodeId) {
|
|
1695
|
+
if (!nodeId) return false;
|
|
1696
|
+
return resolveWorkflowOptionalSteps(ir2).some((step) => step.templateId === nodeId && step.reportingOnly);
|
|
1697
|
+
}
|
|
1698
|
+
var init_workflow_optional_steps = __esm({
|
|
1699
|
+
"../core/src/workflows/workflow-optional-steps.ts"() {
|
|
1700
|
+
"use strict";
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
|
|
1704
|
+
// ../core/src/workflows/workflow-fast-lane.ts
|
|
1705
|
+
function isFastExecutionMode(task) {
|
|
1706
|
+
return task.executionMode === "fast";
|
|
1707
|
+
}
|
|
1708
|
+
function configString(node, key) {
|
|
1709
|
+
const value = node.config?.[key];
|
|
1710
|
+
return typeof value === "string" ? value : void 0;
|
|
1711
|
+
}
|
|
1712
|
+
function isTaskStepsForeach(node) {
|
|
1713
|
+
return node.kind === "foreach" && node.config?.source === "task-steps";
|
|
1714
|
+
}
|
|
1715
|
+
function isFastLaneSkippableCustomNode(node, opts = {}) {
|
|
1716
|
+
if (node.config?.summaryTarget === "task" || node.id === "completion-summary") return false;
|
|
1717
|
+
if (opts.optionalGroupId) return false;
|
|
1718
|
+
if (node.config?.seam) return false;
|
|
1719
|
+
return node.kind === "prompt" || node.kind === "script" || node.kind === "gate";
|
|
1720
|
+
}
|
|
1721
|
+
function isFastLaneBypassedTemplateNode(node) {
|
|
1722
|
+
return node.kind === "step-review";
|
|
1723
|
+
}
|
|
1724
|
+
function inactiveRoute() {
|
|
1725
|
+
return {
|
|
1726
|
+
active: false,
|
|
1727
|
+
bypassedNodeIds: /* @__PURE__ */ new Set(),
|
|
1728
|
+
bypassedPreMergeGroups: [],
|
|
1729
|
+
parseStepsNodeIds: /* @__PURE__ */ new Set()
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
function resolveFastLaneRoute(ir2, task) {
|
|
1733
|
+
if (!isFastExecutionMode(task)) return inactiveRoute();
|
|
1734
|
+
const foreachNode = ir2.nodes.find(isTaskStepsForeach);
|
|
1735
|
+
const executeNode = ir2.nodes.find((node) => configString(node, "seam") === "execute");
|
|
1736
|
+
const implementationNode = foreachNode ?? executeNode;
|
|
1737
|
+
if (!implementationNode) {
|
|
1738
|
+
return { ...inactiveRoute(), unsupportedReason: "no-implementation-node" };
|
|
1739
|
+
}
|
|
1740
|
+
const implementationKind = foreachNode ? "foreach-steps" : "execute-seam";
|
|
1741
|
+
const bypassedPreMergeGroups = resolveWorkflowOptionalSteps(ir2).filter((step) => step.phase === "pre-merge").map((step) => ({ nodeId: step.templateId, name: step.name }));
|
|
1742
|
+
const bypassedGroupIds = new Set(bypassedPreMergeGroups.map((group) => group.nodeId));
|
|
1743
|
+
const bypassedNodeIds = /* @__PURE__ */ new Set();
|
|
1744
|
+
for (const node of ir2.nodes) {
|
|
1745
|
+
if (isMergeRegionNode(node) || node.id === "completion-summary" || node.config?.summaryTarget === "task") continue;
|
|
1746
|
+
if (configString(node, "seam") === "planning") {
|
|
1747
|
+
bypassedNodeIds.add(node.id);
|
|
1748
|
+
continue;
|
|
1749
|
+
}
|
|
1750
|
+
if (bypassedGroupIds.has(node.id)) {
|
|
1751
|
+
bypassedNodeIds.add(node.id);
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1754
|
+
const workflowAction = configString(node, "workflowAction");
|
|
1755
|
+
const groupId = configString(node, "forWorkflowStepId");
|
|
1756
|
+
if (workflowAction === "plan-replan" || workflowAction === "plan-review-no-op" || workflowAction === "pre-merge-remediation" || workflowAction === "review-remediation-steps" || groupId !== void 0 && bypassedGroupIds.has(groupId)) {
|
|
1757
|
+
bypassedNodeIds.add(node.id);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
const parseStepsNodeIds = new Set(ir2.nodes.filter((node) => node.kind === "parse-steps").map((node) => node.id));
|
|
1761
|
+
for (const parseNodeId of parseStepsNodeIds) {
|
|
1762
|
+
if (bypassedNodeIds.has(parseNodeId)) {
|
|
1763
|
+
throw new Error(`Fast lane cannot bypass parse-steps node '${parseNodeId}'`);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
return {
|
|
1767
|
+
active: true,
|
|
1768
|
+
bypassedNodeIds,
|
|
1769
|
+
bypassedPreMergeGroups,
|
|
1770
|
+
parseStepsNodeIds,
|
|
1771
|
+
implementationNodeId: implementationNode.id,
|
|
1772
|
+
implementationKind
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
var FAST_LANE_STEP_NAME, FAST_LANE_SKIP_VALUE, FAST_MODE_BYPASS_ACTOR, FAST_LANE_STEP_REVIEW_ROUTE_VALUE;
|
|
1776
|
+
var init_workflow_fast_lane = __esm({
|
|
1777
|
+
"../core/src/workflows/workflow-fast-lane.ts"() {
|
|
1778
|
+
"use strict";
|
|
1779
|
+
init_workflow_merge_region();
|
|
1780
|
+
init_workflow_optional_steps();
|
|
1781
|
+
FAST_LANE_STEP_NAME = "Fast implementation";
|
|
1782
|
+
FAST_LANE_SKIP_VALUE = "fast-lane-skip";
|
|
1783
|
+
FAST_MODE_BYPASS_ACTOR = "fast-mode";
|
|
1784
|
+
FAST_LANE_STEP_REVIEW_ROUTE_VALUE = "approve";
|
|
1785
|
+
}
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1595
1788
|
// ../core/src/workflows/workflow-step-results.ts
|
|
1596
1789
|
function isWorkflowStepNotRun(result) {
|
|
1597
1790
|
return result.status === "skipped" && typeof result.notRunReason === "string" && WORKFLOW_STEP_NOT_RUN_REASONS.includes(result.notRunReason);
|
|
@@ -1892,6 +2085,31 @@ var init_workflow_step_results = __esm({
|
|
|
1892
2085
|
});
|
|
1893
2086
|
|
|
1894
2087
|
// ../core/src/merge/pre-merge-approval.ts
|
|
2088
|
+
function requiresContentReviewProof(workflowStepId, result) {
|
|
2089
|
+
return workflowStepId === "code-review" || result.reviewKind === "code";
|
|
2090
|
+
}
|
|
2091
|
+
function isAuditedOperatorBypass(result) {
|
|
2092
|
+
if (result.status !== "skipped") return false;
|
|
2093
|
+
const actor = result.bypassedBy?.trim();
|
|
2094
|
+
return Boolean(
|
|
2095
|
+
actor && !AUTOMATED_BYPASS_ACTORS.has(actor) && result.bypassedAt?.trim() && result.bypassReason?.trim()
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
2098
|
+
function resolveUnprovenReviewApproval(result, options) {
|
|
2099
|
+
if ((result.phase ?? "pre-merge") !== "pre-merge" || !requiresContentReviewProof(result.workflowStepId, result) || options.workspace || result.status !== "passed" || result.verdict !== "APPROVE" && result.verdict !== "APPROVE_WITH_NOTES" || result.reviewInputFingerprint !== void 0 || result.bypassedBy !== void 0 || result.remediationArchivedAt != null) {
|
|
2100
|
+
return void 0;
|
|
2101
|
+
}
|
|
2102
|
+
const { verdict: _verdict, ...withoutVerdict } = result;
|
|
2103
|
+
return {
|
|
2104
|
+
downgraded: {
|
|
2105
|
+
...withoutVerdict,
|
|
2106
|
+
status: "failed",
|
|
2107
|
+
output: UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC,
|
|
2108
|
+
notes: UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC
|
|
2109
|
+
},
|
|
2110
|
+
reason: UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
1895
2113
|
function evaluatePreMergeApprovals(task, options = {}) {
|
|
1896
2114
|
const required2 = options.requiredPreMergeStepIds;
|
|
1897
2115
|
if (!required2?.size) return [];
|
|
@@ -1902,13 +2120,16 @@ function evaluateStep(workflowStepId, results, task, descriptor) {
|
|
|
1902
2120
|
const result = results.filter((candidate) => candidate.workflowStepId === workflowStepId).at(-1);
|
|
1903
2121
|
if (!result && descriptor?.kind !== "workspace") return { workflowStepId, state: "missing" };
|
|
1904
2122
|
if (result) {
|
|
1905
|
-
const requiresExplicitVerdict = workflowStepId
|
|
2123
|
+
const requiresExplicitVerdict = requiresContentReviewProof(workflowStepId, result);
|
|
1906
2124
|
const approvedVerdict = result.verdict === "APPROVE" || result.verdict === "APPROVE_WITH_NOTES";
|
|
1907
2125
|
const isPlanDomain = workflowStepId === PLAN_REVIEW_GROUP_ID || result.reviewKind === "plan";
|
|
1908
2126
|
const notRunApproves = isWorkflowStepNotRun(result) && !requiresExplicitVerdict && !isPlanDomain;
|
|
1909
2127
|
const approved = result.status === "passed" && (requiresExplicitVerdict ? approvedVerdict : result.verdict === void 0 || approvedVerdict) || result.status === "skipped" && !!result.bypassedBy || notRunApproves;
|
|
1910
2128
|
if (!approved || !!result.remediationArchivedAt) return { workflowStepId, state: "not-approved" };
|
|
1911
2129
|
if (result.reviewKind === "plan") return { workflowStepId, state: "approved" };
|
|
2130
|
+
if (isAuditedOperatorBypass(result) && descriptor?.kind !== "workspace") {
|
|
2131
|
+
return { workflowStepId, state: "approved" };
|
|
2132
|
+
}
|
|
1912
2133
|
const bindsContent = requiresExplicitVerdict || result.reviewInputFingerprint !== void 0;
|
|
1913
2134
|
if (!bindsContent) return { workflowStepId, state: "approved" };
|
|
1914
2135
|
}
|
|
@@ -1939,11 +2160,15 @@ function evaluateStep(workflowStepId, results, task, descriptor) {
|
|
|
1939
2160
|
if (stale.length) return { workflowStepId, state: "stale-content", repositories: stale };
|
|
1940
2161
|
return { workflowStepId, state: "approved" };
|
|
1941
2162
|
}
|
|
2163
|
+
var AUTOMATED_BYPASS_ACTORS, UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC;
|
|
1942
2164
|
var init_pre_merge_approval = __esm({
|
|
1943
2165
|
"../core/src/merge/pre-merge-approval.ts"() {
|
|
1944
2166
|
"use strict";
|
|
1945
2167
|
init_builtin_plan_review_group();
|
|
2168
|
+
init_workflow_fast_lane();
|
|
1946
2169
|
init_workflow_step_results();
|
|
2170
|
+
AUTOMATED_BYPASS_ACTORS = /* @__PURE__ */ new Set([FAST_MODE_BYPASS_ACTOR]);
|
|
2171
|
+
UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC = "Content-binding review approval recorded without reviewInputFingerprint; approval invalidated so the gate can run again.";
|
|
1947
2172
|
}
|
|
1948
2173
|
});
|
|
1949
2174
|
|
|
@@ -11453,35 +11678,6 @@ var init_workflow_ir_types = __esm({
|
|
|
11453
11678
|
}
|
|
11454
11679
|
});
|
|
11455
11680
|
|
|
11456
|
-
// ../core/src/workflows/workflow-merge-region.ts
|
|
11457
|
-
function isMergeRegionNode(node) {
|
|
11458
|
-
return MERGE_REGION_ENTRY_NODE_KINDS.has(node.kind) || node.config?.seam === "merge";
|
|
11459
|
-
}
|
|
11460
|
-
function classifyWorkflowNodeMergeRegion(ir2, nodeId) {
|
|
11461
|
-
if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return "unknown";
|
|
11462
|
-
const node = ir2.nodes.find((candidate) => candidate.id === nodeId);
|
|
11463
|
-
if (!node) return "unknown";
|
|
11464
|
-
return isMergeRegionNode(node) ? "merge-region" : "outside-merge-region";
|
|
11465
|
-
}
|
|
11466
|
-
var MERGE_REGION_ENTRY_NODE_KINDS;
|
|
11467
|
-
var init_workflow_merge_region = __esm({
|
|
11468
|
-
"../core/src/workflows/workflow-merge-region.ts"() {
|
|
11469
|
-
"use strict";
|
|
11470
|
-
MERGE_REGION_ENTRY_NODE_KINDS = /* @__PURE__ */ new Set([
|
|
11471
|
-
"merge-gate",
|
|
11472
|
-
"merge-attempt",
|
|
11473
|
-
"manual-merge-hold",
|
|
11474
|
-
"retry-backoff",
|
|
11475
|
-
"recovery-router",
|
|
11476
|
-
"branch-group-member-integration",
|
|
11477
|
-
"branch-group-promotion",
|
|
11478
|
-
"pr-create",
|
|
11479
|
-
"pr-respond",
|
|
11480
|
-
"pr-merge"
|
|
11481
|
-
]);
|
|
11482
|
-
}
|
|
11483
|
-
});
|
|
11484
|
-
|
|
11485
11681
|
// ../core/src/workflows/workflow-extension-types.ts
|
|
11486
11682
|
function workflowExtensionRegistryId(pluginId, extensionId) {
|
|
11487
11683
|
return `plugin:${pluginId}:${extensionId}`;
|
|
@@ -12477,6 +12673,16 @@ function validateReviewerAgentOverrides(nodes2) {
|
|
|
12477
12673
|
if (Array.isArray(templateNodes)) validateReviewerAgentOverrides(templateNodes);
|
|
12478
12674
|
}
|
|
12479
12675
|
}
|
|
12676
|
+
function validateReadonlyMcpServersConfig(nodes2) {
|
|
12677
|
+
for (const node of nodes2) {
|
|
12678
|
+
const value = node.config?.readonlyMcpServers;
|
|
12679
|
+
if (value !== void 0 && (!Array.isArray(value) || value.some((name2) => typeof name2 !== "string" || !name2.trim()))) {
|
|
12680
|
+
throw new WorkflowIrError(`Workflow node '${node.id}' readonlyMcpServers must be an array of non-empty strings when present`);
|
|
12681
|
+
}
|
|
12682
|
+
const templateNodes = node.config?.template?.nodes;
|
|
12683
|
+
if (Array.isArray(templateNodes)) validateReadonlyMcpServersConfig(templateNodes);
|
|
12684
|
+
}
|
|
12685
|
+
}
|
|
12480
12686
|
function validateThinkingLevelConfig(nodes2) {
|
|
12481
12687
|
for (const node of nodes2) {
|
|
12482
12688
|
const value = node.config?.thinkingLevel;
|
|
@@ -13091,6 +13297,7 @@ function validateV2(ir2) {
|
|
|
13091
13297
|
const topLevelIds = new Set(ir2.nodes.map((n) => n.id));
|
|
13092
13298
|
validateStepExecutePlacement(ir2.nodes);
|
|
13093
13299
|
validateThinkingLevelConfig(ir2.nodes);
|
|
13300
|
+
validateReadonlyMcpServersConfig(ir2.nodes);
|
|
13094
13301
|
validateCredentialInstanceIdConfig(ir2.nodes);
|
|
13095
13302
|
validateReviewerAgentOverrides(ir2.nodes);
|
|
13096
13303
|
for (const node of ir2.nodes) {
|
|
@@ -29161,169 +29368,6 @@ var init_explicit_duplicate_marker = __esm({
|
|
|
29161
29368
|
}
|
|
29162
29369
|
});
|
|
29163
29370
|
|
|
29164
|
-
// ../core/src/workflows/workflow-optional-steps.ts
|
|
29165
|
-
function isWorkflowOptionalGroupEnabled(enabledWorkflowSteps, groupId, defaultOn = false) {
|
|
29166
|
-
return Array.isArray(enabledWorkflowSteps) ? enabledWorkflowSteps.includes(groupId) : defaultOn;
|
|
29167
|
-
}
|
|
29168
|
-
function isOptionalGroupNode(node) {
|
|
29169
|
-
return node.kind === "optional-group";
|
|
29170
|
-
}
|
|
29171
|
-
function computeNodeExecutionRanks(ir2) {
|
|
29172
|
-
const ranks = /* @__PURE__ */ new Map();
|
|
29173
|
-
if (ir2.version !== "v2" || !Array.isArray(ir2.nodes) || !Array.isArray(ir2.edges)) {
|
|
29174
|
-
return ranks;
|
|
29175
|
-
}
|
|
29176
|
-
const outgoing = /* @__PURE__ */ new Map();
|
|
29177
|
-
for (const edge of ir2.edges) {
|
|
29178
|
-
if (!outgoing.has(edge.from)) outgoing.set(edge.from, []);
|
|
29179
|
-
outgoing.get(edge.from)?.push(edge.to);
|
|
29180
|
-
}
|
|
29181
|
-
const queue = [];
|
|
29182
|
-
for (const node of ir2.nodes) {
|
|
29183
|
-
if (node.kind === "start" || node.id === "start") {
|
|
29184
|
-
queue.push({ id: node.id, rank: 0 });
|
|
29185
|
-
}
|
|
29186
|
-
}
|
|
29187
|
-
while (queue.length > 0) {
|
|
29188
|
-
const next = queue.shift();
|
|
29189
|
-
if (!next) continue;
|
|
29190
|
-
const current = ranks.get(next.id);
|
|
29191
|
-
if (current !== void 0 && current <= next.rank) continue;
|
|
29192
|
-
ranks.set(next.id, next.rank);
|
|
29193
|
-
for (const target of outgoing.get(next.id) ?? []) {
|
|
29194
|
-
queue.push({ id: target, rank: next.rank + 1 });
|
|
29195
|
-
}
|
|
29196
|
-
}
|
|
29197
|
-
return ranks;
|
|
29198
|
-
}
|
|
29199
|
-
function resolveWorkflowOptionalSteps(ir2, _pluginTemplates = []) {
|
|
29200
|
-
if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return [];
|
|
29201
|
-
const ranks = computeNodeExecutionRanks(ir2);
|
|
29202
|
-
const resolved = [];
|
|
29203
|
-
for (const [nodeIndex, node] of ir2.nodes.entries()) {
|
|
29204
|
-
if (!isOptionalGroupNode(node)) continue;
|
|
29205
|
-
const config3 = node.config ?? {};
|
|
29206
|
-
resolved.push({
|
|
29207
|
-
// Keyed by the group node id (documented above); field name preserved.
|
|
29208
|
-
templateId: node.id,
|
|
29209
|
-
name: typeof config3.name === "string" && config3.name.trim() ? config3.name : node.id,
|
|
29210
|
-
description: "",
|
|
29211
|
-
/*
|
|
29212
|
-
FNXC:WorkflowOptionalSteps 2026-06-29-12:47:
|
|
29213
|
-
Post-merge verification is now a graph-native optional group. Task creation and detail surfaces need the resolver to preserve `config.phase` so post-merge toggles do not look like pre-merge gates.
|
|
29214
|
-
*/
|
|
29215
|
-
phase: config3.phase === "post-merge" ? "post-merge" : "pre-merge",
|
|
29216
|
-
defaultOn: config3.defaultOn === true,
|
|
29217
|
-
reportingOnly: config3.reportingOnly === true,
|
|
29218
|
-
/*
|
|
29219
|
-
FNXC:WorkflowDefinitionSteps 2026-06-29-00:41:
|
|
29220
|
-
Definition/task creation surfaces must order optional groups by graph execution position, not raw node-array order. Derived built-ins can insert Plan Review between planning and parse while appending its node object, and operators still need the step list to show Plan Review before execution.
|
|
29221
|
-
*/
|
|
29222
|
-
rank: ranks.get(node.id) ?? Number.MAX_SAFE_INTEGER,
|
|
29223
|
-
nodeIndex
|
|
29224
|
-
});
|
|
29225
|
-
}
|
|
29226
|
-
return resolved.sort((a, b3) => a.rank - b3.rank || a.nodeIndex - b3.nodeIndex).map(({ rank: _rank, nodeIndex: _nodeIndex, ...step }) => step);
|
|
29227
|
-
}
|
|
29228
|
-
function resolveDefaultOnOptionalGroupIds(ir2) {
|
|
29229
|
-
return resolveWorkflowOptionalSteps(ir2).filter((step) => step.defaultOn).map((step) => step.templateId);
|
|
29230
|
-
}
|
|
29231
|
-
function resolveAllOptionalGroupIds(ir2) {
|
|
29232
|
-
return resolveWorkflowOptionalSteps(ir2).map((step) => step.templateId);
|
|
29233
|
-
}
|
|
29234
|
-
function isReportingOnlyOptionalGroup(ir2, nodeId) {
|
|
29235
|
-
if (!nodeId) return false;
|
|
29236
|
-
return resolveWorkflowOptionalSteps(ir2).some((step) => step.templateId === nodeId && step.reportingOnly);
|
|
29237
|
-
}
|
|
29238
|
-
var init_workflow_optional_steps = __esm({
|
|
29239
|
-
"../core/src/workflows/workflow-optional-steps.ts"() {
|
|
29240
|
-
"use strict";
|
|
29241
|
-
}
|
|
29242
|
-
});
|
|
29243
|
-
|
|
29244
|
-
// ../core/src/workflows/workflow-fast-lane.ts
|
|
29245
|
-
function isFastExecutionMode(task) {
|
|
29246
|
-
return task.executionMode === "fast";
|
|
29247
|
-
}
|
|
29248
|
-
function configString(node, key) {
|
|
29249
|
-
const value = node.config?.[key];
|
|
29250
|
-
return typeof value === "string" ? value : void 0;
|
|
29251
|
-
}
|
|
29252
|
-
function isTaskStepsForeach(node) {
|
|
29253
|
-
return node.kind === "foreach" && node.config?.source === "task-steps";
|
|
29254
|
-
}
|
|
29255
|
-
function isFastLaneSkippableCustomNode(node, opts = {}) {
|
|
29256
|
-
if (node.config?.summaryTarget === "task" || node.id === "completion-summary") return false;
|
|
29257
|
-
if (opts.optionalGroupId) return false;
|
|
29258
|
-
if (node.config?.seam) return false;
|
|
29259
|
-
return node.kind === "prompt" || node.kind === "script" || node.kind === "gate";
|
|
29260
|
-
}
|
|
29261
|
-
function isFastLaneBypassedTemplateNode(node) {
|
|
29262
|
-
return node.kind === "step-review";
|
|
29263
|
-
}
|
|
29264
|
-
function inactiveRoute() {
|
|
29265
|
-
return {
|
|
29266
|
-
active: false,
|
|
29267
|
-
bypassedNodeIds: /* @__PURE__ */ new Set(),
|
|
29268
|
-
bypassedPreMergeGroups: [],
|
|
29269
|
-
parseStepsNodeIds: /* @__PURE__ */ new Set()
|
|
29270
|
-
};
|
|
29271
|
-
}
|
|
29272
|
-
function resolveFastLaneRoute(ir2, task) {
|
|
29273
|
-
if (!isFastExecutionMode(task)) return inactiveRoute();
|
|
29274
|
-
const foreachNode = ir2.nodes.find(isTaskStepsForeach);
|
|
29275
|
-
const executeNode = ir2.nodes.find((node) => configString(node, "seam") === "execute");
|
|
29276
|
-
const implementationNode = foreachNode ?? executeNode;
|
|
29277
|
-
if (!implementationNode) {
|
|
29278
|
-
return { ...inactiveRoute(), unsupportedReason: "no-implementation-node" };
|
|
29279
|
-
}
|
|
29280
|
-
const implementationKind = foreachNode ? "foreach-steps" : "execute-seam";
|
|
29281
|
-
const bypassedPreMergeGroups = resolveWorkflowOptionalSteps(ir2).filter((step) => step.phase === "pre-merge").map((step) => ({ nodeId: step.templateId, name: step.name }));
|
|
29282
|
-
const bypassedGroupIds = new Set(bypassedPreMergeGroups.map((group) => group.nodeId));
|
|
29283
|
-
const bypassedNodeIds = /* @__PURE__ */ new Set();
|
|
29284
|
-
for (const node of ir2.nodes) {
|
|
29285
|
-
if (isMergeRegionNode(node) || node.id === "completion-summary" || node.config?.summaryTarget === "task") continue;
|
|
29286
|
-
if (configString(node, "seam") === "planning") {
|
|
29287
|
-
bypassedNodeIds.add(node.id);
|
|
29288
|
-
continue;
|
|
29289
|
-
}
|
|
29290
|
-
if (bypassedGroupIds.has(node.id)) {
|
|
29291
|
-
bypassedNodeIds.add(node.id);
|
|
29292
|
-
continue;
|
|
29293
|
-
}
|
|
29294
|
-
const workflowAction = configString(node, "workflowAction");
|
|
29295
|
-
const groupId = configString(node, "forWorkflowStepId");
|
|
29296
|
-
if (workflowAction === "plan-replan" || workflowAction === "plan-review-no-op" || workflowAction === "pre-merge-remediation" || workflowAction === "review-remediation-steps" || groupId !== void 0 && bypassedGroupIds.has(groupId)) {
|
|
29297
|
-
bypassedNodeIds.add(node.id);
|
|
29298
|
-
}
|
|
29299
|
-
}
|
|
29300
|
-
const parseStepsNodeIds = new Set(ir2.nodes.filter((node) => node.kind === "parse-steps").map((node) => node.id));
|
|
29301
|
-
for (const parseNodeId of parseStepsNodeIds) {
|
|
29302
|
-
if (bypassedNodeIds.has(parseNodeId)) {
|
|
29303
|
-
throw new Error(`Fast lane cannot bypass parse-steps node '${parseNodeId}'`);
|
|
29304
|
-
}
|
|
29305
|
-
}
|
|
29306
|
-
return {
|
|
29307
|
-
active: true,
|
|
29308
|
-
bypassedNodeIds,
|
|
29309
|
-
bypassedPreMergeGroups,
|
|
29310
|
-
parseStepsNodeIds,
|
|
29311
|
-
implementationNodeId: implementationNode.id,
|
|
29312
|
-
implementationKind
|
|
29313
|
-
};
|
|
29314
|
-
}
|
|
29315
|
-
var FAST_LANE_STEP_NAME, FAST_LANE_SKIP_VALUE, FAST_LANE_STEP_REVIEW_ROUTE_VALUE;
|
|
29316
|
-
var init_workflow_fast_lane = __esm({
|
|
29317
|
-
"../core/src/workflows/workflow-fast-lane.ts"() {
|
|
29318
|
-
"use strict";
|
|
29319
|
-
init_workflow_merge_region();
|
|
29320
|
-
init_workflow_optional_steps();
|
|
29321
|
-
FAST_LANE_STEP_NAME = "Fast implementation";
|
|
29322
|
-
FAST_LANE_SKIP_VALUE = "fast-lane-skip";
|
|
29323
|
-
FAST_LANE_STEP_REVIEW_ROUTE_VALUE = "approve";
|
|
29324
|
-
}
|
|
29325
|
-
});
|
|
29326
|
-
|
|
29327
29371
|
// ../core/src/mesh/mesh-task-replication.ts
|
|
29328
29372
|
function buildBootstrapPrompt(taskId, title, description) {
|
|
29329
29373
|
const heading = title ? `${taskId}: ${title}` : taskId;
|
|
@@ -66524,10 +66568,10 @@ var init_migration = __esm({
|
|
|
66524
66568
|
return basename6(projectPath);
|
|
66525
66569
|
}
|
|
66526
66570
|
try {
|
|
66527
|
-
const { execFile:
|
|
66528
|
-
const { promisify:
|
|
66529
|
-
const
|
|
66530
|
-
const { stdout } = await
|
|
66571
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
66572
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
66573
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
66574
|
+
const { stdout } = await execFileAsync37(
|
|
66531
66575
|
"git",
|
|
66532
66576
|
["remote", "get-url", "origin"],
|
|
66533
66577
|
{ cwd: projectPath, timeout: 1e3 }
|
|
@@ -68722,10 +68766,10 @@ var init_central_core = __esm({
|
|
|
68722
68766
|
*/
|
|
68723
68767
|
async generateProjectName(projectPath) {
|
|
68724
68768
|
try {
|
|
68725
|
-
const { execFile:
|
|
68726
|
-
const { promisify:
|
|
68727
|
-
const
|
|
68728
|
-
const { stdout } = await
|
|
68769
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
68770
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
68771
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
68772
|
+
const { stdout } = await execFileAsync37(
|
|
68729
68773
|
"git",
|
|
68730
68774
|
["remote", "get-url", "origin"],
|
|
68731
68775
|
{ cwd: projectPath, timeout: 5e3 }
|
|
@@ -85527,14 +85571,12 @@ async function listWorkflowDefinitionsImpl(store, options) {
|
|
|
85527
85571
|
return pluginFiltered;
|
|
85528
85572
|
}
|
|
85529
85573
|
async function readAllWorkflowDefinitionsImpl(store) {
|
|
85530
|
-
if (store.workflowDefinitionsCache) return store.workflowDefinitionsCache;
|
|
85531
85574
|
const layer = store.getAsyncLayer();
|
|
85532
85575
|
if (!layer) {
|
|
85533
85576
|
throw new Error("workflow definitions: AsyncDataLayer not initialized in backend mode");
|
|
85534
85577
|
}
|
|
85535
85578
|
const rows = await listWorkflowRows(layer);
|
|
85536
|
-
|
|
85537
|
-
return store.workflowDefinitionsCache;
|
|
85579
|
+
return [...BUILTIN_WORKFLOWS, ...rows.map((row) => store.toWorkflowDefinition(row))];
|
|
85538
85580
|
}
|
|
85539
85581
|
async function getWorkflowDefinitionImpl(store, id) {
|
|
85540
85582
|
const builtin = getBuiltinWorkflow(id);
|
|
@@ -85603,7 +85645,6 @@ function insertWorkflowDefinitionSyncImpl(store, input) {
|
|
|
85603
85645
|
if (!isWorkflowDefinitionIdPrimaryKeyCollision(error2)) throw error2;
|
|
85604
85646
|
continue;
|
|
85605
85647
|
}
|
|
85606
|
-
store.workflowDefinitionsCache = null;
|
|
85607
85648
|
return definition;
|
|
85608
85649
|
}
|
|
85609
85650
|
throw new Error("Unable to allocate a free workflow definition id after repeated id collisions");
|
|
@@ -85993,11 +86034,6 @@ function getPluginStoreImpl(store) {
|
|
|
85993
86034
|
...pluginLayer ? { asyncLayer: pluginLayer } : {}
|
|
85994
86035
|
}
|
|
85995
86036
|
);
|
|
85996
|
-
const clearWorkflowDefinitionCache = () => {
|
|
85997
|
-
store.workflowDefinitionsCache = null;
|
|
85998
|
-
};
|
|
85999
|
-
store.pluginStore.on("plugin:registered", clearWorkflowDefinitionCache);
|
|
86000
|
-
store.pluginStore.on("plugin:unregistered", clearWorkflowDefinitionCache);
|
|
86001
86037
|
}
|
|
86002
86038
|
return store.pluginStore;
|
|
86003
86039
|
}
|
|
@@ -90369,11 +90405,11 @@ async function searchWithQmd(rootDir, options) {
|
|
|
90369
90405
|
const command = "qmd";
|
|
90370
90406
|
const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
|
|
90371
90407
|
try {
|
|
90372
|
-
const
|
|
90373
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
90408
|
+
const execFileAsync37 = await getDefaultExecFileAsync();
|
|
90409
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync37);
|
|
90374
90410
|
scheduleQmdProjectMemoryRefresh(rootDir);
|
|
90375
90411
|
const args = buildQmdSearchArgs(rootDir, options);
|
|
90376
|
-
const { stdout } = await
|
|
90412
|
+
const { stdout } = await execFileAsync37(command, args, {
|
|
90377
90413
|
cwd: rootDir,
|
|
90378
90414
|
timeout: 4e3,
|
|
90379
90415
|
maxBuffer: 1024 * 1024
|
|
@@ -90398,12 +90434,12 @@ async function searchWithQmd(rootDir, options) {
|
|
|
90398
90434
|
return [];
|
|
90399
90435
|
}
|
|
90400
90436
|
}
|
|
90401
|
-
async function ensureQmdProjectMemoryCollection(rootDir,
|
|
90437
|
+
async function ensureQmdProjectMemoryCollection(rootDir, execFileAsync37) {
|
|
90402
90438
|
const collectionName = qmdMemoryCollectionName(rootDir);
|
|
90403
90439
|
const memoryDir = memoryWorkspacePath(rootDir);
|
|
90404
90440
|
await mkdir10(memoryDir, { recursive: true });
|
|
90405
90441
|
try {
|
|
90406
|
-
await
|
|
90442
|
+
await execFileAsync37("qmd", buildQmdCollectionAddArgs(rootDir), {
|
|
90407
90443
|
cwd: rootDir,
|
|
90408
90444
|
timeout: 4e3,
|
|
90409
90445
|
maxBuffer: 512 * 1024
|
|
@@ -90501,14 +90537,14 @@ async function refreshQmdProjectMemoryIndex(rootDir, options) {
|
|
|
90501
90537
|
}
|
|
90502
90538
|
}
|
|
90503
90539
|
const promise = (async () => {
|
|
90504
|
-
const
|
|
90505
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
90506
|
-
await
|
|
90540
|
+
const execFileAsync37 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
90541
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync37);
|
|
90542
|
+
await execFileAsync37("qmd", ["update"], {
|
|
90507
90543
|
cwd: rootDir,
|
|
90508
90544
|
timeout: 3e4,
|
|
90509
90545
|
maxBuffer: 1024 * 1024
|
|
90510
90546
|
});
|
|
90511
|
-
await
|
|
90547
|
+
await execFileAsync37("qmd", ["embed"], {
|
|
90512
90548
|
cwd: rootDir,
|
|
90513
90549
|
timeout: 12e4,
|
|
90514
90550
|
maxBuffer: 1024 * 1024
|
|
@@ -90544,12 +90580,12 @@ async function refreshQmdAgentMemoryIndex(rootDir, agentId, options) {
|
|
|
90544
90580
|
}
|
|
90545
90581
|
}
|
|
90546
90582
|
const promise = (async () => {
|
|
90547
|
-
const
|
|
90583
|
+
const execFileAsync37 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
90548
90584
|
const { agentMemoryWorkspacePath: agentMemoryWorkspacePath2 } = await Promise.resolve().then(() => (init_memory_dreams(), memory_dreams_exports));
|
|
90549
90585
|
const workspacePath = agentMemoryWorkspacePath2(rootDir, agentId);
|
|
90550
90586
|
await mkdir10(workspacePath, { recursive: true });
|
|
90551
90587
|
try {
|
|
90552
|
-
await
|
|
90588
|
+
await execFileAsync37("qmd", ["collection", "add", workspacePath, "--name", qmdAgentMemoryCollectionName(rootDir, agentId), "--mask", "**/*.md"], {
|
|
90553
90589
|
cwd: rootDir,
|
|
90554
90590
|
timeout: 4e3,
|
|
90555
90591
|
maxBuffer: 512 * 1024
|
|
@@ -90562,8 +90598,8 @@ ${stderr}`)) {
|
|
|
90562
90598
|
throw err;
|
|
90563
90599
|
}
|
|
90564
90600
|
}
|
|
90565
|
-
await
|
|
90566
|
-
await
|
|
90601
|
+
await execFileAsync37("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
|
|
90602
|
+
await execFileAsync37("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
90567
90603
|
})();
|
|
90568
90604
|
qmdAgentRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
|
|
90569
90605
|
try {
|
|
@@ -90584,8 +90620,8 @@ function scheduleQmdAgentMemoryRefresh(rootDir, agentId) {
|
|
|
90584
90620
|
}
|
|
90585
90621
|
async function isQmdAvailable() {
|
|
90586
90622
|
try {
|
|
90587
|
-
const
|
|
90588
|
-
await
|
|
90623
|
+
const execFileAsync37 = await getDefaultExecFileAsync();
|
|
90624
|
+
await execFileAsync37("qmd", ["--help"], {
|
|
90589
90625
|
timeout: 3e3,
|
|
90590
90626
|
maxBuffer: 128 * 1024,
|
|
90591
90627
|
keepAlive: true
|
|
@@ -90596,12 +90632,12 @@ async function isQmdAvailable() {
|
|
|
90596
90632
|
}
|
|
90597
90633
|
}
|
|
90598
90634
|
async function installQmd(options) {
|
|
90599
|
-
const
|
|
90635
|
+
const execFileAsync37 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
90600
90636
|
const [command, ...args] = QMD_INSTALL_COMMAND.split(" ");
|
|
90601
90637
|
if (!command || args.length === 0) {
|
|
90602
90638
|
throw new MemoryBackendError("BACKEND_UNAVAILABLE", "qmd install command is not configured", "qmd");
|
|
90603
90639
|
}
|
|
90604
|
-
await
|
|
90640
|
+
await execFileAsync37(command, args, {
|
|
90605
90641
|
timeout: 12e4,
|
|
90606
90642
|
maxBuffer: 1024 * 1024
|
|
90607
90643
|
});
|
|
@@ -100116,7 +100152,6 @@ async function createWorkflowDefinitionImpl(store, input) {
|
|
|
100116
100152
|
if (!isWorkflowDefinitionIdPrimaryKeyCollision(error2)) throw error2;
|
|
100117
100153
|
continue;
|
|
100118
100154
|
}
|
|
100119
|
-
store.workflowDefinitionsCache = null;
|
|
100120
100155
|
return definition;
|
|
100121
100156
|
}
|
|
100122
100157
|
throw new Error("Unable to allocate a free workflow definition id after repeated id collisions");
|
|
@@ -103700,7 +103735,6 @@ async function updateWorkflowDefinitionImpl(store, id, updates) {
|
|
|
103700
103735
|
eq(project_exports.workflows.id, id),
|
|
103701
103736
|
projectScopeFor(project_exports.workflows.projectId, layer.projectId)
|
|
103702
103737
|
));
|
|
103703
|
-
store.workflowDefinitionsCache = null;
|
|
103704
103738
|
return next;
|
|
103705
103739
|
});
|
|
103706
103740
|
if (pendingRehome) {
|
|
@@ -103735,7 +103769,6 @@ async function deleteWorkflowDefinitionImpl(store, id) {
|
|
|
103735
103769
|
projectScopeFor(project_exports.workflows.projectId, layer.projectId)
|
|
103736
103770
|
)).returning();
|
|
103737
103771
|
if (deleted.length === 0) throw new Error(`Workflow '${id}' not found`);
|
|
103738
|
-
store.workflowDefinitionsCache = null;
|
|
103739
103772
|
await layer.db.delete(project_exports.workflowSettings).where(and(
|
|
103740
103773
|
eq(project_exports.workflowSettings.workflowId, id),
|
|
103741
103774
|
projectScopeFor(project_exports.workflowSettings.projectId, layer.projectId)
|
|
@@ -108329,7 +108362,6 @@ var init_store = __esm({
|
|
|
108329
108362
|
taskIdIntegrityReport = { status: "ok", checkedAt: (/* @__PURE__ */ new Date()).toISOString(), anomalies: [] };
|
|
108330
108363
|
lastTaskIdIntegrityLogSignature = null;
|
|
108331
108364
|
workflowStepsCache = null;
|
|
108332
|
-
workflowDefinitionsCache = null;
|
|
108333
108365
|
_pluginWorkflowStepTemplates = [];
|
|
108334
108366
|
globalSettingsStore;
|
|
108335
108367
|
donePauseBackfillDone = false;
|
|
@@ -115959,7 +115991,7 @@ function getPostMergeFinalizeBlocker(task) {
|
|
|
115959
115991
|
}
|
|
115960
115992
|
function planConfirmedMergeChecklistReconciliation(task) {
|
|
115961
115993
|
return {
|
|
115962
|
-
skippedStepIndexes: task.steps.map((step, index2) => step.status === "pending" || step.status === "in-progress" ? index2 : -1).filter((index2) => index2 >= 0),
|
|
115994
|
+
skippedStepIndexes: (task.steps ?? []).map((step, index2) => step.status === "pending" || step.status === "in-progress" ? index2 : -1).filter((index2) => index2 >= 0),
|
|
115963
115995
|
reconciledWorkflowStepIds: (task.workflowStepResults ?? []).filter((result) => result.status === "pending").map((result) => result.workflowStepId)
|
|
115964
115996
|
};
|
|
115965
115997
|
}
|
|
@@ -136009,11 +136041,11 @@ var require_extract_zip = __commonJS({
|
|
|
136009
136041
|
var { createWriteStream, promises: fs10 } = __require("fs");
|
|
136010
136042
|
var getStream = require_get_stream();
|
|
136011
136043
|
var path6 = __require("path");
|
|
136012
|
-
var { promisify:
|
|
136044
|
+
var { promisify: promisify91 } = __require("util");
|
|
136013
136045
|
var stream = __require("stream");
|
|
136014
136046
|
var yauzl = require_yauzl();
|
|
136015
|
-
var openZip =
|
|
136016
|
-
var pipeline =
|
|
136047
|
+
var openZip = promisify91(yauzl.open);
|
|
136048
|
+
var pipeline = promisify91(stream.pipeline);
|
|
136017
136049
|
var Extractor = class {
|
|
136018
136050
|
constructor(zipPath, opts) {
|
|
136019
136051
|
this.zipPath = zipPath;
|
|
@@ -136095,7 +136127,7 @@ var require_extract_zip = __commonJS({
|
|
|
136095
136127
|
await fs10.mkdir(destDir, mkdirOptions);
|
|
136096
136128
|
if (isDir) return;
|
|
136097
136129
|
debug("opening read stream", dest);
|
|
136098
|
-
const readStream = await
|
|
136130
|
+
const readStream = await promisify91(this.zipfile.openReadStream.bind(this.zipfile))(entry);
|
|
136099
136131
|
if (symlink) {
|
|
136100
136132
|
const link = await getStream(readStream);
|
|
136101
136133
|
debug("creating symlink", link, dest);
|
|
@@ -137534,6 +137566,7 @@ async function updateChatSession(handle2, id, input) {
|
|
|
137534
137566
|
if (input.status !== void 0) setValues.status = input.status;
|
|
137535
137567
|
if (input.modelProvider !== void 0) setValues.modelProvider = input.modelProvider;
|
|
137536
137568
|
if (input.modelId !== void 0) setValues.modelId = input.modelId;
|
|
137569
|
+
if (input.agentId !== void 0) setValues.agentId = input.agentId;
|
|
137537
137570
|
if (input.thinkingLevel !== void 0) setValues.thinkingLevel = input.thinkingLevel;
|
|
137538
137571
|
if (input.memoryFocus !== void 0) setValues.memoryFocus = input.memoryFocus;
|
|
137539
137572
|
if (input.pinnedAt !== void 0) setValues.pinnedAt = input.pinnedAt;
|
|
@@ -138587,6 +138620,7 @@ var init_cli_session_store = __esm({
|
|
|
138587
138620
|
});
|
|
138588
138621
|
|
|
138589
138622
|
// ../core/src/secrets/oauth-credential-interop.ts
|
|
138623
|
+
import { createHash as createHash22 } from "node:crypto";
|
|
138590
138624
|
import { existsSync as existsSync40, readFileSync as readFileSync11 } from "node:fs";
|
|
138591
138625
|
import { homedir as homedir7 } from "node:os";
|
|
138592
138626
|
import { join as join55 } from "node:path";
|
|
@@ -138646,6 +138680,22 @@ function getLastRefreshFallbackExpiryMs(lastRefresh) {
|
|
|
138646
138680
|
}
|
|
138647
138681
|
return parsed + CODEX_REFRESH_FALLBACK_WINDOW_MS;
|
|
138648
138682
|
}
|
|
138683
|
+
function isSameStoredCredentialMaterial(left, right) {
|
|
138684
|
+
if (!left || !right || left.type !== right.type) {
|
|
138685
|
+
return false;
|
|
138686
|
+
}
|
|
138687
|
+
return left.key === right.key && left.access === right.access && left.refresh === right.refresh;
|
|
138688
|
+
}
|
|
138689
|
+
function computeStoredCredentialAccountFingerprint(credential) {
|
|
138690
|
+
if (!credential) {
|
|
138691
|
+
return void 0;
|
|
138692
|
+
}
|
|
138693
|
+
const material = typeof credential.refresh === "string" && credential.refresh.length > 0 ? credential.refresh : typeof credential.access === "string" && credential.access.length > 0 ? credential.access : typeof credential.key === "string" && credential.key.length > 0 ? credential.key : void 0;
|
|
138694
|
+
if (!material) {
|
|
138695
|
+
return void 0;
|
|
138696
|
+
}
|
|
138697
|
+
return createHash22("sha256").update(`${credential.type ?? ""}\0${material}`).digest("hex").slice(0, 16);
|
|
138698
|
+
}
|
|
138649
138699
|
function isStoredAuthCredential(value) {
|
|
138650
138700
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
138651
138701
|
return false;
|
|
@@ -139616,7 +139666,7 @@ var init_task_timing = __esm({
|
|
|
139616
139666
|
});
|
|
139617
139667
|
|
|
139618
139668
|
// ../core/src/task-recommendation-notice.ts
|
|
139619
|
-
import { createHash as
|
|
139669
|
+
import { createHash as createHash23 } from "node:crypto";
|
|
139620
139670
|
function registerTaskRecommendationNoticeMailbox(store, mailbox) {
|
|
139621
139671
|
mailboxes2.set(store, mailbox);
|
|
139622
139672
|
return () => {
|
|
@@ -139641,7 +139691,7 @@ function buildTaskRecommendationNoticeContent(task, recommendations) {
|
|
|
139641
139691
|
}
|
|
139642
139692
|
function buildTaskRecommendationNoticeIdempotencyKey(taskId, recommendations) {
|
|
139643
139693
|
const ids = recommendations.map(({ id }) => id).sort().join("\n");
|
|
139644
|
-
const digest =
|
|
139694
|
+
const digest = createHash23("sha256").update(ids, "utf8").digest("hex").slice(0, 16);
|
|
139645
139695
|
return `task-recommendation-notice:${taskId}:${digest}`;
|
|
139646
139696
|
}
|
|
139647
139697
|
async function notifyOperatorOfTaskRecommendations(store, task, recommendations, settings) {
|
|
@@ -140087,6 +140137,7 @@ __export(src_exports, {
|
|
|
140087
140137
|
APPROVAL_REQUEST_STATUSES: () => APPROVAL_REQUEST_STATUSES,
|
|
140088
140138
|
ARCHIVED_TASK_DOCUMENT_ADDITION_BOUNDARY: () => ARCHIVED_TASK_DOCUMENT_ADDITION_BOUNDARY,
|
|
140089
140139
|
ARCHIVED_TASK_DOCUMENT_PUBLICATION_REJECTED: () => ARCHIVED_TASK_DOCUMENT_PUBLICATION_REJECTED,
|
|
140140
|
+
AUTOMATED_BYPASS_ACTORS: () => AUTOMATED_BYPASS_ACTORS,
|
|
140090
140141
|
AUTOMATION_PRESETS: () => AUTOMATION_PRESETS,
|
|
140091
140142
|
AUTOMATION_SELECTABLE_TOOLS: () => AUTOMATION_SELECTABLE_TOOLS,
|
|
140092
140143
|
AUTOPILOT_STATES: () => AUTOPILOT_STATES,
|
|
@@ -140282,6 +140333,7 @@ __export(src_exports, {
|
|
|
140282
140333
|
FAST_LANE_SKIP_VALUE: () => FAST_LANE_SKIP_VALUE,
|
|
140283
140334
|
FAST_LANE_STEP_NAME: () => FAST_LANE_STEP_NAME,
|
|
140284
140335
|
FAST_LANE_STEP_REVIEW_ROUTE_VALUE: () => FAST_LANE_STEP_REVIEW_ROUTE_VALUE,
|
|
140336
|
+
FAST_MODE_BYPASS_ACTOR: () => FAST_MODE_BYPASS_ACTOR,
|
|
140285
140337
|
FEATURE_LOOP_REPAIR_TRANSITIONS: () => FEATURE_LOOP_REPAIR_TRANSITIONS,
|
|
140286
140338
|
FEATURE_LOOP_STATES: () => FEATURE_LOOP_STATES,
|
|
140287
140339
|
FEATURE_STATUSES: () => FEATURE_STATUSES,
|
|
@@ -140846,6 +140898,7 @@ __export(src_exports, {
|
|
|
140846
140898
|
computeRetrySummary: () => computeRetrySummary,
|
|
140847
140899
|
computeSkillId: () => computeSkillId,
|
|
140848
140900
|
computeSnapshotChecksum: () => computeSnapshotChecksum,
|
|
140901
|
+
computeStoredCredentialAccountFingerprint: () => computeStoredCredentialAccountFingerprint,
|
|
140849
140902
|
computeWorkflowIrPin: () => computeWorkflowIrPin,
|
|
140850
140903
|
configurationTargetKey: () => configurationTargetKey,
|
|
140851
140904
|
configureApprovalRequestTtls: () => configureApprovalRequestTtls,
|
|
@@ -141168,6 +141221,7 @@ __export(src_exports, {
|
|
|
141168
141221
|
isApprovalRequestExpired: () => isApprovalRequestExpired,
|
|
141169
141222
|
isArchivedColumnRole: () => isArchivedColumnRole,
|
|
141170
141223
|
isArchivedRemediationCarrier: () => isArchivedRemediationCarrier,
|
|
141224
|
+
isAuditedOperatorBypass: () => isAuditedOperatorBypass,
|
|
141171
141225
|
isBlockingFinding: () => isBlockingFinding,
|
|
141172
141226
|
isBranchGroupComplete: () => isBranchGroupComplete,
|
|
141173
141227
|
isBranchGroupMemberLanded: () => isBranchGroupMemberLanded,
|
|
@@ -141255,6 +141309,7 @@ __export(src_exports, {
|
|
|
141255
141309
|
isReviewColumnRole: () => isReviewColumnRole,
|
|
141256
141310
|
isRunRecord: () => isRunRecord,
|
|
141257
141311
|
isRunningAgentTask: () => isRunningAgentTask,
|
|
141312
|
+
isSameStoredCredentialMaterial: () => isSameStoredCredentialMaterial,
|
|
141258
141313
|
isSanctionedEngineBackwardMove: () => isSanctionedEngineBackwardMove,
|
|
141259
141314
|
isSandboxExperimentalEnabled: () => isSandboxExperimentalEnabled,
|
|
141260
141315
|
isSecretAccessPolicy: () => isSecretAccessPolicy,
|
|
@@ -141533,6 +141588,7 @@ __export(src_exports, {
|
|
|
141533
141588
|
renderTriagePolicyPlaceholders: () => renderTriagePolicyPlaceholders,
|
|
141534
141589
|
renderValidationCause: () => renderValidationCause,
|
|
141535
141590
|
renderValidationFailureDescription: () => renderValidationFailureDescription,
|
|
141591
|
+
requiresContentReviewProof: () => requiresContentReviewProof,
|
|
141536
141592
|
requiresPlannerConfirmation: () => requiresPlannerConfirmation,
|
|
141537
141593
|
requiresWorktrunkInstallVerification: () => requiresWorktrunkInstallVerification,
|
|
141538
141594
|
resetGhAvailabilityCache: () => resetGhAvailabilityCache,
|
|
@@ -141696,6 +141752,7 @@ __export(src_exports, {
|
|
|
141696
141752
|
resolveTitleSummarizerSettingsModel: () => resolveTitleSummarizerSettingsModel,
|
|
141697
141753
|
resolveToolOutputBudget: () => resolveToolOutputBudget,
|
|
141698
141754
|
resolveTrailingVerificationStepIndex: () => resolveTrailingVerificationStepIndex,
|
|
141755
|
+
resolveUnprovenReviewApproval: () => resolveUnprovenReviewApproval,
|
|
141699
141756
|
resolveUpdateAutomationSettings: () => resolveUpdateAutomationSettings,
|
|
141700
141757
|
resolveUpdateTargetVersion: () => resolveUpdateTargetVersion,
|
|
141701
141758
|
resolveUpdatesExternallyManaged: () => resolveUpdatesExternallyManaged,
|
|
@@ -145177,18 +145234,25 @@ function parseWorktreesFromPorcelain(porcelain) {
|
|
|
145177
145234
|
if (current.path) rows.push({ path: current.path, branch: current.branch });
|
|
145178
145235
|
return rows;
|
|
145179
145236
|
}
|
|
145237
|
+
function isRegenerableIgnoredPorcelainEntry(entry) {
|
|
145238
|
+
const path6 = entry.slice(3).replace(/\/$/, "");
|
|
145239
|
+
if (!path6 || path6.startsWith('"')) return false;
|
|
145240
|
+
const lastSegment = path6.split("/").at(-1);
|
|
145241
|
+
return lastSegment !== void 0 && REGENERABLE_IGNORED_DIR_NAMES.has(lastSegment);
|
|
145242
|
+
}
|
|
145180
145243
|
function classifyWorktreeRemovalContent(porcelain) {
|
|
145181
145244
|
const entries = porcelain.split(/\r?\n/).filter((line2) => line2.trim().length > 0);
|
|
145182
145245
|
if (entries.length === 0) return "clean";
|
|
145183
|
-
|
|
145246
|
+
if (entries.some((line2) => !line2.startsWith("!! "))) return "deliverable";
|
|
145247
|
+
return entries.every(isRegenerableIgnoredPorcelainEntry) ? "regenerable-ignored" : "ignored-only";
|
|
145184
145248
|
}
|
|
145185
145249
|
async function assertCleanForDefensiveRemoval(worktreePath) {
|
|
145186
145250
|
if (!existsSync42(worktreePath)) {
|
|
145187
|
-
return "clean";
|
|
145251
|
+
return { classification: "clean", entryCount: 0 };
|
|
145188
145252
|
}
|
|
145189
145253
|
let stdout;
|
|
145190
145254
|
try {
|
|
145191
|
-
({ stdout } = await execFileAsync7("git", ["status", "--porcelain=v1", "--ignored", "--untracked-files=normal"], {
|
|
145255
|
+
({ stdout } = await execFileAsync7("git", ["status", "--porcelain=v1", "--ignored=matching", "--untracked-files=normal"], {
|
|
145192
145256
|
cwd: worktreePath,
|
|
145193
145257
|
encoding: "utf-8",
|
|
145194
145258
|
timeout: 15e3,
|
|
@@ -145201,7 +145265,10 @@ async function assertCleanForDefensiveRemoval(worktreePath) {
|
|
|
145201
145265
|
if (classification === "deliverable") {
|
|
145202
145266
|
throw new Error(`preserving ${worktreePath}: uncommitted or ignored content present`);
|
|
145203
145267
|
}
|
|
145204
|
-
return
|
|
145268
|
+
return {
|
|
145269
|
+
classification,
|
|
145270
|
+
entryCount: stdout.split(/\r?\n/).filter((line2) => line2.trim().length > 0).length
|
|
145271
|
+
};
|
|
145205
145272
|
}
|
|
145206
145273
|
async function removeWorktree(input) {
|
|
145207
145274
|
const logger3 = {
|
|
@@ -145218,9 +145285,12 @@ async function removeWorktree(input) {
|
|
|
145218
145285
|
}
|
|
145219
145286
|
const requiresCleanWorktree = DEFENSIVE_REMOVAL_REASONS.has(input.reason);
|
|
145220
145287
|
let contentClassification;
|
|
145288
|
+
let contentEntryCount = 0;
|
|
145221
145289
|
if (requiresCleanWorktree) {
|
|
145222
145290
|
try {
|
|
145223
|
-
|
|
145291
|
+
const contentProbe = await assertCleanForDefensiveRemoval(input.worktreePath);
|
|
145292
|
+
contentClassification = contentProbe.classification;
|
|
145293
|
+
contentEntryCount = contentProbe.entryCount;
|
|
145224
145294
|
} catch (error2) {
|
|
145225
145295
|
const classification = error2 instanceof Error && error2.message.includes(": status probe failed (") ? "unverifiable" : "deliverable";
|
|
145226
145296
|
await input.audit?.git({
|
|
@@ -145237,6 +145307,17 @@ async function removeWorktree(input) {
|
|
|
145237
145307
|
throw error2;
|
|
145238
145308
|
}
|
|
145239
145309
|
if (contentClassification === "ignored-only" && !input.postLandingProof) {
|
|
145310
|
+
await input.audit?.git({
|
|
145311
|
+
type: "worktree:removal-preserved",
|
|
145312
|
+
target: input.worktreePath,
|
|
145313
|
+
metadata: {
|
|
145314
|
+
taskId: input.taskId,
|
|
145315
|
+
reason: input.reason,
|
|
145316
|
+
source: void 0,
|
|
145317
|
+
classification: "ignored-only",
|
|
145318
|
+
hasPostLandingProof: false
|
|
145319
|
+
}
|
|
145320
|
+
}).catch(() => void 0);
|
|
145240
145321
|
throw new Error(`preserving ${input.worktreePath}: uncommitted or ignored content present`);
|
|
145241
145322
|
}
|
|
145242
145323
|
}
|
|
@@ -145256,6 +145337,17 @@ async function removeWorktree(input) {
|
|
|
145256
145337
|
} catch {
|
|
145257
145338
|
}
|
|
145258
145339
|
};
|
|
145340
|
+
const recordRegenerableDiscard = async () => {
|
|
145341
|
+
if (contentClassification !== "regenerable-ignored") return;
|
|
145342
|
+
try {
|
|
145343
|
+
await input.audit?.git({
|
|
145344
|
+
type: "worktree:removal-discarded-regenerable-content",
|
|
145345
|
+
target: input.worktreePath,
|
|
145346
|
+
metadata: { taskId: input.taskId, reason: input.reason, entryCount: contentEntryCount }
|
|
145347
|
+
});
|
|
145348
|
+
} catch {
|
|
145349
|
+
}
|
|
145350
|
+
};
|
|
145259
145351
|
if (input.expectedOwnerTaskId && input.liveOwnerProbe) {
|
|
145260
145352
|
const reconciled = reconcileSelfOwnedActiveSessionForRemoval(
|
|
145261
145353
|
activeSessionRegistry,
|
|
@@ -145309,6 +145401,7 @@ async function removeWorktree(input) {
|
|
|
145309
145401
|
try {
|
|
145310
145402
|
await backend.remove(removeInput);
|
|
145311
145403
|
await recordIgnoredOnlyDiscard();
|
|
145404
|
+
await recordRegenerableDiscard();
|
|
145312
145405
|
if (input.audit) {
|
|
145313
145406
|
await input.audit.git({
|
|
145314
145407
|
type: backend.kind === "worktrunk" ? "worktree:worktrunk-remove" : "worktree:remove",
|
|
@@ -145336,6 +145429,7 @@ async function removeWorktree(input) {
|
|
|
145336
145429
|
try {
|
|
145337
145430
|
await native.remove(removeInput);
|
|
145338
145431
|
await recordIgnoredOnlyDiscard();
|
|
145432
|
+
await recordRegenerableDiscard();
|
|
145339
145433
|
await input.audit?.git({ type: "worktree:remove", target: input.worktreePath });
|
|
145340
145434
|
return { removed: true, classification: "removed" };
|
|
145341
145435
|
} catch (nativeError) {
|
|
@@ -145357,7 +145451,7 @@ function resolveWorktreeBackend(settings, deps = {}) {
|
|
|
145357
145451
|
}
|
|
145358
145452
|
return new NativeWorktreeBackend({ logger: deps.logger, settings, audit: deps.audit });
|
|
145359
145453
|
}
|
|
145360
|
-
var execAsync10, execFileAsync7, NATIVE_TIMEOUT_MS, REMOVE_TIMEOUT_MS, MAX_BUFFER3, HARMLESS_MERGE_REMOVE_ERROR_PATTERNS, WORKTRUNK_TIMEOUTS_MS, WORKTREE_BACKEND_MARKER, WorktrunkOperationError, NativeWorktreeBackend, WorktrunkWorktreeBackend, RemovalReason, ALLOWED_FORCE_REASONS, DEFENSIVE_REMOVAL_REASONS, POST_LANDING_PROOF_REASONS, InvalidForceUsageError, InvalidPostLandingProofUsageError, ActiveSessionWorktreeRemovalError;
|
|
145454
|
+
var execAsync10, execFileAsync7, NATIVE_TIMEOUT_MS, REMOVE_TIMEOUT_MS, MAX_BUFFER3, HARMLESS_MERGE_REMOVE_ERROR_PATTERNS, WORKTRUNK_TIMEOUTS_MS, WORKTREE_BACKEND_MARKER, WorktrunkOperationError, NativeWorktreeBackend, WorktrunkWorktreeBackend, RemovalReason, ALLOWED_FORCE_REASONS, DEFENSIVE_REMOVAL_REASONS, POST_LANDING_PROOF_REASONS, InvalidForceUsageError, InvalidPostLandingProofUsageError, ActiveSessionWorktreeRemovalError, REGENERABLE_IGNORED_DIR_NAMES;
|
|
145361
145455
|
var init_worktree_backend = __esm({
|
|
145362
145456
|
"../engine/src/worktree/worktree-backend.ts"() {
|
|
145363
145457
|
"use strict";
|
|
@@ -146097,6 +146191,27 @@ ${getErrorStderr(error2) ?? ""}`;
|
|
|
146097
146191
|
this.name = "ActiveSessionWorktreeRemovalError";
|
|
146098
146192
|
}
|
|
146099
146193
|
};
|
|
146194
|
+
REGENERABLE_IGNORED_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
146195
|
+
"node_modules",
|
|
146196
|
+
"dist",
|
|
146197
|
+
"build",
|
|
146198
|
+
"out",
|
|
146199
|
+
"target",
|
|
146200
|
+
"bin",
|
|
146201
|
+
"obj",
|
|
146202
|
+
"coverage",
|
|
146203
|
+
".next",
|
|
146204
|
+
".nuxt",
|
|
146205
|
+
".turbo",
|
|
146206
|
+
".svelte-kit",
|
|
146207
|
+
".parcel-cache",
|
|
146208
|
+
".pytest_cache",
|
|
146209
|
+
".mypy_cache",
|
|
146210
|
+
"__pycache__",
|
|
146211
|
+
".gradle",
|
|
146212
|
+
".venv",
|
|
146213
|
+
"venv"
|
|
146214
|
+
]);
|
|
146100
146215
|
}
|
|
146101
146216
|
});
|
|
146102
146217
|
|
|
@@ -146718,6 +146833,14 @@ function resolveAiMergeRootPath(rootDir, settings) {
|
|
|
146718
146833
|
function resolveLegacyAiMergeRootPath(rootDir) {
|
|
146719
146834
|
return join59(rootDir, ".fusion", "ai-merge");
|
|
146720
146835
|
}
|
|
146836
|
+
function resolveAiMergeSearchRoots(rootDir, settings) {
|
|
146837
|
+
const roots = [
|
|
146838
|
+
resolveAiMergeRootPath(rootDir, settings),
|
|
146839
|
+
resolveLegacyAiMergeRootPath(rootDir),
|
|
146840
|
+
...settings?.worktreesDir ? [] : [join59(resolveLegacyWorktreesDirLayout(rootDir), AI_MERGE_DIRNAME)]
|
|
146841
|
+
];
|
|
146842
|
+
return [...new Set(roots)];
|
|
146843
|
+
}
|
|
146721
146844
|
function resolveWorktreesDir(rootDir, settings, workspaceContext) {
|
|
146722
146845
|
return resolveWorktreesDirLayout(rootDir, settings, workspaceContext);
|
|
146723
146846
|
}
|
|
@@ -148194,7 +148317,7 @@ var init_plan_review_continuation = __esm({
|
|
|
148194
148317
|
});
|
|
148195
148318
|
|
|
148196
148319
|
// ../engine/src/execution/hold-release.ts
|
|
148197
|
-
import { createHash as
|
|
148320
|
+
import { createHash as createHash25 } from "node:crypto";
|
|
148198
148321
|
import { readFile as readFile36 } from "node:fs/promises";
|
|
148199
148322
|
function findColumn2(ir2, columnId) {
|
|
148200
148323
|
if (ir2.version !== "v2") return void 0;
|
|
@@ -148232,9 +148355,9 @@ async function checkAndRecordUnplannedExecutionBlock(store, task, ir2) {
|
|
|
148232
148355
|
promptContent = "";
|
|
148233
148356
|
}
|
|
148234
148357
|
}
|
|
148235
|
-
const promptMarker = promptContent.length > 0 ?
|
|
148358
|
+
const promptMarker = promptContent.length > 0 ? createHash25("sha256").update(promptContent).digest("hex") : "missing";
|
|
148236
148359
|
const dependencies = [...task.dependencies ?? []].sort();
|
|
148237
|
-
const episode =
|
|
148360
|
+
const episode = createHash25("sha256").update(JSON.stringify({
|
|
148238
148361
|
planReviewNode,
|
|
148239
148362
|
promptMarker,
|
|
148240
148363
|
dependencies,
|
|
@@ -153237,6 +153360,15 @@ async function withOAuthRefreshLock(authPath, providerId, refresh) {
|
|
|
153237
153360
|
await release3();
|
|
153238
153361
|
}
|
|
153239
153362
|
}
|
|
153363
|
+
async function withOAuthInstanceLoginLock(authPath, providerId, operation) {
|
|
153364
|
+
const safeProviderId = providerId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
153365
|
+
const release3 = await import_proper_lockfile.default.lock(`${authPath}.${safeProviderId}.instance-login`, AUTH_LOCK_OPTIONS);
|
|
153366
|
+
try {
|
|
153367
|
+
return await operation();
|
|
153368
|
+
} finally {
|
|
153369
|
+
await release3();
|
|
153370
|
+
}
|
|
153371
|
+
}
|
|
153240
153372
|
function readDefaultInstanceMap(data) {
|
|
153241
153373
|
const candidate = data.__fusionDefaultInstances;
|
|
153242
153374
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return {};
|
|
@@ -153526,7 +153658,7 @@ function createFusionAuthStorage() {
|
|
|
153526
153658
|
primary.reload();
|
|
153527
153659
|
const selectPersistedRefreshCredential = () => {
|
|
153528
153660
|
const storedCredential = primary.get(storageProvider);
|
|
153529
|
-
if (refreshLockProvider !== ANTHROPIC_PROVIDER_ID2) {
|
|
153661
|
+
if (storedCredential?.type === "oauth" || refreshLockProvider !== ANTHROPIC_PROVIDER_ID2) {
|
|
153530
153662
|
return storedCredential;
|
|
153531
153663
|
}
|
|
153532
153664
|
const legacyCredential = primary.get(ANTHROPIC_PROVIDER_ID2);
|
|
@@ -153656,18 +153788,16 @@ function createFusionAuthStorage() {
|
|
|
153656
153788
|
if (rawKey) return rawKey;
|
|
153657
153789
|
}
|
|
153658
153790
|
const subscriptionLoggedOut = loggedOutProviders.has(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153659
|
-
const
|
|
153791
|
+
const subscriptionCredential = subscriptionLoggedOut ? void 0 : selectStoredCredential(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153792
|
+
if (subscriptionCredential?.type === "oauth") {
|
|
153793
|
+
const subscriptionKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
|
|
153794
|
+
if (subscriptionKey) return subscriptionKey;
|
|
153795
|
+
}
|
|
153796
|
+
const legacyAnthropicOAuthCredential = rawProviderLoggedOut || subscriptionCredential ? void 0 : selectStoredCredentialByType(ANTHROPIC_PROVIDER_ID2, "oauth");
|
|
153660
153797
|
if (!subscriptionLoggedOut && legacyAnthropicOAuthCredential) {
|
|
153661
153798
|
const legacyKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_PROVIDER_ID2, legacyAnthropicOAuthCredential);
|
|
153662
153799
|
if (legacyKey) return legacyKey;
|
|
153663
153800
|
}
|
|
153664
|
-
if (!subscriptionLoggedOut) {
|
|
153665
|
-
const subscriptionCredential = selectStoredCredential(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153666
|
-
if (subscriptionCredential?.type === "oauth") {
|
|
153667
|
-
const subscriptionKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
|
|
153668
|
-
if (subscriptionKey) return subscriptionKey;
|
|
153669
|
-
}
|
|
153670
|
-
}
|
|
153671
153801
|
if (preferSubscription) {
|
|
153672
153802
|
const rawKey = resolveRawApiKey();
|
|
153673
153803
|
if (rawKey) return rawKey;
|
|
@@ -153844,8 +153974,15 @@ function createFusionAuthStorage() {
|
|
|
153844
153974
|
return void 0;
|
|
153845
153975
|
}
|
|
153846
153976
|
if (sourceProvider !== ANTHROPIC_SUBSCRIPTION_PROVIDER_ID) {
|
|
153847
|
-
await
|
|
153848
|
-
|
|
153977
|
+
const legacyKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_PROVIDER_ID2, subscriptionCredential);
|
|
153978
|
+
primary.reload();
|
|
153979
|
+
const storedSubscription = primary.get(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153980
|
+
const refreshedLegacyCredential = primary.get(ANTHROPIC_PROVIDER_ID2);
|
|
153981
|
+
if (!storedSubscription && refreshedLegacyCredential?.type === "oauth") {
|
|
153982
|
+
await primary.set(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, refreshedLegacyCredential);
|
|
153983
|
+
loggedOutProviders.delete(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153984
|
+
}
|
|
153985
|
+
return legacyKey;
|
|
153849
153986
|
}
|
|
153850
153987
|
return resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
|
|
153851
153988
|
}
|
|
@@ -153890,6 +154027,9 @@ var init_auth_storage = __esm({
|
|
|
153890
154027
|
}
|
|
153891
154028
|
data = {};
|
|
153892
154029
|
modelRuntime;
|
|
154030
|
+
async withProviderInstanceLoginLock(providerId, operation) {
|
|
154031
|
+
return withOAuthInstanceLoginLock(this.authPath, providerId, operation);
|
|
154032
|
+
}
|
|
153893
154033
|
ensureFile() {
|
|
153894
154034
|
const parent = dirname27(this.authPath);
|
|
153895
154035
|
if (!existsSync47(parent)) mkdirSync7(parent, { recursive: true, mode: 448 });
|
|
@@ -154596,7 +154736,7 @@ var init_gating_classifications = __esm({
|
|
|
154596
154736
|
});
|
|
154597
154737
|
|
|
154598
154738
|
// ../engine/src/agents/agent-action-gate.ts
|
|
154599
|
-
import { createHash as
|
|
154739
|
+
import { createHash as createHash26 } from "node:crypto";
|
|
154600
154740
|
function getExemptTools() {
|
|
154601
154741
|
if (!_exemptTools) {
|
|
154602
154742
|
_exemptTools = new Set(DEFAULT_EXEMPT_TOOLS);
|
|
@@ -154630,7 +154770,7 @@ function evaluateAgentActionGate(params) {
|
|
|
154630
154770
|
if (params.toolName === "bash") {
|
|
154631
154771
|
const command = extractShellCommand(args);
|
|
154632
154772
|
const git10 = classifyGitCommand(command);
|
|
154633
|
-
resourceId = command ? `cmd:${
|
|
154773
|
+
resourceId = command ? `cmd:${createHash26("sha256").update(command).digest("hex").slice(0, 16)}` : void 0;
|
|
154634
154774
|
if (git10?.write) {
|
|
154635
154775
|
category = "git_write";
|
|
154636
154776
|
operation = git10.operation;
|
|
@@ -176496,6 +176636,7 @@ async function connectMcpSessionTools(servers, opts = {}) {
|
|
|
176496
176636
|
const clients = [];
|
|
176497
176637
|
const closedClients = /* @__PURE__ */ new WeakSet();
|
|
176498
176638
|
const usedToolNames = /* @__PURE__ */ new Set();
|
|
176639
|
+
const serverByToolName = /* @__PURE__ */ new Map();
|
|
176499
176640
|
let disposed = false;
|
|
176500
176641
|
const closeOnce = async (client) => {
|
|
176501
176642
|
if (closedClients.has(client)) return;
|
|
@@ -176545,7 +176686,9 @@ async function connectMcpSessionTools(servers, opts = {}) {
|
|
|
176545
176686
|
opts.logger?.log?.(connectMsg);
|
|
176546
176687
|
}
|
|
176547
176688
|
for (const tool of listedTools) {
|
|
176548
|
-
|
|
176689
|
+
const wrappedTool = wrapMcpTool(server.name, tool, client, usedToolNames);
|
|
176690
|
+
tools.push(wrappedTool);
|
|
176691
|
+
serverByToolName.set(wrappedTool.name, server.name);
|
|
176549
176692
|
}
|
|
176550
176693
|
break;
|
|
176551
176694
|
} catch (error2) {
|
|
@@ -176572,7 +176715,7 @@ async function connectMcpSessionTools(servers, opts = {}) {
|
|
|
176572
176715
|
await closeAll();
|
|
176573
176716
|
}
|
|
176574
176717
|
}
|
|
176575
|
-
return { tools, connected, skipped, dispose: closeAll };
|
|
176718
|
+
return { tools, connected, skipped, serverByToolName, dispose: closeAll };
|
|
176576
176719
|
}
|
|
176577
176720
|
function normalizeMaxAttempts(value) {
|
|
176578
176721
|
if (value === void 0 || !Number.isFinite(value)) return DEFAULT_MAX_ATTEMPTS;
|
|
@@ -179706,8 +179849,10 @@ async function createPiAgentSessionRaw(options) {
|
|
|
179706
179849
|
const createSessionWithModel = async (modelOverride) => {
|
|
179707
179850
|
let mcpToolset;
|
|
179708
179851
|
const allowReadonlyMcpTools = options.allowMcpToolsInReadonly === true;
|
|
179709
|
-
|
|
179710
|
-
|
|
179852
|
+
const readonlyMcpServerAllowlist = options.readonlyMcpServerAllowlist === void 0 ? void 0 : new Set(options.readonlyMcpServerAllowlist.map((name2) => name2.trim()).filter(Boolean));
|
|
179853
|
+
const mcpServersToConnect = isReadonly && allowReadonlyMcpTools && readonlyMcpServerAllowlist !== void 0 ? forwardedMcpServers.filter((server) => readonlyMcpServerAllowlist.has(server.name)) : forwardedMcpServers;
|
|
179854
|
+
if (mcpServersToConnect.length > 0 && (!isReadonly || allowReadonlyMcpTools)) {
|
|
179855
|
+
mcpToolset = await connectMcpSessionTools(mcpServersToConnect, {
|
|
179711
179856
|
cwd: options.cwd,
|
|
179712
179857
|
clientFactory: options.mcpClientFactory,
|
|
179713
179858
|
logger: piLog,
|
|
@@ -179718,7 +179863,8 @@ async function createPiAgentSessionRaw(options) {
|
|
|
179718
179863
|
piLog.warn(`MCP session continuing with unavailable servers: count=${bootstrapFailures.length}`);
|
|
179719
179864
|
}
|
|
179720
179865
|
} else if (forwardedMcpServers.length > 0 && isReadonly) {
|
|
179721
|
-
|
|
179866
|
+
const reason = !allowReadonlyMcpTools ? "no-readonly-opt-in" : "readonly-allowlist-no-match";
|
|
179867
|
+
piLog.log(`readonly session \u2014 MCP servers (${forwardedMcpServers.length}) skipped: reason=${reason}`);
|
|
179722
179868
|
}
|
|
179723
179869
|
const mcpReadonlyTools = new Set(mcpToolset?.tools ?? []);
|
|
179724
179870
|
const candidateCustomTools = [
|
|
@@ -179727,7 +179873,9 @@ async function createPiAgentSessionRaw(options) {
|
|
|
179727
179873
|
];
|
|
179728
179874
|
const readonlyFilteredCustomTools = isReadonly ? filterCustomToolsForReadonly(
|
|
179729
179875
|
candidateCustomTools,
|
|
179730
|
-
allowReadonlyMcpTools ? {
|
|
179876
|
+
allowReadonlyMcpTools ? {
|
|
179877
|
+
allowTool: (tool) => readonlyMcpServerAllowlist === void 0 ? mcpReadonlyTools.has(tool) : readonlyMcpServerAllowlist.has(mcpToolset?.serverByToolName?.get(tool.name) ?? "")
|
|
179878
|
+
} : {}
|
|
179731
179879
|
) : { allowed: candidateCustomTools, denied: [] };
|
|
179732
179880
|
const allowlistFilteredCustomTools = {
|
|
179733
179881
|
...readonlyFilteredCustomTools,
|
|
@@ -180197,7 +180345,7 @@ var init_pi = __esm({
|
|
|
180197
180345
|
});
|
|
180198
180346
|
|
|
180199
180347
|
// ../engine/src/agents/agent-logger.ts
|
|
180200
|
-
import { createHash as
|
|
180348
|
+
import { createHash as createHash27 } from "node:crypto";
|
|
180201
180349
|
function truncateToolResultDetail(value) {
|
|
180202
180350
|
if (value.length <= TOOL_RESULT_DETAIL_LIMIT) return value;
|
|
180203
180351
|
return `${value.slice(0, TOOL_RESULT_DETAIL_LIMIT)}${TOOL_RESULT_DETAIL_TRUNCATION_NOTICE}`;
|
|
@@ -180305,7 +180453,7 @@ function summarizeToolArgs(name2, args) {
|
|
|
180305
180453
|
return `${key}=${clipToolArgValue(compactToolArgValue(args[key]), maximum)}`;
|
|
180306
180454
|
}).join(", ");
|
|
180307
180455
|
if (rendered.length <= TOOL_ARG_SUMMARY_MAX) return rendered;
|
|
180308
|
-
const hash3 =
|
|
180456
|
+
const hash3 = createHash27("sha256").update(fullArgsJson).digest("hex").slice(0, STRUCTURED_ARG_HASH_HEX_LEN);
|
|
180309
180457
|
const suffix = `\u2026#${hash3}`;
|
|
180310
180458
|
const keep = Math.max(0, TOOL_ARG_SUMMARY_MAX - suffix.length);
|
|
180311
180459
|
return `${rendered.slice(0, keep)}${suffix}`;
|
|
@@ -183013,7 +183161,7 @@ var init_retry_burned_logger = __esm({
|
|
|
183013
183161
|
|
|
183014
183162
|
// ../engine/src/merge/merge-dependency-sync.ts
|
|
183015
183163
|
import { exec as exec20 } from "node:child_process";
|
|
183016
|
-
import { createHash as
|
|
183164
|
+
import { createHash as createHash28 } from "node:crypto";
|
|
183017
183165
|
import { existsSync as existsSync50, readFileSync as readFileSync19, writeFileSync as writeFileSync6 } from "node:fs";
|
|
183018
183166
|
import { join as join69 } from "node:path";
|
|
183019
183167
|
import { promisify as promisify27 } from "node:util";
|
|
@@ -183046,7 +183194,7 @@ function computeLockfileHash(rootDir) {
|
|
|
183046
183194
|
const p2 = join69(rootDir, name2);
|
|
183047
183195
|
if (existsSync50(p2)) {
|
|
183048
183196
|
try {
|
|
183049
|
-
return
|
|
183197
|
+
return createHash28("sha256").update(readFileSync19(p2)).digest("hex");
|
|
183050
183198
|
} catch {
|
|
183051
183199
|
return null;
|
|
183052
183200
|
}
|
|
@@ -183176,7 +183324,7 @@ var init_merge_dependency_sync = __esm({
|
|
|
183176
183324
|
});
|
|
183177
183325
|
|
|
183178
183326
|
// ../engine/src/worktree/worktree-dependency-install.ts
|
|
183179
|
-
import { createHash as
|
|
183327
|
+
import { createHash as createHash29 } from "node:crypto";
|
|
183180
183328
|
import { existsSync as existsSync51, readFileSync as readFileSync20, readdirSync as readdirSync8, statSync as statSync11, writeFileSync as writeFileSync7 } from "node:fs";
|
|
183181
183329
|
import { delimiter as delimiter2, join as join70 } from "node:path";
|
|
183182
183330
|
function rootEntries(rootDir) {
|
|
@@ -183274,7 +183422,7 @@ function isCommandAvailable(binary, env = process.env) {
|
|
|
183274
183422
|
);
|
|
183275
183423
|
}
|
|
183276
183424
|
function hashParts(parts) {
|
|
183277
|
-
const hash3 =
|
|
183425
|
+
const hash3 = createHash29("sha256");
|
|
183278
183426
|
for (const [name2, value] of [...parts].sort(([left], [right]) => left.localeCompare(right))) {
|
|
183279
183427
|
hash3.update(name2).update("\0").update(value).update("\0");
|
|
183280
183428
|
}
|
|
@@ -185558,7 +185706,7 @@ var init_code_node_runner = __esm({
|
|
|
185558
185706
|
// ../engine/src/agent-tools.ts
|
|
185559
185707
|
import { appendFile as appendFile3, mkdir as mkdir27, readFile as readFile40, readdir as readdir11, realpath, stat as stat11, writeFile as writeFile23 } from "node:fs/promises";
|
|
185560
185708
|
import { existsSync as existsSync53 } from "node:fs";
|
|
185561
|
-
import { createHash as
|
|
185709
|
+
import { createHash as createHash30, randomUUID as randomUUID48 } from "node:crypto";
|
|
185562
185710
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
185563
185711
|
import { extname as extname4, isAbsolute as isAbsolute14, join as join72, relative as relative13, resolve as resolve40, sep as sep11 } from "node:path";
|
|
185564
185712
|
import { Type as Type2 } from "@earendil-works/pi-ai";
|
|
@@ -185602,7 +185750,7 @@ async function readAgentMemoryWorkspaceLongTerm(rootDir, agentId) {
|
|
|
185602
185750
|
}
|
|
185603
185751
|
}
|
|
185604
185752
|
function qmdAgentMemoryCollectionName2(rootDir, agentId) {
|
|
185605
|
-
const hash3 =
|
|
185753
|
+
const hash3 = createHash30("sha1").update(`${rootDir}:${agentId}`).digest("hex").slice(0, 12);
|
|
185606
185754
|
return `fusion-agent-memory-${sanitizeAgentMemoryId(agentId).toLowerCase()}-${hash3}`;
|
|
185607
185755
|
}
|
|
185608
185756
|
function buildQmdAgentMemoryCollectionAddArgs(rootDir, agentId) {
|
|
@@ -185731,11 +185879,11 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
|
|
|
185731
185879
|
return;
|
|
185732
185880
|
}
|
|
185733
185881
|
const promise = (async () => {
|
|
185734
|
-
const { execFile:
|
|
185735
|
-
const { promisify:
|
|
185736
|
-
const
|
|
185882
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
185883
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
185884
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
185737
185885
|
try {
|
|
185738
|
-
await
|
|
185886
|
+
await execFileAsync37("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
|
|
185739
185887
|
cwd: rootDir,
|
|
185740
185888
|
timeout: 4e3,
|
|
185741
185889
|
maxBuffer: 512 * 1024
|
|
@@ -185748,8 +185896,8 @@ ${stderr}`)) {
|
|
|
185748
185896
|
throw error2;
|
|
185749
185897
|
}
|
|
185750
185898
|
}
|
|
185751
|
-
await
|
|
185752
|
-
await
|
|
185899
|
+
await execFileAsync37("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
|
|
185900
|
+
await execFileAsync37("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
185753
185901
|
})();
|
|
185754
185902
|
agentQmdRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
|
|
185755
185903
|
try {
|
|
@@ -185804,10 +185952,10 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
|
|
|
185804
185952
|
}
|
|
185805
185953
|
try {
|
|
185806
185954
|
await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
|
|
185807
|
-
const { execFile:
|
|
185808
|
-
const { promisify:
|
|
185809
|
-
const
|
|
185810
|
-
const { stdout } = await
|
|
185955
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
185956
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
185957
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
185958
|
+
const { stdout } = await execFileAsync37("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
|
|
185811
185959
|
cwd: rootDir,
|
|
185812
185960
|
timeout: 4e3,
|
|
185813
185961
|
maxBuffer: 1024 * 1024
|
|
@@ -190384,7 +190532,7 @@ var init_workspace_review_remediation = __esm({
|
|
|
190384
190532
|
});
|
|
190385
190533
|
|
|
190386
190534
|
// ../engine/src/worktree/secrets-env-writer.ts
|
|
190387
|
-
import { createHash as
|
|
190535
|
+
import { createHash as createHash31 } from "node:crypto";
|
|
190388
190536
|
import { execFile as execFile17 } from "node:child_process";
|
|
190389
190537
|
import { promises as fs6 } from "node:fs";
|
|
190390
190538
|
import path3 from "node:path";
|
|
@@ -190393,7 +190541,7 @@ function isValidFilename(filename) {
|
|
|
190393
190541
|
return !!filename && !filename.includes("/") && !filename.includes("\\") && !filename.includes("..") && !filename.includes("\0") && filename !== FINGERPRINT_FILE;
|
|
190394
190542
|
}
|
|
190395
190543
|
function sha2562(content) {
|
|
190396
|
-
return
|
|
190544
|
+
return createHash31("sha256").update(Buffer.from(content, "utf8")).digest("hex");
|
|
190397
190545
|
}
|
|
190398
190546
|
function quote(value) {
|
|
190399
190547
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll(" ", "\\t")}"`;
|
|
@@ -199189,7 +199337,7 @@ var init_mesh_lease_manager = __esm({
|
|
|
199189
199337
|
});
|
|
199190
199338
|
|
|
199191
199339
|
// ../engine/src/merge/merger-integration-worktree.ts
|
|
199192
|
-
import { createHash as
|
|
199340
|
+
import { createHash as createHash33 } from "node:crypto";
|
|
199193
199341
|
import { exec as exec33, execFile as execFile26 } from "node:child_process";
|
|
199194
199342
|
import { promisify as promisify49 } from "node:util";
|
|
199195
199343
|
function quoteAutostashArg(value) {
|
|
@@ -199312,7 +199460,7 @@ async function gitDirtyFingerprintLocal(rootDir) {
|
|
|
199312
199460
|
)
|
|
199313
199461
|
]);
|
|
199314
199462
|
if (!diffOut && !statusOut) return "";
|
|
199315
|
-
return
|
|
199463
|
+
return createHash33("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
|
|
199316
199464
|
} catch {
|
|
199317
199465
|
return "";
|
|
199318
199466
|
}
|
|
@@ -200295,7 +200443,7 @@ import { execSync as execSync6, exec as exec35 } from "node:child_process";
|
|
|
200295
200443
|
import * as childProcess4 from "node:child_process";
|
|
200296
200444
|
import { promisify as promisify52 } from "node:util";
|
|
200297
200445
|
import { existsSync as existsSync61, readFileSync as readFileSync23, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
|
|
200298
|
-
import { createHash as
|
|
200446
|
+
import { createHash as createHash34 } from "node:crypto";
|
|
200299
200447
|
import { join as join80, resolve as resolve47 } from "node:path";
|
|
200300
200448
|
import { hostname as hostname3 } from "node:os";
|
|
200301
200449
|
import { Type as Type4 } from "typebox";
|
|
@@ -200550,7 +200698,7 @@ async function gitDirtyFingerprint(rootDir) {
|
|
|
200550
200698
|
)
|
|
200551
200699
|
]);
|
|
200552
200700
|
if (!diffOut && !statusOut) return "";
|
|
200553
|
-
return
|
|
200701
|
+
return createHash34("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
|
|
200554
200702
|
} catch {
|
|
200555
200703
|
return "";
|
|
200556
200704
|
}
|
|
@@ -209575,19 +209723,51 @@ async function captureBaseCommitSha(store, task, worktreePath, audit, options =
|
|
|
209575
209723
|
}
|
|
209576
209724
|
|
|
209577
209725
|
// ../engine/src/worktree/review-diff-fingerprint.ts
|
|
209578
|
-
import { createHash as
|
|
209726
|
+
import { createHash as createHash24 } from "node:crypto";
|
|
209579
209727
|
import { execFile as execFile8 } from "node:child_process";
|
|
209580
209728
|
import { promisify as promisify8 } from "node:util";
|
|
209581
209729
|
var execFileAsync5 = promisify8(execFile8);
|
|
209730
|
+
var REVIEW_DIFF_GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
209731
|
+
var REVIEW_DIFF_GIT_TIMEOUT_MS = 12e4;
|
|
209732
|
+
function gitCaptureOptions(cwd) {
|
|
209733
|
+
return {
|
|
209734
|
+
cwd,
|
|
209735
|
+
encoding: "utf8",
|
|
209736
|
+
maxBuffer: REVIEW_DIFF_GIT_MAX_BUFFER_BYTES,
|
|
209737
|
+
timeout: REVIEW_DIFF_GIT_TIMEOUT_MS
|
|
209738
|
+
};
|
|
209739
|
+
}
|
|
209740
|
+
function isGitDiffBufferOverflow(error2) {
|
|
209741
|
+
if (typeof error2 !== "object" || error2 === null) return false;
|
|
209742
|
+
const candidate = error2;
|
|
209743
|
+
return candidate.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" || typeof candidate.message === "string" && candidate.message.includes("maxBuffer");
|
|
209744
|
+
}
|
|
209582
209745
|
var MAX_REVIEW_CHANGED_FILES = 100;
|
|
209583
209746
|
var EMPTY_REVIEW_DIFF_FINGERPRINT = "empty-review-input:v1";
|
|
209747
|
+
async function resolveContentReviewInputProof(worktreePath, diffBaseCommitSha) {
|
|
209748
|
+
let baseRef;
|
|
209749
|
+
try {
|
|
209750
|
+
baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
|
|
209751
|
+
} catch {
|
|
209752
|
+
return { kind: "unprovable", reason: "no-diff-base" };
|
|
209753
|
+
}
|
|
209754
|
+
if (!baseRef) return { kind: "unprovable", reason: "no-diff-base" };
|
|
209755
|
+
const probe = await probeReviewDiffFingerprint(worktreePath, baseRef);
|
|
209756
|
+
if (probe.state === "empty") {
|
|
209757
|
+
return { kind: "fingerprint", fingerprint: EMPTY_REVIEW_DIFF_FINGERPRINT };
|
|
209758
|
+
}
|
|
209759
|
+
return probe.state === "fingerprint" ? { kind: "fingerprint", fingerprint: probe.fingerprint } : { kind: "unprovable", reason: probe.reason };
|
|
209760
|
+
}
|
|
209584
209761
|
async function probeReviewDiffFingerprint(worktreePath, baseRef, targetRef = "HEAD") {
|
|
209585
209762
|
if (!worktreePath || !baseRef) return { state: "unavailable", reason: "missing-worktree-or-base" };
|
|
209586
209763
|
try {
|
|
209587
|
-
const { stdout } = await execFileAsync5("git", ["diff", "--binary", `${baseRef}..${targetRef}`],
|
|
209588
|
-
return stdout ? { state: "fingerprint", fingerprint:
|
|
209589
|
-
} catch {
|
|
209590
|
-
return {
|
|
209764
|
+
const { stdout } = await execFileAsync5("git", ["diff", "--binary", `${baseRef}..${targetRef}`], gitCaptureOptions(worktreePath));
|
|
209765
|
+
return stdout ? { state: "fingerprint", fingerprint: createHash24("sha256").update(stdout).digest("hex") } : { state: "empty" };
|
|
209766
|
+
} catch (error2) {
|
|
209767
|
+
return {
|
|
209768
|
+
state: "unavailable",
|
|
209769
|
+
reason: isGitDiffBufferOverflow(error2) ? "git-diff-too-large" : "git-diff-failed"
|
|
209770
|
+
};
|
|
209591
209771
|
}
|
|
209592
209772
|
}
|
|
209593
209773
|
async function probeReviewChangesSinceCommit(worktreePath, reviewedCommitSha) {
|
|
@@ -209595,14 +209775,11 @@ async function probeReviewChangesSinceCommit(worktreePath, reviewedCommitSha) {
|
|
|
209595
209775
|
return { state: "unavailable", reason: "missing-worktree-or-reviewed-commit" };
|
|
209596
209776
|
}
|
|
209597
209777
|
try {
|
|
209598
|
-
await execFileAsync5("git", ["cat-file", "-e", `${reviewedCommitSha}^{commit}`],
|
|
209599
|
-
cwd: worktreePath,
|
|
209600
|
-
encoding: "utf8"
|
|
209601
|
-
});
|
|
209778
|
+
await execFileAsync5("git", ["cat-file", "-e", `${reviewedCommitSha}^{commit}`], gitCaptureOptions(worktreePath));
|
|
209602
209779
|
const [{ stdout: countOutput }, { stdout: filesOutput }, { stdout: shortstatOutput }] = await Promise.all([
|
|
209603
|
-
execFileAsync5("git", ["rev-list", "--count", `${reviewedCommitSha}..HEAD`],
|
|
209604
|
-
execFileAsync5("git", ["diff", "--name-only", "-z", `${reviewedCommitSha}..HEAD`],
|
|
209605
|
-
execFileAsync5("git", ["diff", "--shortstat", `${reviewedCommitSha}..HEAD`],
|
|
209780
|
+
execFileAsync5("git", ["rev-list", "--count", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath)),
|
|
209781
|
+
execFileAsync5("git", ["diff", "--name-only", "-z", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath)),
|
|
209782
|
+
execFileAsync5("git", ["diff", "--shortstat", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath))
|
|
209606
209783
|
]);
|
|
209607
209784
|
const commitCount = Number.parseInt(countOutput.trim(), 10);
|
|
209608
209785
|
if (!Number.isSafeInteger(commitCount) || commitCount < 0) {
|
|
@@ -209639,7 +209816,12 @@ import { promisify as promisify11 } from "node:util";
|
|
|
209639
209816
|
import { join as join57 } from "node:path";
|
|
209640
209817
|
var execFileAsync6 = promisify11(execFile9);
|
|
209641
209818
|
async function git(args, cwd) {
|
|
209642
|
-
const { stdout } = await execFileAsync6("git", args, {
|
|
209819
|
+
const { stdout } = await execFileAsync6("git", args, {
|
|
209820
|
+
cwd,
|
|
209821
|
+
encoding: "utf8",
|
|
209822
|
+
maxBuffer: REVIEW_DIFF_GIT_MAX_BUFFER_BYTES,
|
|
209823
|
+
timeout: REVIEW_DIFF_GIT_TIMEOUT_MS
|
|
209824
|
+
});
|
|
209643
209825
|
return stdout.trim();
|
|
209644
209826
|
}
|
|
209645
209827
|
async function captureWorkspaceReviewEvidence(options) {
|
|
@@ -209721,14 +209903,14 @@ async function captureMergeContentDescriptor(task, deps) {
|
|
|
209721
209903
|
|
|
209722
209904
|
// ../engine/src/project-engine.ts
|
|
209723
209905
|
init_integration_branch();
|
|
209724
|
-
import { execFile as
|
|
209725
|
-
import { promisify as
|
|
209906
|
+
import { execFile as execFile42 } from "node:child_process";
|
|
209907
|
+
import { promisify as promisify90 } from "node:util";
|
|
209726
209908
|
|
|
209727
209909
|
// ../engine/src/runtimes/in-process-runtime.ts
|
|
209728
209910
|
init_src2();
|
|
209729
209911
|
init_scheduler();
|
|
209730
209912
|
init_pi();
|
|
209731
|
-
import { createHash as
|
|
209913
|
+
import { createHash as createHash38 } from "node:crypto";
|
|
209732
209914
|
import { EventEmitter as EventEmitter27 } from "node:events";
|
|
209733
209915
|
|
|
209734
209916
|
// ../engine/src/executor/public-reexports.ts
|
|
@@ -211291,7 +211473,7 @@ var WorkflowGraphExecutor = class {
|
|
|
211291
211473
|
phase: "pre-merge",
|
|
211292
211474
|
source: "optional-group",
|
|
211293
211475
|
status: "skipped",
|
|
211294
|
-
bypassedBy:
|
|
211476
|
+
bypassedBy: FAST_MODE_BYPASS_ACTOR,
|
|
211295
211477
|
bypassedAt,
|
|
211296
211478
|
bypassReason: "Fast mode bypasses pre-merge workflow gates",
|
|
211297
211479
|
bypassedFromStatus: "absent",
|
|
@@ -211495,7 +211677,7 @@ var WorkflowGraphExecutor = class {
|
|
|
211495
211677
|
const stepFindings = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.findings) ? exitContextPatch.findings : void 0;
|
|
211496
211678
|
const repositoryReviewOutcomes = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.repositoryReviewOutcomes) ? exitContextPatch.repositoryReviewOutcomes : void 0;
|
|
211497
211679
|
const repositoryScopeRevision = this.workflowReviewKind(node) && typeof exitContextPatch?.repositoryScopeRevision === "number" ? exitContextPatch.repositoryScopeRevision : void 0;
|
|
211498
|
-
const reviewInputFingerprint = this.workflowReviewKind(node) && typeof exitContextPatch?.reviewInputFingerprint === "string" ? exitContextPatch.reviewInputFingerprint : void 0;
|
|
211680
|
+
const reviewInputFingerprint = requiresContentReviewProof(node.id, { reviewKind: this.workflowReviewKind(node) }) && typeof exitContextPatch?.reviewInputFingerprint === "string" ? exitContextPatch.reviewInputFingerprint : void 0;
|
|
211499
211681
|
const reviewedCommitSha = this.workflowReviewKind(node) && typeof exitContextPatch?.reviewedCommitSha === "string" ? exitContextPatch.reviewedCommitSha : void 0;
|
|
211500
211682
|
const supersededFindingSourceWorkflowStepId = this.workflowReviewKind(node) && typeof exitContextPatch?.supersededFindingSourceWorkflowStepId === "string" ? exitContextPatch.supersededFindingSourceWorkflowStepId : void 0;
|
|
211501
211683
|
const supersededFindingIds = supersededFindingSourceWorkflowStepId && this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.supersededFindingIds) ? exitContextPatch.supersededFindingIds.filter((id) => typeof id === "string") : void 0;
|
|
@@ -212234,7 +212416,7 @@ ${stepOutput}` : ""}`);
|
|
|
212234
212416
|
const findings = this.workflowReviewKind(node) && Array.isArray(contextPatch.findings) ? contextPatch.findings : void 0;
|
|
212235
212417
|
const repositoryReviewOutcomes = this.workflowReviewKind(node) && Array.isArray(contextPatch.repositoryReviewOutcomes) ? contextPatch.repositoryReviewOutcomes : void 0;
|
|
212236
212418
|
const repositoryScopeRevision = this.workflowReviewKind(node) && typeof contextPatch.repositoryScopeRevision === "number" ? contextPatch.repositoryScopeRevision : void 0;
|
|
212237
|
-
const reviewInputFingerprint = this.workflowReviewKind(node) && typeof contextPatch.reviewInputFingerprint === "string" ? contextPatch.reviewInputFingerprint : void 0;
|
|
212419
|
+
const reviewInputFingerprint = requiresContentReviewProof(node.id, { reviewKind: this.workflowReviewKind(node) }) && typeof contextPatch.reviewInputFingerprint === "string" ? contextPatch.reviewInputFingerprint : void 0;
|
|
212238
212420
|
const reviewedCommitSha = this.workflowReviewKind(node) && typeof contextPatch.reviewedCommitSha === "string" ? contextPatch.reviewedCommitSha : void 0;
|
|
212239
212421
|
const supersededFindingSourceWorkflowStepId = this.workflowReviewKind(node) && typeof contextPatch.supersededFindingSourceWorkflowStepId === "string" ? contextPatch.supersededFindingSourceWorkflowStepId : void 0;
|
|
212240
212422
|
const supersededFindingIds = supersededFindingSourceWorkflowStepId && this.workflowReviewKind(node) && Array.isArray(contextPatch.supersededFindingIds) ? contextPatch.supersededFindingIds.filter((id) => typeof id === "string") : void 0;
|
|
@@ -212756,7 +212938,7 @@ init_agent_tools();
|
|
|
212756
212938
|
init_agent_logger();
|
|
212757
212939
|
init_agent_usage_telemetry();
|
|
212758
212940
|
import { Type as Type3 } from "@earendil-works/pi-ai";
|
|
212759
|
-
import { createHash as
|
|
212941
|
+
import { createHash as createHash32 } from "node:crypto";
|
|
212760
212942
|
|
|
212761
212943
|
// ../engine/src/agents/approval-mail.ts
|
|
212762
212944
|
init_src2();
|
|
@@ -214385,7 +214567,7 @@ function truncatePrompt(text2, maxChars) {
|
|
|
214385
214567
|
... (truncated, ${text2.length} chars)`;
|
|
214386
214568
|
}
|
|
214387
214569
|
function shortContentHash(value) {
|
|
214388
|
-
return
|
|
214570
|
+
return createHash32("sha256").update(value).digest("hex").slice(0, 8);
|
|
214389
214571
|
}
|
|
214390
214572
|
function buildIdentitySnapshot(args) {
|
|
214391
214573
|
const { agent, resolvedInstructions, workspaceMemory } = args;
|
|
@@ -218766,6 +218948,51 @@ async function finalizeProvenAutoMergeTask({
|
|
|
218766
218948
|
}
|
|
218767
218949
|
}
|
|
218768
218950
|
|
|
218951
|
+
// ../engine/src/merge/stale-content-review-reroute.ts
|
|
218952
|
+
init_src2();
|
|
218953
|
+
function isContentReviewNode(node) {
|
|
218954
|
+
if (node.kind !== "optional-group" && node.kind !== "step-review") return false;
|
|
218955
|
+
const name2 = typeof node.config?.name === "string" ? node.config.name : "";
|
|
218956
|
+
return node.id === "code-review" || node.config?.reviewKind === "code" || /code review/i.test(name2);
|
|
218957
|
+
}
|
|
218958
|
+
async function rerouteSingularStaleContentToReview(store, task, options) {
|
|
218959
|
+
const mergeContent = options.mergeContent;
|
|
218960
|
+
if (mergeContent.kind !== "singular" || task.workspaceWorktrees !== void 0) {
|
|
218961
|
+
return { rerouted: false, reason: "not-singular" };
|
|
218962
|
+
}
|
|
218963
|
+
if (task.paused || task.userPaused || task.deletedAt || task.autoMerge === false) {
|
|
218964
|
+
return { rerouted: false, reason: "operator-held" };
|
|
218965
|
+
}
|
|
218966
|
+
if (mergeContent.diff.state !== "fingerprint") return { rerouted: false, reason: "no-progress" };
|
|
218967
|
+
const currentFingerprint = mergeContent.diff.fingerprint;
|
|
218968
|
+
const ir2 = await resolveWorkflowIrForTask(store, task.id);
|
|
218969
|
+
const selection = store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(task.id) : store.getTaskWorkflowSelection(task.id);
|
|
218970
|
+
const selected = selection?.stepIds ?? [];
|
|
218971
|
+
const nodes2 = ir2.nodes.filter((node2) => {
|
|
218972
|
+
if (!isContentReviewNode(node2) || !options.requiredPreMergeStepIds.has(node2.id)) return false;
|
|
218973
|
+
return node2.config?.defaultOn === true || selected.includes(node2.id);
|
|
218974
|
+
});
|
|
218975
|
+
const node = nodes2.find((candidate) => {
|
|
218976
|
+
const latest = task.workflowStepResults?.filter((result2) => result2.workflowStepId === candidate.id).at(-1);
|
|
218977
|
+
return latest?.reviewInputFingerprint !== currentFingerprint;
|
|
218978
|
+
});
|
|
218979
|
+
if (!node) return { rerouted: false, reason: nodes2.length ? "no-progress" : "no-review-route" };
|
|
218980
|
+
const items = await store.listWorkflowWorkItemsForTask(task.id);
|
|
218981
|
+
const result = await store.seedWorkspaceCodeReviewContinuationIfIdle({
|
|
218982
|
+
taskId: task.id,
|
|
218983
|
+
nodeId: node.id,
|
|
218984
|
+
kind: "task",
|
|
218985
|
+
state: "runnable",
|
|
218986
|
+
runId: `${task.id}:stale-content-review-reroute:${node.id}:${items.length}`,
|
|
218987
|
+
stableWorkflowRunId: `${task.id}:${ir2.name}`,
|
|
218988
|
+
continuationSequence: items.length,
|
|
218989
|
+
sourceColumn: task.column,
|
|
218990
|
+
targetColumn: node.column ?? task.column,
|
|
218991
|
+
irHash: computeWorkflowIrPin(ir2, node.id).irHash
|
|
218992
|
+
});
|
|
218993
|
+
return result.seeded ? { rerouted: true, reason: "seeded", nodeId: node.id, workflowStepId: node.id } : { rerouted: false, reason: "active-continuation", nodeId: node.id, workflowStepId: node.id };
|
|
218994
|
+
}
|
|
218995
|
+
|
|
218769
218996
|
// ../engine/src/healing/auto-recovery.ts
|
|
218770
218997
|
init_logger();
|
|
218771
218998
|
var autoRecoveryLog = createLogger("auto-recovery");
|
|
@@ -220175,9 +220402,6 @@ var BOARD_STALL_NOTIFICATION_COOLDOWN_MS = 60 * 6e4;
|
|
|
220175
220402
|
var DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
220176
220403
|
var PHANTOM_EXECUTOR_BINDING_AGE_MULTIPLIER = 3;
|
|
220177
220404
|
var MAX_NO_PROGRESS_RESUME_ATTEMPTS = 2;
|
|
220178
|
-
function resolveRepoLocalAiMergeRoot(rootDir, settings) {
|
|
220179
|
-
return resolveAiMergeRootPath(rootDir, settings);
|
|
220180
|
-
}
|
|
220181
220405
|
async function classifyOwnedLandedEvidenceForSelfHealing(rootDir, task, mergeTargetBranch) {
|
|
220182
220406
|
const { classifyOwnedLandedEvidence: classifyOwnedLandedEvidence2 } = await Promise.resolve().then(() => (init_merger(), merger_exports));
|
|
220183
220407
|
return classifyOwnedLandedEvidence2(rootDir, task, { mergeTargetBranch });
|
|
@@ -220354,6 +220578,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
220354
220578
|
symbolLockNoActionAudited = false;
|
|
220355
220579
|
maintenanceTickCounter = 0;
|
|
220356
220580
|
taskLifecycleRetentionLastPrunedAt = /* @__PURE__ */ new Map();
|
|
220581
|
+
staleContentRerouteAuditKeys = /* @__PURE__ */ new Set();
|
|
220357
220582
|
githubCheckStateRetentionLastPrunedAt = /* @__PURE__ */ new Map();
|
|
220358
220583
|
processBootStartedAt = Date.now();
|
|
220359
220584
|
lastDbCorruptionNotifiedAt = null;
|
|
@@ -221069,6 +221294,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
221069
221294
|
// flight" to all of them (the merge gate included), which is the two-hour
|
|
221070
221295
|
// stall-deadlock ride this sweep exists to prevent.
|
|
221071
221296
|
{ name: "reconcile-orphaned-pending-step-results", fn: () => this.reconcileOrphanedPendingStepResults().then(() => void 0) },
|
|
221297
|
+
{ name: "reconcile-unproven-review-approvals", fn: () => this.reconcileUnprovenReviewApprovals().then(() => void 0) },
|
|
221072
221298
|
/*
|
|
221073
221299
|
FNXC:WorkspaceContention 2026-08-23-08:00:
|
|
221074
221300
|
`contention-hold` is owned by an in-memory retry timer. After a process restart that
|
|
@@ -221949,6 +222175,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
221949
222175
|
Keep them adjacent and in this order.
|
|
221950
222176
|
*/
|
|
221951
222177
|
{ name: "reconcile-orphaned-pending-step-results", fn: () => this.reconcileOrphanedPendingStepResults() },
|
|
222178
|
+
{ name: "reconcile-unproven-review-approvals", fn: () => this.reconcileUnprovenReviewApprovals() },
|
|
221952
222179
|
{ name: "recover-failed-pre-merge-steps", fn: () => this.recoverReviewTasksWithFailedPreMergeSteps() },
|
|
221953
222180
|
{ name: "recover-missing-worktree-review-failures", fn: () => this.recoverMissingWorktreeReviewFailures() },
|
|
221954
222181
|
{ name: "recover-interrupted-merging", fn: () => this.recoverInterruptedMergingTasks() },
|
|
@@ -226395,6 +226622,95 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
226395
226622
|
return 0;
|
|
226396
226623
|
}
|
|
226397
226624
|
}
|
|
226625
|
+
/*
|
|
226626
|
+
FNXC:ReviewInputProof 2026-09-01-11:28:
|
|
226627
|
+
Prevention cannot release cards that already persisted a proofless `passed` content review. Repair
|
|
226628
|
+
only the invalid result in place, including when auto-merge is off, so automatic recovery can re-run
|
|
226629
|
+
eligible gates and a human-held card gains the failed result its audited bypass needs. The
|
|
226630
|
+
`needsOperatorBypass` label is therefore truthful rather than aspirational; no lifecycle state moves.
|
|
226631
|
+
|
|
226632
|
+
FNXC:ReviewInputProof 2026-09-01-11:57:
|
|
226633
|
+
Reconciliation must recompute from the lock-held task inside `updateTaskAtomic`; a graph writer can
|
|
226634
|
+
publish a proof-bound approval or another gate after the preliminary read, and a stale array write
|
|
226635
|
+
would discard that valid result. Re-check lane, user pause, workspace ownership, and session liveness
|
|
226636
|
+
in the callback, then log and audit only a repair whose atomic mutation actually applied.
|
|
226637
|
+
*/
|
|
226638
|
+
async reconcileUnprovenReviewApprovals() {
|
|
226639
|
+
try {
|
|
226640
|
+
const reviewColumns = await resolveProjectColumnsForRoles(this.store, REVIEW_ROLES);
|
|
226641
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
226642
|
+
for (const column of reviewColumns) {
|
|
226643
|
+
for (const task of await this.store.listTasks({ column, slim: true })) candidates.set(task.id, task);
|
|
226644
|
+
}
|
|
226645
|
+
const settings = await this.store.getSettings().catch(() => void 0);
|
|
226646
|
+
let repairedTasks = 0;
|
|
226647
|
+
const isSessionLive = (taskId) => {
|
|
226648
|
+
const livePaths = activeSessionRegistry.pathsForTask(taskId);
|
|
226649
|
+
return livePaths.some((path6) => activeSessionRegistry.isPathActive(path6)) || executingTaskLock.has(taskId) || this.options.isTaskActive?.(taskId) === true;
|
|
226650
|
+
};
|
|
226651
|
+
for (const candidate of candidates.values()) {
|
|
226652
|
+
if (candidate.userPaused === true || candidate.workspaceWorktrees !== void 0 || isSessionLive(candidate.id)) continue;
|
|
226653
|
+
if (!candidate.workflowStepResults?.some((result) => resolveUnprovenReviewApproval(result, { workspace: false }))) continue;
|
|
226654
|
+
const fresh = await this.store.getTask(candidate.id);
|
|
226655
|
+
if (!fresh || !reviewColumns.has(fresh.column) || fresh.userPaused === true || fresh.workspaceWorktrees !== void 0 || isSessionLive(fresh.id)) continue;
|
|
226656
|
+
let repair;
|
|
226657
|
+
try {
|
|
226658
|
+
await this.store.updateTaskAtomic(fresh.id, (live) => {
|
|
226659
|
+
repair = void 0;
|
|
226660
|
+
if (!reviewColumns.has(live.column) || live.userPaused === true || live.workspaceWorktrees !== void 0 || isSessionLive(live.id)) return null;
|
|
226661
|
+
const repairedStepIds = [];
|
|
226662
|
+
let repairReason;
|
|
226663
|
+
const results = (live.workflowStepResults ?? []).map((result) => {
|
|
226664
|
+
const resolution = resolveUnprovenReviewApproval(result, { workspace: false });
|
|
226665
|
+
if (!resolution) return result;
|
|
226666
|
+
repairedStepIds.push(result.workflowStepId);
|
|
226667
|
+
repairReason ??= resolution.reason;
|
|
226668
|
+
return resolution.downgraded;
|
|
226669
|
+
});
|
|
226670
|
+
if (repairedStepIds.length === 0 || !repairReason) return null;
|
|
226671
|
+
repair = {
|
|
226672
|
+
stepIds: repairedStepIds,
|
|
226673
|
+
reason: repairReason,
|
|
226674
|
+
column: live.column,
|
|
226675
|
+
resultCount: results.length,
|
|
226676
|
+
needsOperatorBypass: settings ? !allowsAutoMergeProcessing(live, settings) : void 0
|
|
226677
|
+
};
|
|
226678
|
+
return { workflowStepResults: results };
|
|
226679
|
+
});
|
|
226680
|
+
if (!repair) continue;
|
|
226681
|
+
repairedTasks += 1;
|
|
226682
|
+
} catch (error2) {
|
|
226683
|
+
log34.warn(`reconcileUnprovenReviewApprovals: failed for ${fresh.id}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
226684
|
+
continue;
|
|
226685
|
+
}
|
|
226686
|
+
await this.store.logEntry(
|
|
226687
|
+
fresh.id,
|
|
226688
|
+
`[pre-merge] Invalid proofless approval repaired for ${repair.stepIds.join(", ")}: ${repair.reason}`
|
|
226689
|
+
).catch(() => void 0);
|
|
226690
|
+
await emitBoundedRunAudit2(this.store, {
|
|
226691
|
+
taskId: fresh.id,
|
|
226692
|
+
agentId: "self-healing",
|
|
226693
|
+
runId: generateSyntheticRunId("reconcile-unproven-review-approval", fresh.id),
|
|
226694
|
+
domain: "database",
|
|
226695
|
+
mutationType: "task:reconcile-unproven-review-approval",
|
|
226696
|
+
target: fresh.id,
|
|
226697
|
+
metadata: {
|
|
226698
|
+
taskId: fresh.id,
|
|
226699
|
+
column: repair.column,
|
|
226700
|
+
workflowStepId: repair.stepIds[0],
|
|
226701
|
+
repairedCount: repair.stepIds.length,
|
|
226702
|
+
resultCount: repair.resultCount,
|
|
226703
|
+
needsOperatorBypass: repair.needsOperatorBypass
|
|
226704
|
+
}
|
|
226705
|
+
}, { log: log34 });
|
|
226706
|
+
}
|
|
226707
|
+
if (repairedTasks > 0) log34.log(`Repaired unproven review approvals on ${repairedTasks} task(s)`);
|
|
226708
|
+
return repairedTasks;
|
|
226709
|
+
} catch (error2) {
|
|
226710
|
+
log34.error(`reconcileUnprovenReviewApprovals failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
226711
|
+
return 0;
|
|
226712
|
+
}
|
|
226713
|
+
}
|
|
226398
226714
|
/**
|
|
226399
226715
|
* Backward lifecycle move gated on triple proof (FN-5335).
|
|
226400
226716
|
* When the unproven fallback predicate fails, emits `task:finalize-no-op-review-no-action` and skips lifecycle mutation.
|
|
@@ -226748,6 +227064,66 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
226748
227064
|
}
|
|
226749
227065
|
return allowsAutoMergeProcessing(task, settings) && resolveEffectiveAutoMerge(task, settings) !== false;
|
|
226750
227066
|
}
|
|
227067
|
+
/*
|
|
227068
|
+
FNXC:PreMergeApproval 2026-09-01-14:05:
|
|
227069
|
+
Self-healing must not treat a stale content-bound approval as mergeable just because the cheap
|
|
227070
|
+
blocker check lacks a fresh Git descriptor. Capture the same merge content the merge queue uses and
|
|
227071
|
+
seed the graph back at Code Review, so cards like FN-9234 stop looping through doomed merge retries.
|
|
227072
|
+
*/
|
|
227073
|
+
async routeStaleSingularApprovalBackToReview(task, reviewColumns, settings) {
|
|
227074
|
+
let mergeGate;
|
|
227075
|
+
try {
|
|
227076
|
+
mergeGate = await resolvePreMergeGateForTask(this.store, task.id, task.enabledWorkflowSteps, task);
|
|
227077
|
+
} catch {
|
|
227078
|
+
return false;
|
|
227079
|
+
}
|
|
227080
|
+
if (mergeGate.provenance === "default" && !mergeGate.selectionAbsent) return false;
|
|
227081
|
+
const mergeContent = await captureMergeContentDescriptor(task, {
|
|
227082
|
+
workspaceRootDir: this.options.rootDir,
|
|
227083
|
+
settings
|
|
227084
|
+
});
|
|
227085
|
+
const blocker = getTaskMergeBlocker(task, {
|
|
227086
|
+
reviewColumns,
|
|
227087
|
+
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
227088
|
+
mergeContent
|
|
227089
|
+
});
|
|
227090
|
+
if (blocker !== "task has a pre-merge approval recorded against different content" || mergeContent.kind !== "singular") {
|
|
227091
|
+
return false;
|
|
227092
|
+
}
|
|
227093
|
+
const reroute = await rerouteSingularStaleContentToReview(this.store, task, {
|
|
227094
|
+
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
227095
|
+
mergeContent
|
|
227096
|
+
}).catch(() => ({
|
|
227097
|
+
rerouted: false,
|
|
227098
|
+
reason: "no-progress",
|
|
227099
|
+
nodeId: void 0,
|
|
227100
|
+
workflowStepId: void 0
|
|
227101
|
+
}));
|
|
227102
|
+
if (reroute.rerouted) {
|
|
227103
|
+
await this.store.logEntry(task.id, "[pre-merge] Self-healing re-seeded Code Review after stale content evidence blocked merge.");
|
|
227104
|
+
log34.warn(`Stale content approval for ${task.id} re-seeded at ${reroute.nodeId ?? "code-review"}`);
|
|
227105
|
+
}
|
|
227106
|
+
const auditKey = `${task.id}:${reroute.reason}:${reroute.nodeId ?? ""}`;
|
|
227107
|
+
if (!this.staleContentRerouteAuditKeys.has(auditKey)) {
|
|
227108
|
+
this.staleContentRerouteAuditKeys.add(auditKey);
|
|
227109
|
+
await emitBoundedRunAudit2(this.store, {
|
|
227110
|
+
taskId: task.id,
|
|
227111
|
+
agentId: "self-healing",
|
|
227112
|
+
runId: generateSyntheticRunId("self-healing", task.id),
|
|
227113
|
+
domain: "database",
|
|
227114
|
+
mutationType: "task:merge-stale-content-review-rerouted",
|
|
227115
|
+
target: task.id,
|
|
227116
|
+
metadata: {
|
|
227117
|
+
taskId: task.id,
|
|
227118
|
+
nodeId: reroute.nodeId,
|
|
227119
|
+
workflowStepId: reroute.workflowStepId,
|
|
227120
|
+
reason: reroute.reason,
|
|
227121
|
+
source: "self-healing"
|
|
227122
|
+
}
|
|
227123
|
+
});
|
|
227124
|
+
}
|
|
227125
|
+
return true;
|
|
227126
|
+
}
|
|
226751
227127
|
/**
|
|
226752
227128
|
* Recover `in-review` tasks that are fully mergeable but never had
|
|
226753
227129
|
* `mergeTask()` invoked.
|
|
@@ -226801,6 +227177,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
226801
227177
|
for (const task of mergeable) {
|
|
226802
227178
|
const reviewColumns = await ownReviewLanesFor(task);
|
|
226803
227179
|
if (!reviewColumns.has(task.column)) continue;
|
|
227180
|
+
if (await this.routeStaleSingularApprovalBackToReview(task, reviewColumns, settings)) continue;
|
|
226804
227181
|
if (getTaskMergeBlocker(task, { reviewColumns }) !== void 0) continue;
|
|
226805
227182
|
laneQualifiedMergeable.push(task);
|
|
226806
227183
|
}
|
|
@@ -229367,8 +229744,7 @@ This review is not retried until its findings change. Re-run the review after ad
|
|
|
229367
229744
|
}
|
|
229368
229745
|
async listAiMergeWorktreeCandidates(taskId, settings) {
|
|
229369
229746
|
const roots = Array.from(/* @__PURE__ */ new Set([
|
|
229370
|
-
|
|
229371
|
-
resolveLegacyAiMergeRootPath(this.options.rootDir),
|
|
229747
|
+
...resolveAiMergeSearchRoots(this.options.rootDir, settings),
|
|
229372
229748
|
tmpdir8()
|
|
229373
229749
|
]));
|
|
229374
229750
|
const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
|
|
@@ -231902,9 +232278,7 @@ This review is not retried until its findings change. Re-run the review after ad
|
|
|
231902
232278
|
log34.debug("[self-healing] temp-dir sweep: worktrunk enabled \u2014 AI merge clean-room worktrees use Fusion's dedicated clean-room root, proceeding with native sweep");
|
|
231903
232279
|
}
|
|
231904
232280
|
const roots = Array.from(/* @__PURE__ */ new Set([
|
|
231905
|
-
|
|
231906
|
-
resolveLegacyAiMergeRootPath(this.options.rootDir),
|
|
231907
|
-
...settings.worktreesDir ? [] : [join81(resolveLegacyWorktreesDirLayout(this.options.rootDir), ".ai-merge")],
|
|
232281
|
+
...resolveAiMergeSearchRoots(this.options.rootDir, settings),
|
|
231908
232282
|
tmpdir8()
|
|
231909
232283
|
]));
|
|
231910
232284
|
const auditor = createRunAuditor(this.store, {
|
|
@@ -234559,7 +234933,7 @@ ${recommendation.description}`)) {
|
|
|
234559
234933
|
// ../engine/src/executor/execute-workflow-step.ts
|
|
234560
234934
|
init_src2();
|
|
234561
234935
|
import { exec as exec41 } from "node:child_process";
|
|
234562
|
-
import { promisify as
|
|
234936
|
+
import { promisify as promisify59 } from "node:util";
|
|
234563
234937
|
|
|
234564
234938
|
// ../engine/src/executor/shared-worker-tools.ts
|
|
234565
234939
|
init_agent_tools();
|
|
@@ -236418,6 +236792,47 @@ function isWorkflowStepSkillDiscoverable(skillName, additionalSkillPaths, ceSkil
|
|
|
236418
236792
|
);
|
|
236419
236793
|
}
|
|
236420
236794
|
|
|
236795
|
+
// ../engine/src/worktree/review-inline-fix-recapture.ts
|
|
236796
|
+
import { execFile as execFile29 } from "node:child_process";
|
|
236797
|
+
import { promisify as promisify58 } from "node:util";
|
|
236798
|
+
var execFileAsync23 = promisify58(execFile29);
|
|
236799
|
+
function classifyReviewInlineFixRecapture(input) {
|
|
236800
|
+
if (input.reviewKind === "plan") return { recapture: false, reason: "plan-domain" };
|
|
236801
|
+
if (input.verdict !== "APPROVE" && input.verdict !== "APPROVE_WITH_NOTES") {
|
|
236802
|
+
return { recapture: false, reason: "not-approval-verdict" };
|
|
236803
|
+
}
|
|
236804
|
+
if (!input.reviewedCommitSha || !input.currentHeadSha || !input.baseRef) {
|
|
236805
|
+
return { recapture: false, reason: "missing-anchor" };
|
|
236806
|
+
}
|
|
236807
|
+
if (input.reviewedCommitSha === input.currentHeadSha) return { recapture: false, reason: "head-unchanged" };
|
|
236808
|
+
if (input.fastForwardAdvance === void 0 || input.baseIsAncestor === void 0) {
|
|
236809
|
+
return { recapture: false, reason: "probe-unavailable" };
|
|
236810
|
+
}
|
|
236811
|
+
if (!input.fastForwardAdvance) return { recapture: false, reason: "history-rewritten" };
|
|
236812
|
+
if (!input.baseIsAncestor) return { recapture: false, reason: "base-not-ancestor" };
|
|
236813
|
+
if (!input.fingerprintProbeAvailable) return { recapture: false, reason: "probe-unavailable" };
|
|
236814
|
+
return { recapture: true, reason: "recaptured" };
|
|
236815
|
+
}
|
|
236816
|
+
async function readHeadSha(worktreePath) {
|
|
236817
|
+
if (!worktreePath) return void 0;
|
|
236818
|
+
try {
|
|
236819
|
+
const { stdout } = await execFileAsync23("git", ["rev-parse", "HEAD"], { cwd: worktreePath, encoding: "utf8" });
|
|
236820
|
+
return stdout.trim() || void 0;
|
|
236821
|
+
} catch {
|
|
236822
|
+
return void 0;
|
|
236823
|
+
}
|
|
236824
|
+
}
|
|
236825
|
+
async function isFastForwardAdvance(worktreePath, fromSha, toSha) {
|
|
236826
|
+
if (!worktreePath || !fromSha || !toSha) return void 0;
|
|
236827
|
+
try {
|
|
236828
|
+
await execFileAsync23("git", ["merge-base", "--is-ancestor", fromSha, toSha], { cwd: worktreePath, encoding: "utf8" });
|
|
236829
|
+
return true;
|
|
236830
|
+
} catch (error2) {
|
|
236831
|
+
const code = error2?.code;
|
|
236832
|
+
return code === 1 ? false : void 0;
|
|
236833
|
+
}
|
|
236834
|
+
}
|
|
236835
|
+
|
|
236421
236836
|
// ../engine/src/executor/optional-step-revision.ts
|
|
236422
236837
|
init_src2();
|
|
236423
236838
|
|
|
@@ -236575,7 +236990,7 @@ function buildGraphPlanReviewConvergenceContext(task, revisionKey) {
|
|
|
236575
236990
|
|
|
236576
236991
|
// ../engine/src/executor/execute-workflow-step.ts
|
|
236577
236992
|
init_agent_usage_telemetry();
|
|
236578
|
-
var execAsync38 =
|
|
236993
|
+
var execAsync38 = promisify59(exec41);
|
|
236579
236994
|
var WORKFLOW_STEP_NOTES_REPAIR_TIMEOUT_MS = 12e4;
|
|
236580
236995
|
function findReusableReviewResult(task, workflowStepId, reviewInputFingerprint, repositoryScopeRevision) {
|
|
236581
236996
|
if (!reviewInputFingerprint) return void 0;
|
|
@@ -236614,6 +237029,8 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236614
237029
|
const unattended = stepOptions?.unattended === true;
|
|
236615
237030
|
const workflowStepMetadata = workflowStep;
|
|
236616
237031
|
const optionalGroupId = workflowStepMetadata.optionalGroupId;
|
|
237032
|
+
const effectiveWorkflowStepId = optionalGroupId ?? workflowStep.id.replace(/^graph:/, "");
|
|
237033
|
+
const isContentBindingStep = requiresContentReviewProof(effectiveWorkflowStepId, workflowStepMetadata);
|
|
236617
237034
|
const isPlanReviewStep = workflowStep.id === "graph:plan-review-step" || workflowStep.name === "Plan Review" || optionalGroupId === PLAN_REVIEW_GROUP_ID;
|
|
236618
237035
|
const planReviewRevisionKey = optionalStepRevisionKey2(optionalGroupId, workflowStep.name);
|
|
236619
237036
|
const isReviewTypeWorkflowStep = isPlanReviewStep || workflowStepMetadata.reviewCanFixInline === true || /(?:^|\b)(?:review|verification)(?:\b|$)/i.test(workflowStep.name) || optionalGroupId === "plan-review" || optionalGroupId === "code-review" || optionalGroupId === "browser-verification";
|
|
@@ -236624,6 +237041,8 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236624
237041
|
toolMode = "coding";
|
|
236625
237042
|
}
|
|
236626
237043
|
const requireExternalIntegrationEvidence = workflowStepMetadata.requireExternalIntegrationEvidence === true;
|
|
237044
|
+
const readonlyMcpServerAllowlist = toolMode === "readonly" ? [...new Set((workflowStepMetadata.readonlyMcpServers ?? []).map((name2) => name2.trim()).filter(Boolean))] : [];
|
|
237045
|
+
const allowReadonlyMcpTools = toolMode === "readonly" && readonlyMcpServerAllowlist.length > 0;
|
|
236627
237046
|
let workflowReviewSpecArtifact;
|
|
236628
237047
|
if (isReviewTypeWorkflowStep) {
|
|
236629
237048
|
try {
|
|
@@ -236642,7 +237061,7 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236642
237061
|
const workflowReviewSpecText = typeof workflowReviewSpecArtifact === "string" ? workflowReviewSpecArtifact : "";
|
|
236643
237062
|
const planReviewSpecText = isPlanReviewStep ? workflowReviewSpecText : "";
|
|
236644
237063
|
const latestTaskForUserComments = await deps.store.getTask(task.id).catch(() => task);
|
|
236645
|
-
const sameGateStepId =
|
|
237064
|
+
const sameGateStepId = effectiveWorkflowStepId;
|
|
236646
237065
|
const planReviewConvergenceContext = isPlanReviewStep ? buildGraphPlanReviewConvergenceContext(latestTaskForUserComments, planReviewRevisionKey) : "";
|
|
236647
237066
|
const planReviewEnvironmentCapabilities = isPlanReviewStep ? await probeEnvironmentCapabilities({
|
|
236648
237067
|
extraCommands: [
|
|
@@ -236690,21 +237109,44 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236690
237109
|
let diffShortstat;
|
|
236691
237110
|
let reviewInputFingerprint;
|
|
236692
237111
|
let reviewedCommitSha;
|
|
237112
|
+
let baseRef;
|
|
236693
237113
|
try {
|
|
236694
|
-
|
|
236695
|
-
|
|
236696
|
-
|
|
236697
|
-
|
|
236698
|
-
|
|
236699
|
-
|
|
236700
|
-
|
|
237114
|
+
baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
|
|
237115
|
+
} catch {
|
|
237116
|
+
}
|
|
237117
|
+
if (isContentBindingStep && task.workspaceWorktrees === void 0) {
|
|
237118
|
+
const suppliedFingerprint = stepOptions?.reviewInputFingerprint?.trim();
|
|
237119
|
+
const proof = suppliedFingerprint ? { kind: "fingerprint", fingerprint: suppliedFingerprint } : await resolveContentReviewInputProof(worktreePath, diffBaseCommitSha);
|
|
237120
|
+
if (proof.kind === "unprovable") {
|
|
237121
|
+
const diagnostic = `${workflowStep.name} review input is unprovable (${proof.reason}); reviewer dispatch refused.`;
|
|
237122
|
+
await deps.store.logEntry(
|
|
237123
|
+
task.id,
|
|
237124
|
+
`[pre-merge] ${diagnostic}`,
|
|
237125
|
+
void 0,
|
|
237126
|
+
deps.getRunContextFor(task.id)
|
|
237127
|
+
);
|
|
237128
|
+
return { success: false, error: diagnostic, failureValue: "review-input-unprovable" };
|
|
237129
|
+
}
|
|
237130
|
+
reviewInputFingerprint = proof.fingerprint;
|
|
237131
|
+
} else if (baseRef) {
|
|
237132
|
+
try {
|
|
236701
237133
|
if (workflowStepMetadata.reviewKind === "code") {
|
|
236702
237134
|
reviewInputFingerprint = await computeCodeReviewInputFingerprint(worktreePath, baseRef);
|
|
236703
237135
|
} else if (isReviewTypeWorkflowStep) {
|
|
236704
237136
|
reviewInputFingerprint = await computeReviewDiffFingerprint(worktreePath, baseRef);
|
|
236705
237137
|
}
|
|
237138
|
+
} catch {
|
|
237139
|
+
}
|
|
237140
|
+
}
|
|
237141
|
+
if (baseRef) {
|
|
237142
|
+
try {
|
|
237143
|
+
const { stdout } = await execAsync38(`git diff --shortstat ${baseRef}..HEAD`, {
|
|
237144
|
+
cwd: worktreePath,
|
|
237145
|
+
encoding: "utf-8"
|
|
237146
|
+
});
|
|
237147
|
+
diffShortstat = stdout.trim() || void 0;
|
|
237148
|
+
} catch {
|
|
236706
237149
|
}
|
|
236707
|
-
} catch {
|
|
236708
237150
|
}
|
|
236709
237151
|
if (isReviewTypeWorkflowStep) {
|
|
236710
237152
|
try {
|
|
@@ -237014,6 +237456,12 @@ ${workflowStepUserCommentSection}` : ""}${priorFindingsBlock}
|
|
|
237014
237456
|
const workflowStepThinkingSource = workflowStep.thinkingLevel ?? (isReviewTypeWorkflowStep ? task.validatorThinkingLevel ?? task.thinkingLevel : task.thinkingLevel);
|
|
237015
237457
|
const workflowStepThinkingLevel = attemptLabel === "fallback" ? isReviewTypeWorkflowStep ? resolveValidatorFallbackThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorFallbackThinkingLevel(workflowStepThinkingSource, settings) : isReviewTypeWorkflowStep ? resolveValidatorThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorThinkingLevel(workflowStepThinkingSource, settings);
|
|
237016
237458
|
const workflowStepFallbackThinkingLevel = isReviewTypeWorkflowStep ? resolveValidatorFallbackThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorFallbackThinkingLevel(workflowStepThinkingSource, settings);
|
|
237459
|
+
if (allowReadonlyMcpTools) {
|
|
237460
|
+
await deps.store.logEntry(
|
|
237461
|
+
task.id,
|
|
237462
|
+
`Workflow step '${workflowStep.name}' enabled read-only MCP servers: ${readonlyMcpServerAllowlist.join(", ")}`
|
|
237463
|
+
);
|
|
237464
|
+
}
|
|
237017
237465
|
const { session } = await createResolvedAgentSession({
|
|
237018
237466
|
sessionPurpose: "executor",
|
|
237019
237467
|
taskExecutionSession: true,
|
|
@@ -237034,6 +237482,10 @@ ${workflowStepUserCommentSection}` : ""}${priorFindingsBlock}
|
|
|
237034
237482
|
settings,
|
|
237035
237483
|
taskEnv: stepEnv,
|
|
237036
237484
|
mcpServers: await deps.resolveMcpServers(void 0),
|
|
237485
|
+
...allowReadonlyMcpTools ? {
|
|
237486
|
+
allowMcpToolsInReadonly: true,
|
|
237487
|
+
readonlyMcpServerAllowlist
|
|
237488
|
+
} : {},
|
|
237037
237489
|
// FNXC:SessionRouting 2026-06-24-11:20:
|
|
237038
237490
|
// #1675: propagate task id so workflow-step requests carry the same
|
|
237039
237491
|
// X-Session-Id/X-Session-Affinity as the primary session.
|
|
@@ -237249,6 +237701,60 @@ ${detectedQuestion}
|
|
|
237249
237701
|
});
|
|
237250
237702
|
}
|
|
237251
237703
|
const revisionRequested = effectiveVerdict === "REVISE";
|
|
237704
|
+
if (isReviewTypeWorkflowStep && !isPlanReviewStep && !revisionRequested) {
|
|
237705
|
+
const priorReviewedCommitSha = reviewedCommitSha;
|
|
237706
|
+
const currentHeadSha = await readHeadSha(worktreePath);
|
|
237707
|
+
const fastForwardAdvance = await isFastForwardAdvance(worktreePath, priorReviewedCommitSha, currentHeadSha);
|
|
237708
|
+
const baseIsAncestor = await isFastForwardAdvance(worktreePath, baseRef, currentHeadSha);
|
|
237709
|
+
const decision = classifyReviewInlineFixRecapture({
|
|
237710
|
+
verdict: effectiveVerdict,
|
|
237711
|
+
reviewKind: workflowStepMetadata.reviewKind,
|
|
237712
|
+
reviewedCommitSha: priorReviewedCommitSha,
|
|
237713
|
+
currentHeadSha,
|
|
237714
|
+
baseRef,
|
|
237715
|
+
fastForwardAdvance,
|
|
237716
|
+
baseIsAncestor,
|
|
237717
|
+
fingerprintProbeAvailable: true
|
|
237718
|
+
});
|
|
237719
|
+
if (decision.recapture) {
|
|
237720
|
+
try {
|
|
237721
|
+
const recapturedFingerprint = workflowStepMetadata.reviewKind === "code" ? await computeCodeReviewInputFingerprint(worktreePath, baseRef) : await computeReviewDiffFingerprint(worktreePath, baseRef);
|
|
237722
|
+
const finalDecision = classifyReviewInlineFixRecapture({
|
|
237723
|
+
verdict: effectiveVerdict,
|
|
237724
|
+
reviewKind: workflowStepMetadata.reviewKind,
|
|
237725
|
+
reviewedCommitSha: priorReviewedCommitSha,
|
|
237726
|
+
currentHeadSha,
|
|
237727
|
+
baseRef,
|
|
237728
|
+
fastForwardAdvance,
|
|
237729
|
+
baseIsAncestor,
|
|
237730
|
+
fingerprintProbeAvailable: recapturedFingerprint !== void 0
|
|
237731
|
+
});
|
|
237732
|
+
if (finalDecision.recapture && currentHeadSha) {
|
|
237733
|
+
reviewInputFingerprint = recapturedFingerprint;
|
|
237734
|
+
reviewedCommitSha = currentHeadSha;
|
|
237735
|
+
const resolvedInReviewFindingCount = parsed.findings?.filter((finding) => finding.resolution === "resolved-in-review").length ?? 0;
|
|
237736
|
+
await deps.store.logEntry(task.id, `[pre-merge] ${workflowStep.name} re-captured its own review identity after fast-forward ${priorReviewedCommitSha?.slice(0, 7)} \u2192 ${currentHeadSha.slice(0, 7)} (${finalDecision.reason})`);
|
|
237737
|
+
const runContext = deps.getRunContextFor(task.id);
|
|
237738
|
+
if (runContext) await emitBoundedRunAudit2(deps.store, {
|
|
237739
|
+
taskId: task.id,
|
|
237740
|
+
agentId: runContext.agentId,
|
|
237741
|
+
runId: runContext.runId,
|
|
237742
|
+
domain: "git",
|
|
237743
|
+
mutationType: "task:review-input-recaptured",
|
|
237744
|
+
target: task.id,
|
|
237745
|
+
metadata: {
|
|
237746
|
+
taskId: task.id,
|
|
237747
|
+
workflowStepId: workflowStep.id,
|
|
237748
|
+
verdict: effectiveVerdict,
|
|
237749
|
+
resolvedInReviewFindingCount,
|
|
237750
|
+
reason: finalDecision.reason
|
|
237751
|
+
}
|
|
237752
|
+
});
|
|
237753
|
+
}
|
|
237754
|
+
} catch {
|
|
237755
|
+
}
|
|
237756
|
+
}
|
|
237757
|
+
}
|
|
237252
237758
|
if (workflowStep.requiresBrowser === true) {
|
|
237253
237759
|
await logBrowserVerificationActivity(`[browser-verification] finished browser verification for task ${task.id}: verdict ${effectiveVerdict}`);
|
|
237254
237760
|
}
|
|
@@ -237953,10 +238459,10 @@ init_branch_conflicts();
|
|
|
237953
238459
|
init_integration_branch();
|
|
237954
238460
|
init_logger();
|
|
237955
238461
|
import { exec as exec42 } from "node:child_process";
|
|
237956
|
-
import { promisify as
|
|
238462
|
+
import { promisify as promisify60 } from "node:util";
|
|
237957
238463
|
import { existsSync as existsSync66 } from "node:fs";
|
|
237958
238464
|
import { rm as rm11 } from "node:fs/promises";
|
|
237959
|
-
var execAsync39 =
|
|
238465
|
+
var execAsync39 = promisify60(exec42);
|
|
237960
238466
|
async function tryCreateWorktree(deps, branch, path6, taskId, startPoint, attemptNumber = 0, recoveryDepth = 0, allowSiblingBranchRename = false, settings = {}) {
|
|
237961
238467
|
await assertWorktreePathNotNested(deps.rootDir, deps.store, path6, taskId);
|
|
237962
238468
|
const installGuardOrCleanup = async () => {
|
|
@@ -238244,10 +238750,10 @@ init_src2();
|
|
|
238244
238750
|
init_worktree_pool();
|
|
238245
238751
|
init_logger();
|
|
238246
238752
|
import { exec as exec43 } from "node:child_process";
|
|
238247
|
-
import { promisify as
|
|
238753
|
+
import { promisify as promisify61 } from "node:util";
|
|
238248
238754
|
import { existsSync as existsSync67, lstatSync as lstatSync3, realpathSync as realpathSync11 } from "node:fs";
|
|
238249
238755
|
import { rm as rm12 } from "node:fs/promises";
|
|
238250
|
-
var execAsync40 =
|
|
238756
|
+
var execAsync40 = promisify61(exec43);
|
|
238251
238757
|
async function cleanupConflictingWorktree(deps, worktreePath, branch, taskId) {
|
|
238252
238758
|
await deps.reconcileSelfOwnedBeforeRemove(worktreePath, taskId);
|
|
238253
238759
|
const activeOwner = await deps.findActiveWorktreeOwner(worktreePath, taskId);
|
|
@@ -238364,10 +238870,10 @@ init_worktree_stale_lock();
|
|
|
238364
238870
|
init_integration_branch();
|
|
238365
238871
|
init_logger();
|
|
238366
238872
|
import { exec as exec44 } from "node:child_process";
|
|
238367
|
-
import { promisify as
|
|
238873
|
+
import { promisify as promisify62 } from "node:util";
|
|
238368
238874
|
import { existsSync as existsSync68 } from "node:fs";
|
|
238369
238875
|
import { isAbsolute as isAbsolute22 } from "node:path";
|
|
238370
|
-
var execAsync41 =
|
|
238876
|
+
var execAsync41 = promisify62(exec44);
|
|
238371
238877
|
async function resolveWorktreeStartPoint(rootDir, store, startPoint, taskId) {
|
|
238372
238878
|
const command = isAbsolute22(startPoint) && existsSync68(startPoint) ? `git -C "${startPoint}" rev-parse --verify HEAD^{commit}` : `git rev-parse --verify "${startPoint}^{commit}"`;
|
|
238373
238879
|
try {
|
|
@@ -238569,8 +239075,8 @@ init_effective_settings();
|
|
|
238569
239075
|
init_worktree_pinning();
|
|
238570
239076
|
init_logger();
|
|
238571
239077
|
import { exec as exec45 } from "node:child_process";
|
|
238572
|
-
import { promisify as
|
|
238573
|
-
var execAsync42 =
|
|
239078
|
+
import { promisify as promisify63 } from "node:util";
|
|
239079
|
+
var execAsync42 = promisify63(exec45);
|
|
238574
239080
|
async function reclaimExistingWorktree(deps, task, livePath, branch, tipSha, count2, settings) {
|
|
238575
239081
|
const targetPath = preservedWorktreeTargetPathForTask(task.id, livePath, settings, deps.rootDir);
|
|
238576
239082
|
const normalizedPath = await deps.normalizeReclaimableWorktreePath(livePath, targetPath, task.id, settings);
|
|
@@ -238803,7 +239309,7 @@ init_worktree_names();
|
|
|
238803
239309
|
init_logger();
|
|
238804
239310
|
init_run_audit();
|
|
238805
239311
|
import { exec as exec47 } from "node:child_process";
|
|
238806
|
-
import { promisify as
|
|
239312
|
+
import { promisify as promisify66 } from "node:util";
|
|
238807
239313
|
import { existsSync as existsSync71 } from "node:fs";
|
|
238808
239314
|
|
|
238809
239315
|
// ../engine/src/executor/session-worktree-paths.ts
|
|
@@ -238931,11 +239437,11 @@ function classifyWorkspaceZeroAcquire(task, options) {
|
|
|
238931
239437
|
}
|
|
238932
239438
|
|
|
238933
239439
|
// ../engine/src/execution/external-execution-checkout.ts
|
|
238934
|
-
import { execFile as
|
|
239440
|
+
import { execFile as execFile30 } from "node:child_process";
|
|
238935
239441
|
import { existsSync as existsSync69, realpathSync as realpathSync13, statSync as statSync14 } from "node:fs";
|
|
238936
239442
|
import { isAbsolute as isAbsolute23 } from "node:path";
|
|
238937
|
-
import { promisify as
|
|
238938
|
-
var
|
|
239443
|
+
import { promisify as promisify64 } from "node:util";
|
|
239444
|
+
var execFileAsync24 = promisify64(execFile30);
|
|
238939
239445
|
function readSourceMetadata(task) {
|
|
238940
239446
|
if (!task || typeof task !== "object") return void 0;
|
|
238941
239447
|
const sourceMetadata = task.sourceMetadata;
|
|
@@ -238954,7 +239460,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
|
|
|
238954
239460
|
return { valid: false, reason: `checkoutPath is not a directory: ${checkoutPath}` };
|
|
238955
239461
|
}
|
|
238956
239462
|
const canonicalCheckout = realpathSync13(checkoutPath);
|
|
238957
|
-
const { stdout: topLevelOutput } = await
|
|
239463
|
+
const { stdout: topLevelOutput } = await execFileAsync24("git", ["rev-parse", "--show-toplevel"], {
|
|
238958
239464
|
cwd: canonicalCheckout,
|
|
238959
239465
|
encoding: "utf-8",
|
|
238960
239466
|
timeout: 1e4
|
|
@@ -238967,7 +239473,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
|
|
|
238967
239473
|
reason: `checkoutPath must be the Git top-level (observed ${canonicalTopLevel})`
|
|
238968
239474
|
};
|
|
238969
239475
|
}
|
|
238970
|
-
const { stdout: branchOutput } = await
|
|
239476
|
+
const { stdout: branchOutput } = await execFileAsync24("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
238971
239477
|
cwd: canonicalCheckout,
|
|
238972
239478
|
encoding: "utf-8",
|
|
238973
239479
|
timeout: 1e4
|
|
@@ -238977,7 +239483,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
|
|
|
238977
239483
|
return { valid: false, reason: "checkoutPath must have a checked-out branch" };
|
|
238978
239484
|
}
|
|
238979
239485
|
if (options.requireClean) {
|
|
238980
|
-
const { stdout: statusOutput } = await
|
|
239486
|
+
const { stdout: statusOutput } = await execFileAsync24("git", ["status", "--porcelain=v1"], {
|
|
238981
239487
|
cwd: canonicalCheckout,
|
|
238982
239488
|
encoding: "utf-8",
|
|
238983
239489
|
timeout: 1e4
|
|
@@ -239040,9 +239546,9 @@ async function resolveAuthoritativeExternalExecutionRoute(store, task) {
|
|
|
239040
239546
|
import { exec as exec46 } from "node:child_process";
|
|
239041
239547
|
import { existsSync as existsSync70, promises as fs7 } from "node:fs";
|
|
239042
239548
|
import path4 from "node:path";
|
|
239043
|
-
import { promisify as
|
|
239549
|
+
import { promisify as promisify65 } from "node:util";
|
|
239044
239550
|
init_worktree_paths();
|
|
239045
|
-
var execAsync43 =
|
|
239551
|
+
var execAsync43 = promisify65(exec46);
|
|
239046
239552
|
var probeOptions = { encoding: "utf-8", timeout: 1e4, maxBuffer: 1024 * 1024 };
|
|
239047
239553
|
function workspaceExecutionAnchor(task) {
|
|
239048
239554
|
const executionValues = [task.firstExecutionAt, task.executionStartedAt].map((value) => typeof value === "string" ? Date.parse(value) : Number.NaN).filter(Number.isFinite);
|
|
@@ -239162,7 +239668,7 @@ async function detectWorkspaceMainCheckoutWork(deps, task, repos, declaredScope)
|
|
|
239162
239668
|
}
|
|
239163
239669
|
|
|
239164
239670
|
// ../engine/src/executor/worktree-verify-invariants.ts
|
|
239165
|
-
var execAsync44 =
|
|
239671
|
+
var execAsync44 = promisify66(exec47);
|
|
239166
239672
|
async function verifyWorktreeInvariants(deps, task, worktreePathOverride, allowReanchor = true, options) {
|
|
239167
239673
|
const workspaceConfig = deps.ensureWorkspaceConfig ? await deps.ensureWorkspaceConfig() : deps.workspaceConfig;
|
|
239168
239674
|
const settings = await deps.store.getSettings();
|
|
@@ -239567,14 +240073,14 @@ async function emitWorktreeReanchoredAudit(deps, taskId, fromPath, toPath, sourc
|
|
|
239567
240073
|
}
|
|
239568
240074
|
|
|
239569
240075
|
// ../engine/src/executor/worktree-task-done-scope-leak.ts
|
|
239570
|
-
import { execFile as
|
|
240076
|
+
import { execFile as execFile31 } from "node:child_process";
|
|
239571
240077
|
import { access as access9 } from "node:fs/promises";
|
|
239572
|
-
import { promisify as
|
|
240078
|
+
import { promisify as promisify67 } from "node:util";
|
|
239573
240079
|
init_logger();
|
|
239574
|
-
var
|
|
240080
|
+
var execFileAsync25 = promisify67(execFile31);
|
|
239575
240081
|
async function verifyRepositoryCaptureEvidence(worktreePath) {
|
|
239576
240082
|
await access9(worktreePath);
|
|
239577
|
-
const { stdout } = await
|
|
240083
|
+
const { stdout } = await execFileAsync25("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
239578
240084
|
cwd: worktreePath,
|
|
239579
240085
|
encoding: "utf8"
|
|
239580
240086
|
});
|
|
@@ -239591,7 +240097,7 @@ async function captureRepositoryChangeEvidence(worktreePath, baseCommitSha) {
|
|
|
239591
240097
|
} else {
|
|
239592
240098
|
commands.push(["rev-parse", "--verify", "HEAD"]);
|
|
239593
240099
|
}
|
|
239594
|
-
const results = await Promise.all(commands.map((args) =>
|
|
240100
|
+
const results = await Promise.all(commands.map((args) => execFileAsync25("git", args, {
|
|
239595
240101
|
cwd: worktreePath,
|
|
239596
240102
|
encoding: "utf8"
|
|
239597
240103
|
})));
|
|
@@ -239725,8 +240231,8 @@ async function evaluateTaskDoneScopeLeak(deps, task, worktreePath, promptContent
|
|
|
239725
240231
|
init_branch_attribution();
|
|
239726
240232
|
init_logger();
|
|
239727
240233
|
import { exec as exec48 } from "node:child_process";
|
|
239728
|
-
import { promisify as
|
|
239729
|
-
var execAsync45 =
|
|
240234
|
+
import { promisify as promisify68 } from "node:util";
|
|
240235
|
+
var execAsync45 = promisify68(exec48);
|
|
239730
240236
|
async function captureModifiedFiles(worktreePath, baseCommitSha, taskId, audit, source = "unspecified") {
|
|
239731
240237
|
try {
|
|
239732
240238
|
const baseRef = await resolveDiffBaseRef(worktreePath, baseCommitSha);
|
|
@@ -240024,6 +240530,27 @@ ${result.review}`);
|
|
|
240024
240530
|
summarySections.push(`[${repoRel}] ${result.verdict}: ${result.summary}`);
|
|
240025
240531
|
}
|
|
240026
240532
|
const aggregateVerdict = reviewedResults.some(({ result }) => result.verdict === "RETHINK") ? "RETHINK" : reviewedResults.some(({ result }) => result.verdict === "REVISE") ? "REVISE" : reviewedResults.some(({ result }) => !isApprovalFamilyVerdict(result.verdict)) ? "UNAVAILABLE" : "APPROVE";
|
|
240533
|
+
let publishedModifiedFiles = modifiedFiles;
|
|
240534
|
+
if (isApprovalFamilyVerdict(aggregateVerdict) && evidence && options.workspaceRootDir) {
|
|
240535
|
+
try {
|
|
240536
|
+
const refreshed = await captureWorkspaceReviewEvidence({ task, workspaceRootDir: options.workspaceRootDir, settings: options.settings ?? {} });
|
|
240537
|
+
if (refreshed.outOfScopeRepositories.size > 0) {
|
|
240538
|
+
return { verdict: "UNAVAILABLE", retryable: false, review: "Workspace Code Review cannot approve changes outside confirmed scope after review.", summary: "Unavailable: changes outside confirmed scope after review", repositoryScopeRevision };
|
|
240539
|
+
}
|
|
240540
|
+
for (const updated of refreshed.repositories) {
|
|
240541
|
+
const original = evidence.repositories.find((candidate) => candidate.repository === updated.repository);
|
|
240542
|
+
const worktreePath = workspaceWorktrees[updated.repository]?.worktreePath;
|
|
240543
|
+
const outcome = repositoryReviewOutcomes.find((candidate) => candidate.repository === updated.repository && candidate.status === "REVIEWED");
|
|
240544
|
+
if (!original || !worktreePath || !updated.fingerprint || !outcome || !repositoryScope.has(updated.repository)) continue;
|
|
240545
|
+
if (await isFastForwardAdvance(worktreePath, original.branch, updated.branch)) {
|
|
240546
|
+
repositoryDiffFingerprints[updated.repository] = updated.fingerprint;
|
|
240547
|
+
outcome.fingerprint = updated.fingerprint;
|
|
240548
|
+
}
|
|
240549
|
+
}
|
|
240550
|
+
publishedModifiedFiles = refreshed.modifiedFiles;
|
|
240551
|
+
} catch {
|
|
240552
|
+
}
|
|
240553
|
+
}
|
|
240027
240554
|
const blockingRepositories = reviewedResults.filter(({ result }) => !isApprovalFamilyVerdict(result.verdict)).map(({ repository }) => repository);
|
|
240028
240555
|
const blockingSummary = blockingRepositories.length > 0 ? `blocking repositories: ${blockingRepositories.join(", ")}` : `all ${repoKeys.length} modified in-scope repositories approved`;
|
|
240029
240556
|
const coverageNotice = noVerdictRepositories.length > 0 ? `
|
|
@@ -240035,7 +240562,7 @@ Not covered by a verdict: ${noVerdictRepositories.join(", ")}.` : "";
|
|
|
240035
240562
|
${reviewSections.join("\n\n")}`,
|
|
240036
240563
|
summary: `${aggregateVerdict} \u2014 ${blockingSummary} \u2014 ${summarySections.join(" | ")}`,
|
|
240037
240564
|
repositoryDiffFingerprints,
|
|
240038
|
-
repositoryModifiedFiles:
|
|
240565
|
+
repositoryModifiedFiles: publishedModifiedFiles,
|
|
240039
240566
|
repositoryReviewOutcomes,
|
|
240040
240567
|
...findings.length > 0 ? { findings } : {},
|
|
240041
240568
|
repositoryScopeRevision
|
|
@@ -240357,9 +240884,9 @@ init_worktree_names();
|
|
|
240357
240884
|
init_worktree_pool();
|
|
240358
240885
|
init_logger();
|
|
240359
240886
|
import { exec as exec49 } from "node:child_process";
|
|
240360
|
-
import { promisify as
|
|
240887
|
+
import { promisify as promisify69 } from "node:util";
|
|
240361
240888
|
init_lifecycle_columns();
|
|
240362
|
-
var execAsync46 =
|
|
240889
|
+
var execAsync46 = promisify69(exec49);
|
|
240363
240890
|
async function handleDepAbortCleanup(deps, taskId, worktreePath) {
|
|
240364
240891
|
executorLog.log(`${taskId} dependency added \u2014 work discarded, moved to triage for re-planning`);
|
|
240365
240892
|
const task = await deps.store.getTask(taskId);
|
|
@@ -240935,8 +241462,8 @@ async function advanceNoMergeWorkflowToCompleteColumn(store, task) {
|
|
|
240935
241462
|
init_logger();
|
|
240936
241463
|
import { exec as exec50 } from "node:child_process";
|
|
240937
241464
|
import { existsSync as existsSync73, statSync as statSync15 } from "node:fs";
|
|
240938
|
-
import { promisify as
|
|
240939
|
-
var execAsync47 =
|
|
241465
|
+
import { promisify as promisify70 } from "node:util";
|
|
241466
|
+
var execAsync47 = promisify70(exec50);
|
|
240940
241467
|
async function runTaskStep(deps, task, stepIndex, opts = {}) {
|
|
240941
241468
|
const { store, worktreePath } = deps;
|
|
240942
241469
|
const gitRevParse = deps.gitRevParse ?? defaultGitRevParse;
|
|
@@ -243022,8 +243549,8 @@ async function recoverFailedPreMergeWorkflowStep(deps, task) {
|
|
|
243022
243549
|
init_src2();
|
|
243023
243550
|
init_logger();
|
|
243024
243551
|
import { exec as exec51 } from "node:child_process";
|
|
243025
|
-
import { promisify as
|
|
243026
|
-
var execAsync48 =
|
|
243552
|
+
import { promisify as promisify71 } from "node:util";
|
|
243553
|
+
var execAsync48 = promisify71(exec51);
|
|
243027
243554
|
async function reconcileStepsFromGitHistory(deps, taskId, detail, worktreePath) {
|
|
243028
243555
|
const baseCommitSha = detail.baseCommitSha;
|
|
243029
243556
|
if (!baseCommitSha) return;
|
|
@@ -245347,7 +245874,14 @@ async function persistWorkflowStepResultWithOutcome(deps, taskId, result, fence
|
|
|
245347
245874
|
scopeSuperseded = true;
|
|
245348
245875
|
return null;
|
|
245349
245876
|
}
|
|
245350
|
-
const
|
|
245877
|
+
const unprovenApproval = resolveUnprovenReviewApproval(result, {
|
|
245878
|
+
workspace: current.workspaceWorktrees !== void 0
|
|
245879
|
+
});
|
|
245880
|
+
const built = buildWorkflowStepResultPatch(
|
|
245881
|
+
current,
|
|
245882
|
+
unprovenApproval?.downgraded ?? result,
|
|
245883
|
+
isPlanReviewResult
|
|
245884
|
+
);
|
|
245351
245885
|
activityResult = built.resultToPersist;
|
|
245352
245886
|
activityResults = built.results;
|
|
245353
245887
|
return built.patch;
|
|
@@ -245384,21 +245918,30 @@ async function persistWorkflowStepResultWithOutcome(deps, taskId, result, fence
|
|
|
245384
245918
|
if (scopeSuperseded) return { scopeCurrent: false, persisted: false };
|
|
245385
245919
|
if (fenceRefused) return { scopeCurrent: true, persisted: false };
|
|
245386
245920
|
const persistedResult = activityResults?.find((entry) => entry.workflowStepId === result.workflowStepId) ?? activityResult;
|
|
245387
|
-
|
|
245388
|
-
|
|
245921
|
+
const approvalDowngraded = result.status === "passed" && persistedResult.status === "failed" && result.reviewInputFingerprint === void 0 && persistedResult.verdict === void 0;
|
|
245922
|
+
if (approvalDowngraded) {
|
|
245923
|
+
await deps.store.logEntry(
|
|
245924
|
+
taskId,
|
|
245925
|
+
`[pre-merge] ${result.workflowStepName} approval invalidated: ${persistedResult.notes ?? persistedResult.output ?? "review input proof missing"}`,
|
|
245926
|
+
void 0,
|
|
245927
|
+
deps.getRunContextFor(taskId)
|
|
245928
|
+
).catch(() => void 0);
|
|
245929
|
+
}
|
|
245930
|
+
if (isTerminalStepResult(persistedResult)) {
|
|
245931
|
+
const passed = persistedResult.status === "passed" || persistedResult.status === "skipped" || persistedResult.verdict === "APPROVE" || persistedResult.verdict === "APPROVE_WITH_NOTES" || persistedResult.verdict === "CLOSE_NO_OP";
|
|
245389
245932
|
try {
|
|
245390
245933
|
await deps.store.recordAgentActivity({
|
|
245391
245934
|
type: passed ? "workflow:gate-passed" : "workflow:gate-failed",
|
|
245392
245935
|
attributionClaim: resolveWorkflowGateActivityClaim(
|
|
245393
|
-
deps.workflowGateActivityPrincipals?.get(`${taskId}\0${
|
|
245936
|
+
deps.workflowGateActivityPrincipals?.get(`${taskId}\0${persistedResult.workflowStepId}`) ?? deps.activeWorkflowPrincipals?.get(taskId)?.agentId,
|
|
245394
245937
|
live?.assignedAgentId
|
|
245395
245938
|
),
|
|
245396
245939
|
taskId,
|
|
245397
|
-
occurredAt:
|
|
245398
|
-
discriminator: `${
|
|
245399
|
-
metadata: buildWorkflowGateActivityMetadata(
|
|
245940
|
+
occurredAt: persistedResult.completedAt ?? persistedResult.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
245941
|
+
discriminator: `${persistedResult.workflowStepId}:${persistedResult.startedAt ?? persistedResult.completedAt ?? persistedResult.status}`,
|
|
245942
|
+
metadata: buildWorkflowGateActivityMetadata(persistedResult, persistedResult)
|
|
245400
245943
|
});
|
|
245401
|
-
deps.workflowGateActivityPrincipals?.delete(`${taskId}\0${
|
|
245944
|
+
deps.workflowGateActivityPrincipals?.delete(`${taskId}\0${persistedResult.workflowStepId}`);
|
|
245402
245945
|
} catch (error2) {
|
|
245403
245946
|
executorLog.warn(`[agent-activity] ${taskId}: failed to record workflow gate activity: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
245404
245947
|
}
|
|
@@ -247323,8 +247866,8 @@ async function runSpawnedChild(deps, agentId, childSession, taskPrompt) {
|
|
|
247323
247866
|
|
|
247324
247867
|
// ../engine/src/auto-recovery-handlers/file-scope.ts
|
|
247325
247868
|
import { exec as exec52 } from "node:child_process";
|
|
247326
|
-
import { promisify as
|
|
247327
|
-
var execAsync49 =
|
|
247869
|
+
import { promisify as promisify72 } from "node:util";
|
|
247870
|
+
var execAsync49 = promisify72(exec52);
|
|
247328
247871
|
var FileScopeAutoRecoveryHandler = class {
|
|
247329
247872
|
constructor(deps) {
|
|
247330
247873
|
this.deps = deps;
|
|
@@ -247349,8 +247892,8 @@ init_integration_branch();
|
|
|
247349
247892
|
init_logger();
|
|
247350
247893
|
import { exec as exec53 } from "node:child_process";
|
|
247351
247894
|
import { existsSync as existsSync76 } from "node:fs";
|
|
247352
|
-
import { promisify as
|
|
247353
|
-
var execAsync50 =
|
|
247895
|
+
import { promisify as promisify73 } from "node:util";
|
|
247896
|
+
var execAsync50 = promisify73(exec53);
|
|
247354
247897
|
var baseLog2 = createLogger("auto-recovery:branch-worktree");
|
|
247355
247898
|
var GIT_TIMEOUT_MS8 = 3e4;
|
|
247356
247899
|
var GIT_MAX_BUFFER6 = 10 * 1024 * 1024;
|
|
@@ -248340,8 +248883,8 @@ init_src2();
|
|
|
248340
248883
|
init_worktree_names();
|
|
248341
248884
|
init_logger();
|
|
248342
248885
|
import { exec as exec54 } from "node:child_process";
|
|
248343
|
-
import { promisify as
|
|
248344
|
-
var execAsync51 =
|
|
248886
|
+
import { promisify as promisify74 } from "node:util";
|
|
248887
|
+
var execAsync51 = promisify74(exec54);
|
|
248345
248888
|
async function resetStepsIfWorkLost(deps, task) {
|
|
248346
248889
|
const completedSteps = task.steps.filter(
|
|
248347
248890
|
(s3) => s3.status === "done" || s3.status === "in-progress"
|
|
@@ -248416,8 +248959,8 @@ init_worktree_names();
|
|
|
248416
248959
|
init_worktree_paths();
|
|
248417
248960
|
init_logger();
|
|
248418
248961
|
import { exec as exec55 } from "node:child_process";
|
|
248419
|
-
import { promisify as
|
|
248420
|
-
var execAsync52 =
|
|
248962
|
+
import { promisify as promisify75 } from "node:util";
|
|
248963
|
+
var execAsync52 = promisify75(exec55);
|
|
248421
248964
|
var WORKSPACE_ISOLATION_UNSUPPORTED_MESSAGE = "per-instance worktree isolation is not supported for workspace projects";
|
|
248422
248965
|
function buildForeachWorktreeDeps(deps, task, runId) {
|
|
248423
248966
|
const taskId = task.id;
|
|
@@ -248610,7 +249153,7 @@ init_src2();
|
|
|
248610
249153
|
// ../engine/src/executor/derive-remediation-steps.ts
|
|
248611
249154
|
init_src2();
|
|
248612
249155
|
init_merger_file_scope();
|
|
248613
|
-
import { createHash as
|
|
249156
|
+
import { createHash as createHash35 } from "node:crypto";
|
|
248614
249157
|
var fileReference = /(?:^|[\s(])([\w@./-]+\.(?:[cm]?[jt]sx?|json|md|css|html|yml|yaml))(?::(\d+))?/gm;
|
|
248615
249158
|
var ansiEscapeSequence = /\u001B\[[0-?]*[ -/]*[@-~]/g;
|
|
248616
249159
|
var isoTimestamp = /\b\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?\b/g;
|
|
@@ -248623,7 +249166,7 @@ function normalizeVerificationEvidence(output) {
|
|
|
248623
249166
|
}
|
|
248624
249167
|
function verificationEvidenceDigest(output) {
|
|
248625
249168
|
const evidence = normalizeVerificationEvidence(output);
|
|
248626
|
-
return evidence ?
|
|
249169
|
+
return evidence ? createHash35("sha256").update(evidence).digest("hex").slice(0, 16) : void 0;
|
|
248627
249170
|
}
|
|
248628
249171
|
function verificationCandidates(input) {
|
|
248629
249172
|
const detail = input.verificationCommandLabel ?? "verification command";
|
|
@@ -252011,6 +252554,8 @@ async function runGraphCustomNode(deps, node, nodeTask, settings, columnBinding,
|
|
|
252011
252554
|
}
|
|
252012
252555
|
const optionalGroupId = typeof graphContext?.[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] === "string" ? graphContext[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] : void 0;
|
|
252013
252556
|
const declaredReviewKind = cfg.reviewKind === "plan" || cfg.reviewKind === "code" ? cfg.reviewKind : graphContext?.[WORKFLOW_REVIEW_KIND_CONTEXT_KEY] === "plan" || graphContext?.[WORKFLOW_REVIEW_KIND_CONTEXT_KEY] === "code" ? graphContext[WORKFLOW_REVIEW_KIND_CONTEXT_KEY] : void 0;
|
|
252557
|
+
const effectiveStepId = optionalGroupId ?? node.id;
|
|
252558
|
+
const isContentBindingStep = requiresContentReviewProof(effectiveStepId, { reviewKind: declaredReviewKind });
|
|
252014
252559
|
if (isFastExecutionMode(live) && graphContext?.["workflow:fast-lane-active"] === true && isFastLaneSkippableCustomNode(node, { optionalGroupId })) {
|
|
252015
252560
|
executorLog.debug(`${live.id}: fast mode \u2014 skipping custom graph node '${node.id}'`);
|
|
252016
252561
|
await deps.store.logEntry(
|
|
@@ -252205,6 +252750,7 @@ ${prompt}`;
|
|
|
252205
252750
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
252206
252751
|
const stepSkillName = executorKind === "skill" && typeof cfg.skillName === "string" && cfg.skillName.trim() ? cfg.skillName.trim() : void 0;
|
|
252207
252752
|
const stepThinkingLevel = typeof cfg.thinkingLevel === "string" && WORKFLOW_THINKING_LEVEL_SET2.has(cfg.thinkingLevel) ? cfg.thinkingLevel : void 0;
|
|
252753
|
+
const readonlyMcpServers = Array.isArray(cfg.readonlyMcpServers) ? [...new Set(cfg.readonlyMcpServers.filter((name2) => typeof name2 === "string").map((name2) => name2.trim()).filter(Boolean))] : [];
|
|
252208
252754
|
const step = {
|
|
252209
252755
|
id: `graph:${node.id}`,
|
|
252210
252756
|
name: typeof cfg.name === "string" && cfg.name.trim() ? cfg.name : node.id,
|
|
@@ -252221,7 +252767,8 @@ ${prompt}`;
|
|
|
252221
252767
|
...stepSkillName ? { skillName: stepSkillName } : {},
|
|
252222
252768
|
...cfg.requiresBrowser === true ? { requiresBrowser: true } : {},
|
|
252223
252769
|
...modelProvider && modelId ? { modelProvider, modelId } : {},
|
|
252224
|
-
...stepThinkingLevel ? { thinkingLevel: stepThinkingLevel } : {}
|
|
252770
|
+
...stepThinkingLevel ? { thinkingLevel: stepThinkingLevel } : {},
|
|
252771
|
+
...readonlyMcpServers.length > 0 ? { readonlyMcpServers } : {}
|
|
252225
252772
|
};
|
|
252226
252773
|
if (cfg.summaryTarget === "task") {
|
|
252227
252774
|
step.summaryTarget = "task";
|
|
@@ -252335,12 +252882,36 @@ ${prompt}`;
|
|
|
252335
252882
|
outcome = buildWorkspaceReviewOutcome(aggregate, { superseded: reviewSuperseded });
|
|
252336
252883
|
}
|
|
252337
252884
|
} else {
|
|
252338
|
-
|
|
252339
|
-
|
|
252340
|
-
|
|
252341
|
-
|
|
252342
|
-
|
|
252343
|
-
|
|
252885
|
+
const dispatchSingularStep = async (reviewInputFingerprint) => {
|
|
252886
|
+
if (mode === "script") {
|
|
252887
|
+
const scriptOutcome = await deps.executeScriptWorkflowStep(live, step, worktreePath, settings, nodeEnv);
|
|
252888
|
+
return reviewInputFingerprint === void 0 ? scriptOutcome : { ...scriptOutcome, reviewInputFingerprint };
|
|
252889
|
+
}
|
|
252890
|
+
return deps.executeWorkflowStep(live, step, worktreePath, settings, nodeEnv, {
|
|
252891
|
+
unattended,
|
|
252892
|
+
principalAgentId,
|
|
252893
|
+
outputLanguage,
|
|
252894
|
+
...nodeSessionBoundary ? { sessionBoundary: nodeSessionBoundary } : {},
|
|
252895
|
+
...reviewInputFingerprint !== void 0 ? { reviewInputFingerprint } : {}
|
|
252896
|
+
});
|
|
252897
|
+
};
|
|
252898
|
+
if (isContentBindingStep && !workspaceConfig) {
|
|
252899
|
+
const proof = await resolveContentReviewInputProof(worktreePath, executionTarget.baseCommitSha);
|
|
252900
|
+
if (proof.kind === "unprovable") {
|
|
252901
|
+
const diagnostic = `${step.name} review input is unprovable (${proof.reason}); reviewer dispatch refused.`;
|
|
252902
|
+
await deps.store.logEntry(
|
|
252903
|
+
live.id,
|
|
252904
|
+
`[pre-merge] ${diagnostic}`,
|
|
252905
|
+
void 0,
|
|
252906
|
+
deps.getRunContextFor(live.id)
|
|
252907
|
+
);
|
|
252908
|
+
outcome = { success: false, error: diagnostic, failureValue: "review-input-unprovable" };
|
|
252909
|
+
} else {
|
|
252910
|
+
outcome = await dispatchSingularStep(proof.fingerprint);
|
|
252911
|
+
}
|
|
252912
|
+
} else {
|
|
252913
|
+
outcome = await dispatchSingularStep();
|
|
252914
|
+
}
|
|
252344
252915
|
}
|
|
252345
252916
|
if (declaredReviewKind && typeof outcome.output === "string") {
|
|
252346
252917
|
const rawReviewOutput = outcome.output;
|
|
@@ -253328,7 +253899,7 @@ async function runImplementationPhase(deps, task, prepared) {
|
|
|
253328
253899
|
// ../engine/src/executor/run-implementation.ts
|
|
253329
253900
|
init_src2();
|
|
253330
253901
|
import { exec as exec56 } from "node:child_process";
|
|
253331
|
-
import { promisify as
|
|
253902
|
+
import { promisify as promisify77 } from "node:util";
|
|
253332
253903
|
import { existsSync as existsSync80 } from "node:fs";
|
|
253333
253904
|
import { join as join91 } from "node:path";
|
|
253334
253905
|
import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
|
|
@@ -254203,11 +254774,11 @@ init_logger();
|
|
|
254203
254774
|
// ../engine/src/merge/merger-orphan-rehome.ts
|
|
254204
254775
|
init_src2();
|
|
254205
254776
|
init_merger_ref_update_advance();
|
|
254206
|
-
import { execFile as
|
|
254207
|
-
import { promisify as
|
|
254208
|
-
var
|
|
254777
|
+
import { execFile as execFile32 } from "node:child_process";
|
|
254778
|
+
import { promisify as promisify76 } from "node:util";
|
|
254779
|
+
var execFileAsync26 = promisify76(execFile32);
|
|
254209
254780
|
async function runGit5(args, cwd) {
|
|
254210
|
-
const { stdout } = await
|
|
254781
|
+
const { stdout } = await execFileAsync26("git", args, {
|
|
254211
254782
|
cwd,
|
|
254212
254783
|
encoding: "utf-8",
|
|
254213
254784
|
timeout: 3e4
|
|
@@ -254216,7 +254787,7 @@ async function runGit5(args, cwd) {
|
|
|
254216
254787
|
}
|
|
254217
254788
|
async function isAncestor3(repoDir, ancestor, descendant) {
|
|
254218
254789
|
try {
|
|
254219
|
-
await
|
|
254790
|
+
await execFileAsync26(
|
|
254220
254791
|
"git",
|
|
254221
254792
|
["merge-base", "--is-ancestor", ancestor, descendant],
|
|
254222
254793
|
{ cwd: repoDir, encoding: "utf-8", timeout: 3e4 }
|
|
@@ -254320,7 +254891,7 @@ init_run_audit();
|
|
|
254320
254891
|
init_worktree_acquisition();
|
|
254321
254892
|
init_worktree_paths();
|
|
254322
254893
|
init_worktree_pool();
|
|
254323
|
-
var execAsync53 =
|
|
254894
|
+
var execAsync53 = promisify77(exec56);
|
|
254324
254895
|
var MAX_TASK_DONE_SESSION_RETRIES = 3;
|
|
254325
254896
|
async function parkExternalSessionObstacle(deps, taskId, errorMessage) {
|
|
254326
254897
|
const obstacle = classifyExternalObstacle(errorMessage);
|
|
@@ -260093,8 +260664,8 @@ init_active_session_registry();
|
|
|
260093
260664
|
init_agent_session_helpers();
|
|
260094
260665
|
init_logger();
|
|
260095
260666
|
init_effective_settings();
|
|
260096
|
-
import { execFile as
|
|
260097
|
-
import { promisify as
|
|
260667
|
+
import { execFile as execFile33 } from "node:child_process";
|
|
260668
|
+
import { promisify as promisify78 } from "node:util";
|
|
260098
260669
|
|
|
260099
260670
|
// ../engine/src/agents/workflow-agent-capacity.ts
|
|
260100
260671
|
var WorkflowAgentCapacity = class _WorkflowAgentCapacity {
|
|
@@ -260171,7 +260742,7 @@ var WorkflowAgentCapacity = class _WorkflowAgentCapacity {
|
|
|
260171
260742
|
};
|
|
260172
260743
|
|
|
260173
260744
|
// ../engine/src/executor/wire-executor-lifecycle.ts
|
|
260174
|
-
var
|
|
260745
|
+
var execFileAsync27 = promisify78(execFile33);
|
|
260175
260746
|
async function releaseWorkspaceAcquireClaims(store, taskId) {
|
|
260176
260747
|
for (const entry of activeSessionRegistry.entriesByKind("workspace-repo-acquire")) {
|
|
260177
260748
|
if (entry.taskId === taskId) activeSessionRegistry.unregisterPath(entry.path);
|
|
@@ -260263,7 +260834,7 @@ function wireExecutorLifecycle(deps) {
|
|
|
260263
260834
|
if (await canonicalizeWorktreePath(entry.worktreePath) === await canonicalizeWorktreePath(entry.repoRootDir)) throw new Error("Refusing to remove workspace repository root");
|
|
260264
260835
|
activeSessionRegistry.unregisterPath(entry.worktreePath);
|
|
260265
260836
|
await removeWorktree({ worktreePath: entry.worktreePath, rootDir: entry.repoRootDir, settings: await deps.store.getSettings(), taskId: task.id, reason: RemovalReason.ExecutorDispose, force: true });
|
|
260266
|
-
await
|
|
260837
|
+
await execFileAsync27("git", ["branch", "-D", entry.branch], { cwd: entry.repoRootDir, timeout: 12e4, maxBuffer: 10 * 1024 * 1024 });
|
|
260267
260838
|
if (task.workspaceWorktrees) for (const repoRel of [entry.repoRel, ...entry.aliasRepoRels]) delete task.workspaceWorktrees[repoRel];
|
|
260268
260839
|
removed.push(entry.repoRel);
|
|
260269
260840
|
} catch (error2) {
|
|
@@ -262939,9 +263510,9 @@ var BUNDLED_CLI_ADAPTERS = Object.freeze([
|
|
|
262939
263510
|
|
|
262940
263511
|
// ../engine/src/cli-agent/resume-coordinator.ts
|
|
262941
263512
|
import { existsSync as existsSync83 } from "node:fs";
|
|
262942
|
-
import { execFile as
|
|
262943
|
-
import { promisify as
|
|
262944
|
-
var
|
|
263513
|
+
import { execFile as execFile34 } from "node:child_process";
|
|
263514
|
+
import { promisify as promisify79 } from "node:util";
|
|
263515
|
+
var execFileAsync28 = promisify79(execFile34);
|
|
262945
263516
|
var ORPHANED_LIVE_STATES = /* @__PURE__ */ new Set([
|
|
262946
263517
|
"starting",
|
|
262947
263518
|
"ready",
|
|
@@ -262952,7 +263523,7 @@ var DEFAULT_MAX_RESUME_ATTEMPTS = 2;
|
|
|
262952
263523
|
var DEFAULT_RESUME_BACKOFF_BASE_MS = 1e3;
|
|
262953
263524
|
async function defaultIsWorktreeDirty(worktreePath) {
|
|
262954
263525
|
try {
|
|
262955
|
-
const { stdout } = await
|
|
263526
|
+
const { stdout } = await execFileAsync28("git", ["status", "--porcelain"], {
|
|
262956
263527
|
cwd: worktreePath
|
|
262957
263528
|
});
|
|
262958
263529
|
return stdout.trim().length > 0;
|
|
@@ -265301,7 +265872,7 @@ init_notifier();
|
|
|
265301
265872
|
|
|
265302
265873
|
// ../engine/src/healing/stuck-task-detector.ts
|
|
265303
265874
|
init_logger();
|
|
265304
|
-
import { createHash as
|
|
265875
|
+
import { createHash as createHash36 } from "node:crypto";
|
|
265305
265876
|
var stuckLog = createLogger("stuck-detector");
|
|
265306
265877
|
var LOOP_ACTIVITY_THRESHOLD = 60;
|
|
265307
265878
|
var LOOP_IGNORED_STEP_MIN = 10;
|
|
@@ -265312,7 +265883,7 @@ var TOOL_DETAIL_HASH_HEX_LEN = 16;
|
|
|
265312
265883
|
var NO_PROGRESS_CHURN_THRESHOLD = 25;
|
|
265313
265884
|
var VERIFICATION_DEADLINE_GRACE_MS = 5e3;
|
|
265314
265885
|
function hashToolDetail(detail) {
|
|
265315
|
-
return
|
|
265886
|
+
return createHash36("sha256").update(detail).digest("hex").slice(0, TOOL_DETAIL_HASH_HEX_LEN);
|
|
265316
265887
|
}
|
|
265317
265888
|
function buildToolFingerprint(toolName, toolDetail) {
|
|
265318
265889
|
const name2 = toolName.trim().toLowerCase() || "tool";
|
|
@@ -268021,7 +268592,7 @@ var MissionAutopilot = class {
|
|
|
268021
268592
|
// ../engine/src/missions/mission-execution-loop.ts
|
|
268022
268593
|
init_src2();
|
|
268023
268594
|
import { EventEmitter as EventEmitter26 } from "node:events";
|
|
268024
|
-
import { createHash as
|
|
268595
|
+
import { createHash as createHash37 } from "node:crypto";
|
|
268025
268596
|
|
|
268026
268597
|
// ../engine/src/missions/mission-verification.ts
|
|
268027
268598
|
init_sandbox();
|
|
@@ -268033,8 +268604,8 @@ import { promises as fs9 } from "node:fs";
|
|
|
268033
268604
|
import os7 from "node:os";
|
|
268034
268605
|
import path5 from "node:path";
|
|
268035
268606
|
import { exec as exec58 } from "node:child_process";
|
|
268036
|
-
import { promisify as
|
|
268037
|
-
var execAsync54 =
|
|
268607
|
+
import { promisify as promisify80 } from "node:util";
|
|
268608
|
+
var execAsync54 = promisify80(exec58);
|
|
268038
268609
|
var verifyLog = createLogger("mission-verify");
|
|
268039
268610
|
var GitCheckoutMaterializer = class {
|
|
268040
268611
|
async materialize(rootDir, revision) {
|
|
@@ -268083,8 +268654,8 @@ init_fallback_model_observer();
|
|
|
268083
268654
|
init_mcp_resolution();
|
|
268084
268655
|
init_run_audit();
|
|
268085
268656
|
import { exec as exec59 } from "node:child_process";
|
|
268086
|
-
import { promisify as
|
|
268087
|
-
var execAsync55 =
|
|
268657
|
+
import { promisify as promisify81 } from "node:util";
|
|
268658
|
+
var execAsync55 = promisify81(exec59);
|
|
268088
268659
|
function quoteShellArg8(value) {
|
|
268089
268660
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
268090
268661
|
}
|
|
@@ -268094,7 +268665,7 @@ var MAX_VALIDATION_RESPONSE_BYTES = 256 * 1024;
|
|
|
268094
268665
|
var MAX_VALIDATION_JSON_CANDIDATES = 8;
|
|
268095
268666
|
var VALIDATION_FAILURE_BUDGET_PER_FINGERPRINT = 3;
|
|
268096
268667
|
function fingerprintMissionValidationInput(landedSha, provider, modelId, systemPrompt, userPrompt) {
|
|
268097
|
-
return
|
|
268668
|
+
return createHash37("sha256").update(Buffer.from(JSON.stringify(["mission-validation-input-v1", landedSha, provider, modelId, systemPrompt, userPrompt]), "utf8")).digest("hex");
|
|
268098
268669
|
}
|
|
268099
268670
|
var MissionExecutionLoop = class extends EventEmitter26 {
|
|
268100
268671
|
running = false;
|
|
@@ -269802,7 +270373,7 @@ import { exec as exec60 } from "node:child_process";
|
|
|
269802
270373
|
import { existsSync as existsSync84 } from "node:fs";
|
|
269803
270374
|
import { readFile as readFile50, writeFile as writeFile29, rm as rm16 } from "node:fs/promises";
|
|
269804
270375
|
import { join as join94 } from "node:path";
|
|
269805
|
-
import { promisify as
|
|
270376
|
+
import { promisify as promisify82 } from "node:util";
|
|
269806
270377
|
|
|
269807
270378
|
// ../engine/src/triage-domain/triage-preflight.ts
|
|
269808
270379
|
var BUG_FIX_REGEX = /typecheck error|compile error|broken|regression|lint error/i;
|
|
@@ -273020,7 +273591,7 @@ ${lines.join("\n")}` }],
|
|
|
273020
273591
|
written,
|
|
273021
273592
|
{
|
|
273022
273593
|
cwd: this.rootDir,
|
|
273023
|
-
exec:
|
|
273594
|
+
exec: promisify82(exec60)
|
|
273024
273595
|
}
|
|
273025
273596
|
),
|
|
273026
273597
|
new Promise((resolve52) => setTimeout(() => resolve52(null), 15e3))
|
|
@@ -273797,7 +274368,7 @@ function stableNotificationJson(value) {
|
|
|
273797
274368
|
return `{${fields.join(",")}}`;
|
|
273798
274369
|
}
|
|
273799
274370
|
function buildCliAgentNotificationDedupeKey(input) {
|
|
273800
|
-
const notificationFingerprint =
|
|
274371
|
+
const notificationFingerprint = createHash38("sha256").update(stableNotificationJson(input.info.notification ?? null)).digest("hex").slice(0, 16);
|
|
273801
274372
|
const waitingEpoch = input.session?.updatedAt ?? "unknown-waiting-epoch";
|
|
273802
274373
|
return [
|
|
273803
274374
|
"cli-agent",
|
|
@@ -278487,8 +279058,8 @@ init_src2();
|
|
|
278487
279058
|
init_agent_user_comments();
|
|
278488
279059
|
init_worktree_names();
|
|
278489
279060
|
init_integration_branch();
|
|
278490
|
-
import { execFile as
|
|
278491
|
-
import { promisify as
|
|
279061
|
+
import { execFile as execFile39 } from "node:child_process";
|
|
279062
|
+
import { promisify as promisify87 } from "node:util";
|
|
278492
279063
|
import { realpathSync as realpathSync15, readdirSync as readdirSync13 } from "node:fs";
|
|
278493
279064
|
import { mkdtemp as mkdtemp5 } from "node:fs/promises";
|
|
278494
279065
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
@@ -278497,10 +279068,10 @@ init_workspace_base_branch();
|
|
|
278497
279068
|
init_merger_ref_update_advance();
|
|
278498
279069
|
|
|
278499
279070
|
// ../engine/src/merge/merger-ai-squash-gates.ts
|
|
278500
|
-
import { execFile as
|
|
278501
|
-
import { promisify as
|
|
279071
|
+
import { execFile as execFile35 } from "node:child_process";
|
|
279072
|
+
import { promisify as promisify83 } from "node:util";
|
|
278502
279073
|
init_merger_file_scope();
|
|
278503
|
-
var
|
|
279074
|
+
var execFileAsync29 = promisify83(execFile35);
|
|
278504
279075
|
function resolveRepoDeclaredScopeTransform({ repoRel, repoKeys }) {
|
|
278505
279076
|
return {
|
|
278506
279077
|
transform(scope) {
|
|
@@ -278531,8 +279102,8 @@ async function enforceAiMergeSquashGates(params) {
|
|
|
278531
279102
|
});
|
|
278532
279103
|
} catch (error2) {
|
|
278533
279104
|
if (!(error2 instanceof FileScopeViolationError)) throw error2;
|
|
278534
|
-
await
|
|
278535
|
-
await
|
|
279105
|
+
await execFileAsync29("git", ["reset", "--hard", params.tipSha], { cwd: params.mergeRoot });
|
|
279106
|
+
await execFileAsync29("git", ["clean", "-fd"], { cwd: params.mergeRoot });
|
|
278536
279107
|
try {
|
|
278537
279108
|
await params.store.updateTask(params.taskId, { aiMergeReviewReconciliation: null });
|
|
278538
279109
|
} catch {
|
|
@@ -278721,10 +279292,10 @@ function resolveWorkspaceMergeReadiness(task, freshModifiedRepositories, netZero
|
|
|
278721
279292
|
}
|
|
278722
279293
|
|
|
278723
279294
|
// ../engine/src/merge/workspace-fence-ref.ts
|
|
278724
|
-
import { execFile as
|
|
278725
|
-
import { createHash as
|
|
278726
|
-
import { promisify as
|
|
278727
|
-
var
|
|
279295
|
+
import { execFile as execFile36 } from "node:child_process";
|
|
279296
|
+
import { createHash as createHash39 } from "node:crypto";
|
|
279297
|
+
import { promisify as promisify84 } from "node:util";
|
|
279298
|
+
var execFileAsync30 = promisify84(execFile36);
|
|
278728
279299
|
var WorkspaceFenceRefError = class extends Error {
|
|
278729
279300
|
constructor(message, kind) {
|
|
278730
279301
|
super(message);
|
|
@@ -278733,7 +279304,7 @@ var WorkspaceFenceRefError = class extends Error {
|
|
|
278733
279304
|
}
|
|
278734
279305
|
};
|
|
278735
279306
|
async function git6(args, cwd) {
|
|
278736
|
-
const { stdout } = await
|
|
279307
|
+
const { stdout } = await execFileAsync30("git", args, {
|
|
278737
279308
|
cwd,
|
|
278738
279309
|
encoding: "utf8",
|
|
278739
279310
|
maxBuffer: 1024 * 1024
|
|
@@ -278746,7 +279317,7 @@ async function remoteRefSha(remote, ref, cwd) {
|
|
|
278746
279317
|
return /^[0-9a-f]{40,64}$/i.test(sha ?? "") ? sha : void 0;
|
|
278747
279318
|
}
|
|
278748
279319
|
function workspaceLandFenceRef(repoRelPath) {
|
|
278749
|
-
const slug2 =
|
|
279320
|
+
const slug2 = createHash39("sha256").update(repoRelPath).digest("hex").slice(0, 24);
|
|
278750
279321
|
return `refs/fusion/workspace-lease/${slug2}`;
|
|
278751
279322
|
}
|
|
278752
279323
|
function mergeDispatchFenceRef(taskId) {
|
|
@@ -278755,7 +279326,7 @@ function mergeDispatchFenceRef(taskId) {
|
|
|
278755
279326
|
async function createFenceObject(cwd, handle2) {
|
|
278756
279327
|
const tree = await git6(["hash-object", "-w", "-t", "tree", "/dev/null"], cwd);
|
|
278757
279328
|
const message = `workspace lease ${handle2.leaseKey} ${handle2.owner.taskId} ${handle2.owner.nodeId} ${handle2.owner.incarnationId} ${handle2.fenceToken}`;
|
|
278758
|
-
const { stdout } = await
|
|
279329
|
+
const { stdout } = await execFileAsync30("git", [
|
|
278759
279330
|
"-c",
|
|
278760
279331
|
"user.name=Fusion",
|
|
278761
279332
|
"-c",
|
|
@@ -278890,9 +279461,9 @@ async function publishWorkspaceIntegrationRef(input) {
|
|
|
278890
279461
|
init_push_after_merge_policy();
|
|
278891
279462
|
|
|
278892
279463
|
// ../engine/src/merge/workspace-integration-target.ts
|
|
278893
|
-
import { execFile as
|
|
278894
|
-
import { promisify as
|
|
278895
|
-
var
|
|
279464
|
+
import { execFile as execFile37 } from "node:child_process";
|
|
279465
|
+
import { promisify as promisify85 } from "node:util";
|
|
279466
|
+
var execFileAsync31 = promisify85(execFile37);
|
|
278896
279467
|
var WorkspaceEnvironmentError = class extends Error {
|
|
278897
279468
|
constructor(repository, resource, action, message) {
|
|
278898
279469
|
super(message);
|
|
@@ -278912,7 +279483,7 @@ var WorkspaceIntegrationTargetError = class extends WorkspaceEnvironmentError {
|
|
|
278912
279483
|
}
|
|
278913
279484
|
};
|
|
278914
279485
|
async function git7(args, cwd) {
|
|
278915
|
-
const { stdout } = await
|
|
279486
|
+
const { stdout } = await execFileAsync31("git", args, { cwd, encoding: "utf8" });
|
|
278916
279487
|
return stdout.trim();
|
|
278917
279488
|
}
|
|
278918
279489
|
async function resolveWorkspaceIntegrationTarget(input) {
|
|
@@ -278959,17 +279530,17 @@ init_worktree_paths();
|
|
|
278959
279530
|
|
|
278960
279531
|
// ../engine/src/merge/merger-ai-worktree.ts
|
|
278961
279532
|
init_active_session_registry();
|
|
278962
|
-
import { execFile as
|
|
279533
|
+
import { execFile as execFile38 } from "node:child_process";
|
|
278963
279534
|
import { appendFileSync as appendFileSync2, existsSync as existsSync87, mkdirSync as mkdirSync11, readdirSync as readdirSync12, readFileSync as readFileSync28, realpathSync as realpathSync14, rmSync as rmSync8, statSync as statSync16 } from "node:fs";
|
|
278964
279535
|
import { rm as rm17 } from "node:fs/promises";
|
|
278965
279536
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
278966
279537
|
import { isAbsolute as isAbsolute27, join as join96, relative as relative23 } from "node:path";
|
|
278967
|
-
import { promisify as
|
|
279538
|
+
import { promisify as promisify86 } from "node:util";
|
|
278968
279539
|
init_worktree_paths();
|
|
278969
279540
|
init_worktree_removal_retry();
|
|
278970
|
-
var
|
|
279541
|
+
var execFileAsync32 = promisify86(execFile38);
|
|
278971
279542
|
async function git8(args, cwd, opts = {}) {
|
|
278972
|
-
const { stdout } = await
|
|
279543
|
+
const { stdout } = await execFileAsync32("git", args, {
|
|
278973
279544
|
cwd,
|
|
278974
279545
|
encoding: "utf-8",
|
|
278975
279546
|
timeout: opts.timeout ?? 12e4,
|
|
@@ -278998,14 +279569,7 @@ function ensureAiMergeRootIgnored(projectRootDir, settings) {
|
|
|
278998
279569
|
if (!existsSync87(excludePath)) return;
|
|
278999
279570
|
try {
|
|
279000
279571
|
const current = readFileSync28(excludePath, "utf-8");
|
|
279001
|
-
const
|
|
279002
|
-
const legacyRelativeAiMergeRoot = relative23(projectRootDir, legacyAiMergeRoot);
|
|
279003
|
-
const entries = [`${legacyRelativeAiMergeRoot.replaceAll("\\", "/")}/`];
|
|
279004
|
-
const aiMergeRoot = resolveAiMergeRootPath(projectRootDir, settings);
|
|
279005
|
-
const relativeAiMergeRoot = relative23(projectRootDir, aiMergeRoot);
|
|
279006
|
-
if (relativeAiMergeRoot && !relativeAiMergeRoot.startsWith("..") && !isAbsolute27(relativeAiMergeRoot)) {
|
|
279007
|
-
entries.push(`${relativeAiMergeRoot.replaceAll("\\", "/")}/`);
|
|
279008
|
-
}
|
|
279572
|
+
const entries = resolveAiMergeSearchRoots(projectRootDir, settings).map((root) => relative23(projectRootDir, root)).filter((root) => root && !root.startsWith("..") && !isAbsolute27(root)).map((root) => `${root.replaceAll("\\", "/")}/`);
|
|
279009
279573
|
const missing = entries.filter((entry) => !current.split(/\r?\n/).includes(entry));
|
|
279010
279574
|
if (missing.length > 0) {
|
|
279011
279575
|
appendFileSync2(excludePath, `${current.endsWith("\n") ? "" : "\n"}${missing.join("\n")}
|
|
@@ -279021,7 +279585,7 @@ function resolveAiMergeRoot(projectRootDir, settings) {
|
|
|
279021
279585
|
return root;
|
|
279022
279586
|
}
|
|
279023
279587
|
function getAiMergeTempSearchRoots(projectRootDir, settings) {
|
|
279024
|
-
const roots = [resolveAiMergeRoot(projectRootDir, settings),
|
|
279588
|
+
const roots = [resolveAiMergeRoot(projectRootDir, settings), ...resolveAiMergeSearchRoots(projectRootDir, settings), tmpdir11()];
|
|
279025
279589
|
const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
|
|
279026
279590
|
if (testWorkerRoot) {
|
|
279027
279591
|
try {
|
|
@@ -279074,7 +279638,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log4
|
|
|
279074
279638
|
let alreadyAbsent = false;
|
|
279075
279639
|
try {
|
|
279076
279640
|
cleanupAttempted = true;
|
|
279077
|
-
await
|
|
279641
|
+
await execFileAsync32("git", ["worktree", "remove", "--force", canonicalPath], {
|
|
279078
279642
|
cwd: projectRootDir,
|
|
279079
279643
|
timeout: 3e4
|
|
279080
279644
|
});
|
|
@@ -279105,7 +279669,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log4
|
|
|
279105
279669
|
}
|
|
279106
279670
|
if (cleanupAttempted) {
|
|
279107
279671
|
try {
|
|
279108
|
-
await
|
|
279672
|
+
await execFileAsync32("git", ["worktree", "prune"], { cwd: projectRootDir, timeout: 3e4 });
|
|
279109
279673
|
} catch (err) {
|
|
279110
279674
|
await log42(`AI merge pre-merge prune: git worktree prune failed: ${describeCleanupError(err)}`);
|
|
279111
279675
|
}
|
|
@@ -279514,7 +280078,7 @@ function short(sha) {
|
|
|
279514
280078
|
}
|
|
279515
280079
|
|
|
279516
280080
|
// ../engine/src/merge/merger-ai.ts
|
|
279517
|
-
var
|
|
280081
|
+
var execFileAsync33 = promisify87(execFile39);
|
|
279518
280082
|
var aiMergeLog = createLogger("merger-ai");
|
|
279519
280083
|
async function resolveNoOpFinalizeGateIds3(store, task) {
|
|
279520
280084
|
const selection = store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(task.id) : store.getTaskWorkflowSelection?.(task.id);
|
|
@@ -279540,7 +280104,7 @@ function writeTransientMergeStatus(store, taskId, signal, status) {
|
|
|
279540
280104
|
return fence.write("lifecycle", () => store.updateTask(taskId, { status }).catch(() => void 0));
|
|
279541
280105
|
}
|
|
279542
280106
|
async function git9(args, cwd, opts = {}) {
|
|
279543
|
-
const { stdout } = await
|
|
280107
|
+
const { stdout } = await execFileAsync33("git", args, {
|
|
279544
280108
|
cwd,
|
|
279545
280109
|
encoding: "utf-8",
|
|
279546
280110
|
timeout: opts.timeout ?? 12e4,
|
|
@@ -279581,7 +280145,7 @@ function boundBlockingReviewReasons(reasons) {
|
|
|
279581
280145
|
}
|
|
279582
280146
|
function listAiMergeWorktreeCandidates(taskId, projectRootDir, settings) {
|
|
279583
280147
|
const prefix = `fusion-ai-merge-${taskId.toLowerCase()}-`;
|
|
279584
|
-
const roots = Array.from(/* @__PURE__ */ new Set([resolveAiMergeRoot(projectRootDir, settings),
|
|
280148
|
+
const roots = Array.from(/* @__PURE__ */ new Set([resolveAiMergeRoot(projectRootDir, settings), ...resolveAiMergeSearchRoots(projectRootDir, settings), tmpdir12()]));
|
|
279585
280149
|
const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
|
|
279586
280150
|
if (testWorkerRoot) {
|
|
279587
280151
|
try {
|
|
@@ -282166,8 +282730,8 @@ init_transient_merge_error_classifier();
|
|
|
282166
282730
|
|
|
282167
282731
|
// ../engine/src/remote-access/remote-tunnel-service.ts
|
|
282168
282732
|
init_logger();
|
|
282169
|
-
import { execFile as
|
|
282170
|
-
import { promisify as
|
|
282733
|
+
import { execFile as execFile41 } from "node:child_process";
|
|
282734
|
+
import { promisify as promisify89 } from "node:util";
|
|
282171
282735
|
|
|
282172
282736
|
// ../engine/src/local-dashboard-port.ts
|
|
282173
282737
|
var DEFAULT_DASHBOARD_PORT = 4040;
|
|
@@ -282180,8 +282744,8 @@ function getLocalDashboardPort() {
|
|
|
282180
282744
|
init_src2();
|
|
282181
282745
|
init_logger();
|
|
282182
282746
|
import { EventEmitter as EventEmitter28 } from "node:events";
|
|
282183
|
-
import { exec as exec61, execFile as
|
|
282184
|
-
import { promisify as
|
|
282747
|
+
import { exec as exec61, execFile as execFile40, spawn as spawn8 } from "node:child_process";
|
|
282748
|
+
import { promisify as promisify88 } from "node:util";
|
|
282185
282749
|
|
|
282186
282750
|
// ../engine/src/remote-access/provider-adapters.ts
|
|
282187
282751
|
import { accessSync, constants as fsConstants5 } from "node:fs";
|
|
@@ -282349,8 +282913,8 @@ var DEFAULT_MAX_LOG_ENTRIES = 400;
|
|
|
282349
282913
|
var DEFAULT_STOP_TIMEOUT_MS2 = 5e3;
|
|
282350
282914
|
var DEFAULT_RESTART_BASE_DELAY_MS = 1e3;
|
|
282351
282915
|
var DEFAULT_RESTART_MAX_DELAY_MS = 3e4;
|
|
282352
|
-
var
|
|
282353
|
-
var execAsync56 =
|
|
282916
|
+
var execFileAsync34 = promisify88(execFile40);
|
|
282917
|
+
var execAsync56 = promisify88(exec61);
|
|
282354
282918
|
function serveConfigScopes(config3) {
|
|
282355
282919
|
const foreground = Object.values(config3.Foreground ?? {}).filter(
|
|
282356
282920
|
(scope) => Boolean(scope)
|
|
@@ -282500,7 +283064,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
282500
283064
|
return null;
|
|
282501
283065
|
}
|
|
282502
283066
|
try {
|
|
282503
|
-
const { stdout } = await
|
|
283067
|
+
const { stdout } = await execFileAsync34("tailscale", ["status", "--json"], { timeout: 3e3 });
|
|
282504
283068
|
const data = JSON.parse(String(stdout));
|
|
282505
283069
|
const dnsName = data.Self?.DNSName?.replace(/\.$/, "");
|
|
282506
283070
|
if (!dnsName) {
|
|
@@ -282523,7 +283087,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
282523
283087
|
];
|
|
282524
283088
|
for (const resetCommand of resetCommands) {
|
|
282525
283089
|
try {
|
|
282526
|
-
await
|
|
283090
|
+
await execFileAsync34(resetCommand.command, resetCommand.args, { timeout: 5e3 });
|
|
282527
283091
|
return;
|
|
282528
283092
|
} catch {
|
|
282529
283093
|
}
|
|
@@ -282629,7 +283193,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
282629
283193
|
async detectActiveFunnel() {
|
|
282630
283194
|
let stdout = "";
|
|
282631
283195
|
try {
|
|
282632
|
-
const result = await
|
|
283196
|
+
const result = await execFileAsync34("tailscale", ["serve", "status", "--json"], { timeout: 5e3 });
|
|
282633
283197
|
stdout = String(result.stdout ?? "");
|
|
282634
283198
|
} catch (error2) {
|
|
282635
283199
|
const failure = error2;
|
|
@@ -283045,7 +283609,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
283045
283609
|
};
|
|
283046
283610
|
|
|
283047
283611
|
// ../engine/src/remote-access/remote-tunnel-service.ts
|
|
283048
|
-
var
|
|
283612
|
+
var execFileAsync35 = promisify89(execFile41);
|
|
283049
283613
|
var isRemoteActive = (ra) => ra?.activeProvider != null && (ra.providers[ra.activeProvider]?.enabled ?? false);
|
|
283050
283614
|
var RemoteTunnelService = class {
|
|
283051
283615
|
manager = new TunnelProcessManager();
|
|
@@ -283394,7 +283958,7 @@ var RemoteTunnelService = class {
|
|
|
283394
283958
|
async checkTailscaleDaemonReady() {
|
|
283395
283959
|
let stdout = "";
|
|
283396
283960
|
try {
|
|
283397
|
-
const result = await
|
|
283961
|
+
const result = await execFileAsync35("tailscale", ["status", "--json"], {
|
|
283398
283962
|
timeout: 5e3,
|
|
283399
283963
|
maxBuffer: 8 * 1024 * 1024
|
|
283400
283964
|
});
|
|
@@ -283442,7 +284006,7 @@ var RemoteTunnelService = class {
|
|
|
283442
284006
|
async checkExecutableAvailable(command) {
|
|
283443
284007
|
const checker = process.platform === "win32" ? "where" : "which";
|
|
283444
284008
|
try {
|
|
283445
|
-
await
|
|
284009
|
+
await execFileAsync35(checker, [command]);
|
|
283446
284010
|
return { available: true };
|
|
283447
284011
|
} catch {
|
|
283448
284012
|
return {
|
|
@@ -283625,7 +284189,7 @@ function emitMergeRequestShadowDequeueParityAudit(store, legacyTaskId, shadowTas
|
|
|
283625
284189
|
metadata: { legacyTaskId, shadowTaskId, agree }
|
|
283626
284190
|
}, { log: runtimeLog });
|
|
283627
284191
|
}
|
|
283628
|
-
var
|
|
284192
|
+
var execFileAsync36 = promisify90(execFile42);
|
|
283629
284193
|
var MERGE_HANDOFF_GRACE_MS = 300;
|
|
283630
284194
|
function isActiveMergeRequestState(state) {
|
|
283631
284195
|
return state === "running" || state === "retrying";
|
|
@@ -283671,7 +284235,7 @@ async function verifyMergeConfirmedReachability(args) {
|
|
|
283671
284235
|
return { reachable: true, skipped: "no-integration-branch" };
|
|
283672
284236
|
}
|
|
283673
284237
|
try {
|
|
283674
|
-
await
|
|
284238
|
+
await execFileAsync36("git", ["cat-file", "-e", `${commitSha}^{commit}`], {
|
|
283675
284239
|
cwd,
|
|
283676
284240
|
timeout: 1e4
|
|
283677
284241
|
});
|
|
@@ -283680,7 +284244,7 @@ async function verifyMergeConfirmedReachability(args) {
|
|
|
283680
284244
|
return { reachable: false, reason: "commit-missing", diagnostic };
|
|
283681
284245
|
}
|
|
283682
284246
|
try {
|
|
283683
|
-
await
|
|
284247
|
+
await execFileAsync36(
|
|
283684
284248
|
"git",
|
|
283685
284249
|
["merge-base", "--is-ancestor", commitSha, `refs/heads/${integrationBranch}`],
|
|
283686
284250
|
{ cwd, timeout: 1e4 }
|
|
@@ -283756,6 +284320,7 @@ var ProjectEngine = class _ProjectEngine {
|
|
|
283756
284320
|
}
|
|
283757
284321
|
});
|
|
283758
284322
|
}
|
|
284323
|
+
staleContentRerouteAuditKeys = /* @__PURE__ */ new Set();
|
|
283759
284324
|
runtime;
|
|
283760
284325
|
started = false;
|
|
283761
284326
|
specDriftReconciler;
|
|
@@ -285552,11 +286117,44 @@ ${detail}`);
|
|
|
285552
286117
|
workspaceRootDir: this.config.workingDirectory,
|
|
285553
286118
|
settings
|
|
285554
286119
|
});
|
|
285555
|
-
|
|
286120
|
+
const blocker = getTaskMergeBlocker(task, {
|
|
285556
286121
|
reviewColumns: mergeGate.reviewColumns.size > 0 ? mergeGate.reviewColumns : /* @__PURE__ */ new Set(["in-review"]),
|
|
285557
286122
|
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
285558
286123
|
mergeContent
|
|
285559
286124
|
});
|
|
286125
|
+
if (blocker === "task has a pre-merge approval recorded against different content" && mergeContent.kind === "singular") {
|
|
286126
|
+
const reroute = await rerouteSingularStaleContentToReview(store, task, {
|
|
286127
|
+
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
286128
|
+
mergeContent
|
|
286129
|
+
}).catch(() => ({
|
|
286130
|
+
rerouted: false,
|
|
286131
|
+
reason: "no-progress",
|
|
286132
|
+
nodeId: void 0,
|
|
286133
|
+
workflowStepId: void 0
|
|
286134
|
+
}));
|
|
286135
|
+
if (reroute.rerouted) {
|
|
286136
|
+
await store.logEntry(task.id, `[pre-merge] Code Review re-entry is owned by the workflow graph after stale content evidence was refused.`);
|
|
286137
|
+
}
|
|
286138
|
+
const auditKey = `${task.id}:${reroute.reason}`;
|
|
286139
|
+
if (!this.staleContentRerouteAuditKeys.has(auditKey)) {
|
|
286140
|
+
this.staleContentRerouteAuditKeys.add(auditKey);
|
|
286141
|
+
await emitBoundedRunAudit2(store, {
|
|
286142
|
+
taskId: task.id,
|
|
286143
|
+
agentId: "merge-gate",
|
|
286144
|
+
runId: `${task.id}:merge-gate`,
|
|
286145
|
+
domain: "database",
|
|
286146
|
+
mutationType: "task:merge-stale-content-review-rerouted",
|
|
286147
|
+
target: task.id,
|
|
286148
|
+
metadata: {
|
|
286149
|
+
taskId: task.id,
|
|
286150
|
+
nodeId: reroute.nodeId,
|
|
286151
|
+
workflowStepId: reroute.workflowStepId,
|
|
286152
|
+
reason: reroute.reason
|
|
286153
|
+
}
|
|
286154
|
+
});
|
|
286155
|
+
}
|
|
286156
|
+
}
|
|
286157
|
+
return blocker;
|
|
285560
286158
|
}
|
|
285561
286159
|
/**
|
|
285562
286160
|
* Remove and return the highest-priority taskId from the merge queue.
|
|
@@ -286402,7 +287000,7 @@ ${detail}`);
|
|
|
286402
287000
|
}
|
|
286403
287001
|
const checklist = planConfirmedMergeChecklistReconciliation(task);
|
|
286404
287002
|
if (checklist.skippedStepIndexes.length > 0 || checklist.reconciledWorkflowStepIds.length > 0) {
|
|
286405
|
-
const steps = task.steps.map((step, index2) => checklist.skippedStepIndexes.includes(index2) ? { ...step, status: "skipped" } : step);
|
|
287003
|
+
const steps = (task.steps ?? []).map((step, index2) => checklist.skippedStepIndexes.includes(index2) ? { ...step, status: "skipped" } : step);
|
|
286406
287004
|
const workflowStepResults = (task.workflowStepResults ?? []).map((result) => checklist.reconciledWorkflowStepIds.includes(result.workflowStepId) ? { ...result, status: "skipped" } : result);
|
|
286407
287005
|
await store.updateTask(taskId, { steps, workflowStepResults });
|
|
286408
287006
|
task.steps = steps;
|