@runfusion/fusion 0.77.0-beta.12 → 0.77.0-beta.14
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 +1648 -909
- package/dist/child-process-worker.js +1072 -471
- package/dist/client/.vite/manifest.json +260 -260
- package/dist/client/assets/{AgentDetailView-BZfDgV8f.js → AgentDetailView-C-fxrRM5.js} +1 -1
- package/dist/client/assets/AgentDetailView-DPoh46Ym.css +1 -0
- package/dist/client/assets/{AgentPermissionPolicyEditor-8yBqnwbx.js → AgentPermissionPolicyEditor-BvEdHYdU.js} +1 -1
- package/dist/client/assets/{AgentsView-BjMOtIMq.js → AgentsView-nLidYV1p.js} +3 -3
- package/dist/client/assets/CommandCenter-BshTzOtB.css +1 -0
- package/dist/client/assets/{CommandCenter-CDuO3HPd.js → CommandCenter-BxFBD-rU.js} +22 -22
- package/dist/client/assets/{DevServerView-C96RV0QJ.js → DevServerView-KLdA68W-.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-iRielXf7.js → DirectoryPicker-BiclyrJo.js} +1 -1
- package/dist/client/assets/{DocumentsView-DhAUnUD_.js → DocumentsView-BU24Dd5I.js} +1 -1
- package/dist/client/assets/{EvalsView--n1p2Bt0.js → EvalsView-BMSTg0vH.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-DraglCCV.js → ExperimentalAgentOnboardingModal-BtYOAtE2.js} +1 -1
- package/dist/client/assets/{GoalsView-BOWOua5t.js → GoalsView-Dlb12ETy.js} +1 -1
- package/dist/client/assets/{InsightsView-C5YcJZSc.js → InsightsView-NJuA0vFY.js} +1 -1
- package/dist/client/assets/{MemoryView-DsCuGVGx.js → MemoryView-te2vPbGq.js} +1 -1
- package/dist/client/assets/{PatchnodeView-CzgChkJV.js → PatchnodeView-F-TmysVw.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-qYbmaigE.js → PiExtensionsManager-CClfNfAm.js} +1 -1
- package/dist/client/assets/{PluginManager-Cklj4Smo.js → PluginManager-BdNdqcjr.js} +1 -1
- package/dist/client/assets/{PullRequestView-C6vozTTI.js → PullRequestView-Du4FqTkG.js} +1 -1
- package/dist/client/assets/{ReportModal-B0LU4E4L.js → ReportModal-BCUOLOBM.js} +1 -1
- package/dist/client/assets/{ResearchView-CpESx46e.js → ResearchView-DukV-C42.js} +1 -1
- package/dist/client/assets/{SecretsView-8ZdH9Yzs.js → SecretsView-B3ApHMyx.js} +1 -1
- package/dist/client/assets/SettingsModal-BEULP2a7.css +1 -0
- package/dist/client/assets/{SettingsModal-BJXu-dhz.js → SettingsModal-D-_HKpi5.js} +1 -1
- package/dist/client/assets/SettingsModal-JPt8VHZy.js +21 -0
- package/dist/client/assets/{SettingsTextareaRow-th-q0_2k.js → SettingsTextareaRow-CpTYQz1W.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-CBElxrRA.js → SetupWizardModal-DcD2ERVR.js} +2 -2
- package/dist/client/assets/{SkillsView-BuoicLbJ.js → SkillsView-DCqRw00z.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-BDw0LpWM.js → WorkflowNodeEditor-CxpjK-k_.js} +1 -1
- package/dist/client/assets/{agent-import-generation-CNridJHO.js → agent-import-generation-COouuGNI.js} +1 -1
- package/dist/client/assets/{agentsOrgChartLayout-BopFGp0r.js → agentsOrgChartLayout-BkXeACZM.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-CGeVlxee.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-ueBSwDJh.js → blockDiagram-GPEHLZMM-D3J6Tg96.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-D0cUU3pE.js → c4Diagram-AAUBKEIU-Ckh64Ujd.js} +1 -1
- package/dist/client/assets/channel-HtwB1uv6.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-DKJnGdD6.js → chunk-2J33WTMH-D2nEfwjq.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-BUrgUtvt.js → chunk-4BX2VUAB-C_LbWHxf.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DHy2hCYz.js → chunk-55IACEB6-DCe4vUlx.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-Dgbhllem.js → chunk-727SXJPM-iwy0O4kD.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-tPbicvl-.js → chunk-AQP2D5EJ-3FRhkbWy.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-BpHFGFmo.js → chunk-FMBD7UC4-DKwvI3J1.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-DUTQ63ld.js → chunk-ND2GUHAM-BLCbQ396.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-ChCf_usL.js → chunk-QZHKN3VN-B8_SVfXK.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DY01_o5q.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DY01_o5q.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-DgWzHtF9.js → cose-bilkent-S5V4N54A-BI3P2QH1.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-gQ1C1xHJ.js → dagre-BM42HDAG-Cw7T4fR4.js} +1 -1
- package/dist/client/assets/{dashboard-view-BXtoQ9a4.js → dashboard-view-Bahw8YdV.js} +1 -1
- package/dist/client/assets/{dashboard-view-BLenRoXu.js → dashboard-view-GzD2Iawz.js} +1 -1
- package/dist/client/assets/{dashboard-view-AQmzkBNb.js → dashboard-view-_8Rh_v2d.js} +1 -1
- package/dist/client/assets/{dashboard-view-BtFepPos.js → dashboard-view-nmh7Oq3W.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-Dv96I1MI.js → diagram-2AECGRRQ-D-HeBfdu.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-BRyhjYes.js → diagram-5GNKFQAL-DdqdGn6R.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-Bmj3ihjc.js → diagram-KO2AKTUF-BiqjUeas.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-BYHVCFK2.js → diagram-LMA3HP47-XAqAjX_Q.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-0WZBLayt.js → diagram-OG6HWLK6-DFA7xW7A.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Cu-yj8hA.js → erDiagram-TEJ5UH35-ChXB-xPr.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BSetu6oh.js → flowDiagram-I6XJVG4X-7EGMaA4S.js} +1 -1
- package/dist/client/assets/{folder-open-CkswT0lE.js → folder-open-CRG4IIvN.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-B5qn0KFQ.js → ganttDiagram-6RSMTGT7-CFu_eMTW.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-BVB3wm46.js → gitGraphDiagram-PVQCEYII-B6D4IPay.js} +1 -1
- package/dist/client/assets/index-bjswUBcF.js +2937 -0
- package/dist/client/assets/index-lxhrCjd_.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-ZBNKOBSK.js → infoDiagram-5YYISTIA-WjP49ki8.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CbNKgenI.js → ishikawaDiagram-YF4QCWOH-D9dfXlEr.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BLc2FHIF.js → journeyDiagram-JHISSGLW-B1qmhVqE.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-B08tij8f.js → kanban-definition-UN3LZRKU-DKJ9zHQh.js} +1 -1
- package/dist/client/assets/{mermaid.core-QX5z7w8Z.js → mermaid.core-L96x9i-s.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-C1md8M3c.js → mindmap-definition-RKZ34NQL-Cd6f8xCu.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-BoQbn3Xp.js → pieDiagram-4H26LBE5-DxV4qYtG.js} +1 -1
- package/dist/client/assets/{puzzle-DCqPnWPE.js → puzzle-B-xyPV3x.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DPvNcVK-.js → quadrantDiagram-W4KKPZXB-CSfHWa-s.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-KfdYf15t.js → requirementDiagram-4Y6WPE33-BVyQ-8E1.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-D1Eyoanf.js → sankeyDiagram-5OEKKPKP-bz2Lc_rV.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CmODsbCf.js → sequenceDiagram-3UESZ5HK-ZvToVBro.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-D_mPaGcG.js → standing-instructions-template-DVKRWk6d.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-Blbw_21G.js → stateDiagram-AJRCARHV-CSCy0VcB.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-DwMgvYO8.js → stateDiagram-v2-BHNVJYJU-ChRwUFh1.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-DDtndgLc.js → timeline-definition-PNZ67QCA-9MuQjnnW.js} +1 -1
- package/dist/client/assets/{upload-DGCjJkMH.js → upload-B1HSIk-m.js} +1 -1
- package/dist/client/assets/{users-CbWZvFZP.js → users-CHrRYBSi.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-B6Sx0OqW.js → vennDiagram-CIIHVFJN-D3XO2rfJ.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-_SQFYU4g.js → wardley-L42UT6IY-Dug4bLhv.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Ce5igv6s.js → wardleyDiagram-YWT4CUSO-CtGA4P2g.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-zI0zyvDP.js → xychartDiagram-2RQKCTM6-D0EMf4Z7.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 +1487 -803
- 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
|
|
|
@@ -6505,7 +6730,7 @@ function scoreLatinLocale(text2) {
|
|
|
6505
6730
|
return { locale: "en", confidence: "low" };
|
|
6506
6731
|
}
|
|
6507
6732
|
const ratio = secondScore === 0 ? Infinity : bestScore / secondScore;
|
|
6508
|
-
const confidence = bestScore >= 4 && ratio >= 1.6 ? "high" : bestScore >=
|
|
6733
|
+
const confidence = bestScore >= 4 && ratio >= 1.6 ? "high" : bestScore >= 3 && ratio >= 1.5 ? "medium" : "low";
|
|
6509
6734
|
return { locale: best[0] === "cs" ? "unknown" : best[0], confidence };
|
|
6510
6735
|
}
|
|
6511
6736
|
function detectContentLanguage(text2) {
|
|
@@ -6647,11 +6872,16 @@ var init_detect_content_language = __esm({
|
|
|
6647
6872
|
"there",
|
|
6648
6873
|
"should"
|
|
6649
6874
|
],
|
|
6875
|
+
/*
|
|
6876
|
+
FNXC:TitleSummaryInputLanguage 2026-09-01-21:25:
|
|
6877
|
+
FN-9241 found that English and technical chat prose can contain `plus`, `par`, and `est`.
|
|
6878
|
+
Omit these collision-prone French tokens so a short English message cannot steer title generation
|
|
6879
|
+
toward French; stronger medium confidence keeps the import translation high-confidence behavior unchanged.
|
|
6880
|
+
*/
|
|
6650
6881
|
fr: [
|
|
6651
6882
|
"les",
|
|
6652
6883
|
"des",
|
|
6653
6884
|
"une",
|
|
6654
|
-
"est",
|
|
6655
6885
|
"dans",
|
|
6656
6886
|
"pour",
|
|
6657
6887
|
"que",
|
|
@@ -6659,8 +6889,6 @@ var init_detect_content_language = __esm({
|
|
|
6659
6889
|
"sur",
|
|
6660
6890
|
"avec",
|
|
6661
6891
|
"pas",
|
|
6662
|
-
"plus",
|
|
6663
|
-
"par",
|
|
6664
6892
|
"sont",
|
|
6665
6893
|
"cette",
|
|
6666
6894
|
"aussi",
|
|
@@ -11453,35 +11681,6 @@ var init_workflow_ir_types = __esm({
|
|
|
11453
11681
|
}
|
|
11454
11682
|
});
|
|
11455
11683
|
|
|
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
11684
|
// ../core/src/workflows/workflow-extension-types.ts
|
|
11486
11685
|
function workflowExtensionRegistryId(pluginId, extensionId) {
|
|
11487
11686
|
return `plugin:${pluginId}:${extensionId}`;
|
|
@@ -12477,6 +12676,16 @@ function validateReviewerAgentOverrides(nodes2) {
|
|
|
12477
12676
|
if (Array.isArray(templateNodes)) validateReviewerAgentOverrides(templateNodes);
|
|
12478
12677
|
}
|
|
12479
12678
|
}
|
|
12679
|
+
function validateReadonlyMcpServersConfig(nodes2) {
|
|
12680
|
+
for (const node of nodes2) {
|
|
12681
|
+
const value = node.config?.readonlyMcpServers;
|
|
12682
|
+
if (value !== void 0 && (!Array.isArray(value) || value.some((name2) => typeof name2 !== "string" || !name2.trim()))) {
|
|
12683
|
+
throw new WorkflowIrError(`Workflow node '${node.id}' readonlyMcpServers must be an array of non-empty strings when present`);
|
|
12684
|
+
}
|
|
12685
|
+
const templateNodes = node.config?.template?.nodes;
|
|
12686
|
+
if (Array.isArray(templateNodes)) validateReadonlyMcpServersConfig(templateNodes);
|
|
12687
|
+
}
|
|
12688
|
+
}
|
|
12480
12689
|
function validateThinkingLevelConfig(nodes2) {
|
|
12481
12690
|
for (const node of nodes2) {
|
|
12482
12691
|
const value = node.config?.thinkingLevel;
|
|
@@ -13091,6 +13300,7 @@ function validateV2(ir2) {
|
|
|
13091
13300
|
const topLevelIds = new Set(ir2.nodes.map((n) => n.id));
|
|
13092
13301
|
validateStepExecutePlacement(ir2.nodes);
|
|
13093
13302
|
validateThinkingLevelConfig(ir2.nodes);
|
|
13303
|
+
validateReadonlyMcpServersConfig(ir2.nodes);
|
|
13094
13304
|
validateCredentialInstanceIdConfig(ir2.nodes);
|
|
13095
13305
|
validateReviewerAgentOverrides(ir2.nodes);
|
|
13096
13306
|
for (const node of ir2.nodes) {
|
|
@@ -29161,169 +29371,6 @@ var init_explicit_duplicate_marker = __esm({
|
|
|
29161
29371
|
}
|
|
29162
29372
|
});
|
|
29163
29373
|
|
|
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
29374
|
// ../core/src/mesh/mesh-task-replication.ts
|
|
29328
29375
|
function buildBootstrapPrompt(taskId, title, description) {
|
|
29329
29376
|
const heading = title ? `${taskId}: ${title}` : taskId;
|
|
@@ -66524,10 +66571,10 @@ var init_migration = __esm({
|
|
|
66524
66571
|
return basename6(projectPath);
|
|
66525
66572
|
}
|
|
66526
66573
|
try {
|
|
66527
|
-
const { execFile:
|
|
66528
|
-
const { promisify:
|
|
66529
|
-
const
|
|
66530
|
-
const { stdout } = await
|
|
66574
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
66575
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
66576
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
66577
|
+
const { stdout } = await execFileAsync37(
|
|
66531
66578
|
"git",
|
|
66532
66579
|
["remote", "get-url", "origin"],
|
|
66533
66580
|
{ cwd: projectPath, timeout: 1e3 }
|
|
@@ -68722,10 +68769,10 @@ var init_central_core = __esm({
|
|
|
68722
68769
|
*/
|
|
68723
68770
|
async generateProjectName(projectPath) {
|
|
68724
68771
|
try {
|
|
68725
|
-
const { execFile:
|
|
68726
|
-
const { promisify:
|
|
68727
|
-
const
|
|
68728
|
-
const { stdout } = await
|
|
68772
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
68773
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
68774
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
68775
|
+
const { stdout } = await execFileAsync37(
|
|
68729
68776
|
"git",
|
|
68730
68777
|
["remote", "get-url", "origin"],
|
|
68731
68778
|
{ cwd: projectPath, timeout: 5e3 }
|
|
@@ -85527,14 +85574,12 @@ async function listWorkflowDefinitionsImpl(store, options) {
|
|
|
85527
85574
|
return pluginFiltered;
|
|
85528
85575
|
}
|
|
85529
85576
|
async function readAllWorkflowDefinitionsImpl(store) {
|
|
85530
|
-
if (store.workflowDefinitionsCache) return store.workflowDefinitionsCache;
|
|
85531
85577
|
const layer = store.getAsyncLayer();
|
|
85532
85578
|
if (!layer) {
|
|
85533
85579
|
throw new Error("workflow definitions: AsyncDataLayer not initialized in backend mode");
|
|
85534
85580
|
}
|
|
85535
85581
|
const rows = await listWorkflowRows(layer);
|
|
85536
|
-
|
|
85537
|
-
return store.workflowDefinitionsCache;
|
|
85582
|
+
return [...BUILTIN_WORKFLOWS, ...rows.map((row) => store.toWorkflowDefinition(row))];
|
|
85538
85583
|
}
|
|
85539
85584
|
async function getWorkflowDefinitionImpl(store, id) {
|
|
85540
85585
|
const builtin = getBuiltinWorkflow(id);
|
|
@@ -85603,7 +85648,6 @@ function insertWorkflowDefinitionSyncImpl(store, input) {
|
|
|
85603
85648
|
if (!isWorkflowDefinitionIdPrimaryKeyCollision(error2)) throw error2;
|
|
85604
85649
|
continue;
|
|
85605
85650
|
}
|
|
85606
|
-
store.workflowDefinitionsCache = null;
|
|
85607
85651
|
return definition;
|
|
85608
85652
|
}
|
|
85609
85653
|
throw new Error("Unable to allocate a free workflow definition id after repeated id collisions");
|
|
@@ -85993,11 +86037,6 @@ function getPluginStoreImpl(store) {
|
|
|
85993
86037
|
...pluginLayer ? { asyncLayer: pluginLayer } : {}
|
|
85994
86038
|
}
|
|
85995
86039
|
);
|
|
85996
|
-
const clearWorkflowDefinitionCache = () => {
|
|
85997
|
-
store.workflowDefinitionsCache = null;
|
|
85998
|
-
};
|
|
85999
|
-
store.pluginStore.on("plugin:registered", clearWorkflowDefinitionCache);
|
|
86000
|
-
store.pluginStore.on("plugin:unregistered", clearWorkflowDefinitionCache);
|
|
86001
86040
|
}
|
|
86002
86041
|
return store.pluginStore;
|
|
86003
86042
|
}
|
|
@@ -90369,11 +90408,11 @@ async function searchWithQmd(rootDir, options) {
|
|
|
90369
90408
|
const command = "qmd";
|
|
90370
90409
|
const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
|
|
90371
90410
|
try {
|
|
90372
|
-
const
|
|
90373
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
90411
|
+
const execFileAsync37 = await getDefaultExecFileAsync();
|
|
90412
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync37);
|
|
90374
90413
|
scheduleQmdProjectMemoryRefresh(rootDir);
|
|
90375
90414
|
const args = buildQmdSearchArgs(rootDir, options);
|
|
90376
|
-
const { stdout } = await
|
|
90415
|
+
const { stdout } = await execFileAsync37(command, args, {
|
|
90377
90416
|
cwd: rootDir,
|
|
90378
90417
|
timeout: 4e3,
|
|
90379
90418
|
maxBuffer: 1024 * 1024
|
|
@@ -90398,12 +90437,12 @@ async function searchWithQmd(rootDir, options) {
|
|
|
90398
90437
|
return [];
|
|
90399
90438
|
}
|
|
90400
90439
|
}
|
|
90401
|
-
async function ensureQmdProjectMemoryCollection(rootDir,
|
|
90440
|
+
async function ensureQmdProjectMemoryCollection(rootDir, execFileAsync37) {
|
|
90402
90441
|
const collectionName = qmdMemoryCollectionName(rootDir);
|
|
90403
90442
|
const memoryDir = memoryWorkspacePath(rootDir);
|
|
90404
90443
|
await mkdir10(memoryDir, { recursive: true });
|
|
90405
90444
|
try {
|
|
90406
|
-
await
|
|
90445
|
+
await execFileAsync37("qmd", buildQmdCollectionAddArgs(rootDir), {
|
|
90407
90446
|
cwd: rootDir,
|
|
90408
90447
|
timeout: 4e3,
|
|
90409
90448
|
maxBuffer: 512 * 1024
|
|
@@ -90501,14 +90540,14 @@ async function refreshQmdProjectMemoryIndex(rootDir, options) {
|
|
|
90501
90540
|
}
|
|
90502
90541
|
}
|
|
90503
90542
|
const promise = (async () => {
|
|
90504
|
-
const
|
|
90505
|
-
await ensureQmdProjectMemoryCollection(rootDir,
|
|
90506
|
-
await
|
|
90543
|
+
const execFileAsync37 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
90544
|
+
await ensureQmdProjectMemoryCollection(rootDir, execFileAsync37);
|
|
90545
|
+
await execFileAsync37("qmd", ["update"], {
|
|
90507
90546
|
cwd: rootDir,
|
|
90508
90547
|
timeout: 3e4,
|
|
90509
90548
|
maxBuffer: 1024 * 1024
|
|
90510
90549
|
});
|
|
90511
|
-
await
|
|
90550
|
+
await execFileAsync37("qmd", ["embed"], {
|
|
90512
90551
|
cwd: rootDir,
|
|
90513
90552
|
timeout: 12e4,
|
|
90514
90553
|
maxBuffer: 1024 * 1024
|
|
@@ -90544,12 +90583,12 @@ async function refreshQmdAgentMemoryIndex(rootDir, agentId, options) {
|
|
|
90544
90583
|
}
|
|
90545
90584
|
}
|
|
90546
90585
|
const promise = (async () => {
|
|
90547
|
-
const
|
|
90586
|
+
const execFileAsync37 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
90548
90587
|
const { agentMemoryWorkspacePath: agentMemoryWorkspacePath2 } = await Promise.resolve().then(() => (init_memory_dreams(), memory_dreams_exports));
|
|
90549
90588
|
const workspacePath = agentMemoryWorkspacePath2(rootDir, agentId);
|
|
90550
90589
|
await mkdir10(workspacePath, { recursive: true });
|
|
90551
90590
|
try {
|
|
90552
|
-
await
|
|
90591
|
+
await execFileAsync37("qmd", ["collection", "add", workspacePath, "--name", qmdAgentMemoryCollectionName(rootDir, agentId), "--mask", "**/*.md"], {
|
|
90553
90592
|
cwd: rootDir,
|
|
90554
90593
|
timeout: 4e3,
|
|
90555
90594
|
maxBuffer: 512 * 1024
|
|
@@ -90562,8 +90601,8 @@ ${stderr}`)) {
|
|
|
90562
90601
|
throw err;
|
|
90563
90602
|
}
|
|
90564
90603
|
}
|
|
90565
|
-
await
|
|
90566
|
-
await
|
|
90604
|
+
await execFileAsync37("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
|
|
90605
|
+
await execFileAsync37("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
90567
90606
|
})();
|
|
90568
90607
|
qmdAgentRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
|
|
90569
90608
|
try {
|
|
@@ -90584,8 +90623,8 @@ function scheduleQmdAgentMemoryRefresh(rootDir, agentId) {
|
|
|
90584
90623
|
}
|
|
90585
90624
|
async function isQmdAvailable() {
|
|
90586
90625
|
try {
|
|
90587
|
-
const
|
|
90588
|
-
await
|
|
90626
|
+
const execFileAsync37 = await getDefaultExecFileAsync();
|
|
90627
|
+
await execFileAsync37("qmd", ["--help"], {
|
|
90589
90628
|
timeout: 3e3,
|
|
90590
90629
|
maxBuffer: 128 * 1024,
|
|
90591
90630
|
keepAlive: true
|
|
@@ -90596,12 +90635,12 @@ async function isQmdAvailable() {
|
|
|
90596
90635
|
}
|
|
90597
90636
|
}
|
|
90598
90637
|
async function installQmd(options) {
|
|
90599
|
-
const
|
|
90638
|
+
const execFileAsync37 = options?.execFileAsync ?? await getDefaultExecFileAsync();
|
|
90600
90639
|
const [command, ...args] = QMD_INSTALL_COMMAND.split(" ");
|
|
90601
90640
|
if (!command || args.length === 0) {
|
|
90602
90641
|
throw new MemoryBackendError("BACKEND_UNAVAILABLE", "qmd install command is not configured", "qmd");
|
|
90603
90642
|
}
|
|
90604
|
-
await
|
|
90643
|
+
await execFileAsync37(command, args, {
|
|
90605
90644
|
timeout: 12e4,
|
|
90606
90645
|
maxBuffer: 1024 * 1024
|
|
90607
90646
|
});
|
|
@@ -94978,7 +95017,7 @@ Your ONLY job is to create a concise title (max 60 characters) that summarizes t
|
|
|
94978
95017
|
|
|
94979
95018
|
## Style
|
|
94980
95019
|
- Clear, descriptive, actionable, professional
|
|
94981
|
-
- Write the title in the SAME language as the task description content.
|
|
95020
|
+
- Write the title in the SAME language as the task description content.
|
|
94982
95021
|
- Maximum 60 characters
|
|
94983
95022
|
- Focus on the main goal or deliverable of the task`;
|
|
94984
95023
|
MAX_DESCRIPTION_LENGTH = 2e3;
|
|
@@ -100116,7 +100155,6 @@ async function createWorkflowDefinitionImpl(store, input) {
|
|
|
100116
100155
|
if (!isWorkflowDefinitionIdPrimaryKeyCollision(error2)) throw error2;
|
|
100117
100156
|
continue;
|
|
100118
100157
|
}
|
|
100119
|
-
store.workflowDefinitionsCache = null;
|
|
100120
100158
|
return definition;
|
|
100121
100159
|
}
|
|
100122
100160
|
throw new Error("Unable to allocate a free workflow definition id after repeated id collisions");
|
|
@@ -103700,7 +103738,6 @@ async function updateWorkflowDefinitionImpl(store, id, updates) {
|
|
|
103700
103738
|
eq(project_exports.workflows.id, id),
|
|
103701
103739
|
projectScopeFor(project_exports.workflows.projectId, layer.projectId)
|
|
103702
103740
|
));
|
|
103703
|
-
store.workflowDefinitionsCache = null;
|
|
103704
103741
|
return next;
|
|
103705
103742
|
});
|
|
103706
103743
|
if (pendingRehome) {
|
|
@@ -103735,7 +103772,6 @@ async function deleteWorkflowDefinitionImpl(store, id) {
|
|
|
103735
103772
|
projectScopeFor(project_exports.workflows.projectId, layer.projectId)
|
|
103736
103773
|
)).returning();
|
|
103737
103774
|
if (deleted.length === 0) throw new Error(`Workflow '${id}' not found`);
|
|
103738
|
-
store.workflowDefinitionsCache = null;
|
|
103739
103775
|
await layer.db.delete(project_exports.workflowSettings).where(and(
|
|
103740
103776
|
eq(project_exports.workflowSettings.workflowId, id),
|
|
103741
103777
|
projectScopeFor(project_exports.workflowSettings.projectId, layer.projectId)
|
|
@@ -108329,7 +108365,6 @@ var init_store = __esm({
|
|
|
108329
108365
|
taskIdIntegrityReport = { status: "ok", checkedAt: (/* @__PURE__ */ new Date()).toISOString(), anomalies: [] };
|
|
108330
108366
|
lastTaskIdIntegrityLogSignature = null;
|
|
108331
108367
|
workflowStepsCache = null;
|
|
108332
|
-
workflowDefinitionsCache = null;
|
|
108333
108368
|
_pluginWorkflowStepTemplates = [];
|
|
108334
108369
|
globalSettingsStore;
|
|
108335
108370
|
donePauseBackfillDone = false;
|
|
@@ -115959,7 +115994,7 @@ function getPostMergeFinalizeBlocker(task) {
|
|
|
115959
115994
|
}
|
|
115960
115995
|
function planConfirmedMergeChecklistReconciliation(task) {
|
|
115961
115996
|
return {
|
|
115962
|
-
skippedStepIndexes: task.steps.map((step, index2) => step.status === "pending" || step.status === "in-progress" ? index2 : -1).filter((index2) => index2 >= 0),
|
|
115997
|
+
skippedStepIndexes: (task.steps ?? []).map((step, index2) => step.status === "pending" || step.status === "in-progress" ? index2 : -1).filter((index2) => index2 >= 0),
|
|
115963
115998
|
reconciledWorkflowStepIds: (task.workflowStepResults ?? []).filter((result) => result.status === "pending").map((result) => result.workflowStepId)
|
|
115964
115999
|
};
|
|
115965
116000
|
}
|
|
@@ -136009,11 +136044,11 @@ var require_extract_zip = __commonJS({
|
|
|
136009
136044
|
var { createWriteStream, promises: fs10 } = __require("fs");
|
|
136010
136045
|
var getStream = require_get_stream();
|
|
136011
136046
|
var path6 = __require("path");
|
|
136012
|
-
var { promisify:
|
|
136047
|
+
var { promisify: promisify91 } = __require("util");
|
|
136013
136048
|
var stream = __require("stream");
|
|
136014
136049
|
var yauzl = require_yauzl();
|
|
136015
|
-
var openZip =
|
|
136016
|
-
var pipeline =
|
|
136050
|
+
var openZip = promisify91(yauzl.open);
|
|
136051
|
+
var pipeline = promisify91(stream.pipeline);
|
|
136017
136052
|
var Extractor = class {
|
|
136018
136053
|
constructor(zipPath, opts) {
|
|
136019
136054
|
this.zipPath = zipPath;
|
|
@@ -136095,7 +136130,7 @@ var require_extract_zip = __commonJS({
|
|
|
136095
136130
|
await fs10.mkdir(destDir, mkdirOptions);
|
|
136096
136131
|
if (isDir) return;
|
|
136097
136132
|
debug("opening read stream", dest);
|
|
136098
|
-
const readStream = await
|
|
136133
|
+
const readStream = await promisify91(this.zipfile.openReadStream.bind(this.zipfile))(entry);
|
|
136099
136134
|
if (symlink) {
|
|
136100
136135
|
const link = await getStream(readStream);
|
|
136101
136136
|
debug("creating symlink", link, dest);
|
|
@@ -137534,6 +137569,7 @@ async function updateChatSession(handle2, id, input) {
|
|
|
137534
137569
|
if (input.status !== void 0) setValues.status = input.status;
|
|
137535
137570
|
if (input.modelProvider !== void 0) setValues.modelProvider = input.modelProvider;
|
|
137536
137571
|
if (input.modelId !== void 0) setValues.modelId = input.modelId;
|
|
137572
|
+
if (input.agentId !== void 0) setValues.agentId = input.agentId;
|
|
137537
137573
|
if (input.thinkingLevel !== void 0) setValues.thinkingLevel = input.thinkingLevel;
|
|
137538
137574
|
if (input.memoryFocus !== void 0) setValues.memoryFocus = input.memoryFocus;
|
|
137539
137575
|
if (input.pinnedAt !== void 0) setValues.pinnedAt = input.pinnedAt;
|
|
@@ -138587,6 +138623,7 @@ var init_cli_session_store = __esm({
|
|
|
138587
138623
|
});
|
|
138588
138624
|
|
|
138589
138625
|
// ../core/src/secrets/oauth-credential-interop.ts
|
|
138626
|
+
import { createHash as createHash22 } from "node:crypto";
|
|
138590
138627
|
import { existsSync as existsSync40, readFileSync as readFileSync11 } from "node:fs";
|
|
138591
138628
|
import { homedir as homedir7 } from "node:os";
|
|
138592
138629
|
import { join as join55 } from "node:path";
|
|
@@ -138646,6 +138683,22 @@ function getLastRefreshFallbackExpiryMs(lastRefresh) {
|
|
|
138646
138683
|
}
|
|
138647
138684
|
return parsed + CODEX_REFRESH_FALLBACK_WINDOW_MS;
|
|
138648
138685
|
}
|
|
138686
|
+
function isSameStoredCredentialMaterial(left, right) {
|
|
138687
|
+
if (!left || !right || left.type !== right.type) {
|
|
138688
|
+
return false;
|
|
138689
|
+
}
|
|
138690
|
+
return left.key === right.key && left.access === right.access && left.refresh === right.refresh;
|
|
138691
|
+
}
|
|
138692
|
+
function computeStoredCredentialAccountFingerprint(credential) {
|
|
138693
|
+
if (!credential) {
|
|
138694
|
+
return void 0;
|
|
138695
|
+
}
|
|
138696
|
+
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;
|
|
138697
|
+
if (!material) {
|
|
138698
|
+
return void 0;
|
|
138699
|
+
}
|
|
138700
|
+
return createHash22("sha256").update(`${credential.type ?? ""}\0${material}`).digest("hex").slice(0, 16);
|
|
138701
|
+
}
|
|
138649
138702
|
function isStoredAuthCredential(value) {
|
|
138650
138703
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
138651
138704
|
return false;
|
|
@@ -139616,7 +139669,7 @@ var init_task_timing = __esm({
|
|
|
139616
139669
|
});
|
|
139617
139670
|
|
|
139618
139671
|
// ../core/src/task-recommendation-notice.ts
|
|
139619
|
-
import { createHash as
|
|
139672
|
+
import { createHash as createHash23 } from "node:crypto";
|
|
139620
139673
|
function registerTaskRecommendationNoticeMailbox(store, mailbox) {
|
|
139621
139674
|
mailboxes2.set(store, mailbox);
|
|
139622
139675
|
return () => {
|
|
@@ -139641,7 +139694,7 @@ function buildTaskRecommendationNoticeContent(task, recommendations) {
|
|
|
139641
139694
|
}
|
|
139642
139695
|
function buildTaskRecommendationNoticeIdempotencyKey(taskId, recommendations) {
|
|
139643
139696
|
const ids = recommendations.map(({ id }) => id).sort().join("\n");
|
|
139644
|
-
const digest =
|
|
139697
|
+
const digest = createHash23("sha256").update(ids, "utf8").digest("hex").slice(0, 16);
|
|
139645
139698
|
return `task-recommendation-notice:${taskId}:${digest}`;
|
|
139646
139699
|
}
|
|
139647
139700
|
async function notifyOperatorOfTaskRecommendations(store, task, recommendations, settings) {
|
|
@@ -140087,6 +140140,7 @@ __export(src_exports, {
|
|
|
140087
140140
|
APPROVAL_REQUEST_STATUSES: () => APPROVAL_REQUEST_STATUSES,
|
|
140088
140141
|
ARCHIVED_TASK_DOCUMENT_ADDITION_BOUNDARY: () => ARCHIVED_TASK_DOCUMENT_ADDITION_BOUNDARY,
|
|
140089
140142
|
ARCHIVED_TASK_DOCUMENT_PUBLICATION_REJECTED: () => ARCHIVED_TASK_DOCUMENT_PUBLICATION_REJECTED,
|
|
140143
|
+
AUTOMATED_BYPASS_ACTORS: () => AUTOMATED_BYPASS_ACTORS,
|
|
140090
140144
|
AUTOMATION_PRESETS: () => AUTOMATION_PRESETS,
|
|
140091
140145
|
AUTOMATION_SELECTABLE_TOOLS: () => AUTOMATION_SELECTABLE_TOOLS,
|
|
140092
140146
|
AUTOPILOT_STATES: () => AUTOPILOT_STATES,
|
|
@@ -140282,6 +140336,7 @@ __export(src_exports, {
|
|
|
140282
140336
|
FAST_LANE_SKIP_VALUE: () => FAST_LANE_SKIP_VALUE,
|
|
140283
140337
|
FAST_LANE_STEP_NAME: () => FAST_LANE_STEP_NAME,
|
|
140284
140338
|
FAST_LANE_STEP_REVIEW_ROUTE_VALUE: () => FAST_LANE_STEP_REVIEW_ROUTE_VALUE,
|
|
140339
|
+
FAST_MODE_BYPASS_ACTOR: () => FAST_MODE_BYPASS_ACTOR,
|
|
140285
140340
|
FEATURE_LOOP_REPAIR_TRANSITIONS: () => FEATURE_LOOP_REPAIR_TRANSITIONS,
|
|
140286
140341
|
FEATURE_LOOP_STATES: () => FEATURE_LOOP_STATES,
|
|
140287
140342
|
FEATURE_STATUSES: () => FEATURE_STATUSES,
|
|
@@ -140846,6 +140901,7 @@ __export(src_exports, {
|
|
|
140846
140901
|
computeRetrySummary: () => computeRetrySummary,
|
|
140847
140902
|
computeSkillId: () => computeSkillId,
|
|
140848
140903
|
computeSnapshotChecksum: () => computeSnapshotChecksum,
|
|
140904
|
+
computeStoredCredentialAccountFingerprint: () => computeStoredCredentialAccountFingerprint,
|
|
140849
140905
|
computeWorkflowIrPin: () => computeWorkflowIrPin,
|
|
140850
140906
|
configurationTargetKey: () => configurationTargetKey,
|
|
140851
140907
|
configureApprovalRequestTtls: () => configureApprovalRequestTtls,
|
|
@@ -141168,6 +141224,7 @@ __export(src_exports, {
|
|
|
141168
141224
|
isApprovalRequestExpired: () => isApprovalRequestExpired,
|
|
141169
141225
|
isArchivedColumnRole: () => isArchivedColumnRole,
|
|
141170
141226
|
isArchivedRemediationCarrier: () => isArchivedRemediationCarrier,
|
|
141227
|
+
isAuditedOperatorBypass: () => isAuditedOperatorBypass,
|
|
141171
141228
|
isBlockingFinding: () => isBlockingFinding,
|
|
141172
141229
|
isBranchGroupComplete: () => isBranchGroupComplete,
|
|
141173
141230
|
isBranchGroupMemberLanded: () => isBranchGroupMemberLanded,
|
|
@@ -141255,6 +141312,7 @@ __export(src_exports, {
|
|
|
141255
141312
|
isReviewColumnRole: () => isReviewColumnRole,
|
|
141256
141313
|
isRunRecord: () => isRunRecord,
|
|
141257
141314
|
isRunningAgentTask: () => isRunningAgentTask,
|
|
141315
|
+
isSameStoredCredentialMaterial: () => isSameStoredCredentialMaterial,
|
|
141258
141316
|
isSanctionedEngineBackwardMove: () => isSanctionedEngineBackwardMove,
|
|
141259
141317
|
isSandboxExperimentalEnabled: () => isSandboxExperimentalEnabled,
|
|
141260
141318
|
isSecretAccessPolicy: () => isSecretAccessPolicy,
|
|
@@ -141533,6 +141591,7 @@ __export(src_exports, {
|
|
|
141533
141591
|
renderTriagePolicyPlaceholders: () => renderTriagePolicyPlaceholders,
|
|
141534
141592
|
renderValidationCause: () => renderValidationCause,
|
|
141535
141593
|
renderValidationFailureDescription: () => renderValidationFailureDescription,
|
|
141594
|
+
requiresContentReviewProof: () => requiresContentReviewProof,
|
|
141536
141595
|
requiresPlannerConfirmation: () => requiresPlannerConfirmation,
|
|
141537
141596
|
requiresWorktrunkInstallVerification: () => requiresWorktrunkInstallVerification,
|
|
141538
141597
|
resetGhAvailabilityCache: () => resetGhAvailabilityCache,
|
|
@@ -141696,6 +141755,7 @@ __export(src_exports, {
|
|
|
141696
141755
|
resolveTitleSummarizerSettingsModel: () => resolveTitleSummarizerSettingsModel,
|
|
141697
141756
|
resolveToolOutputBudget: () => resolveToolOutputBudget,
|
|
141698
141757
|
resolveTrailingVerificationStepIndex: () => resolveTrailingVerificationStepIndex,
|
|
141758
|
+
resolveUnprovenReviewApproval: () => resolveUnprovenReviewApproval,
|
|
141699
141759
|
resolveUpdateAutomationSettings: () => resolveUpdateAutomationSettings,
|
|
141700
141760
|
resolveUpdateTargetVersion: () => resolveUpdateTargetVersion,
|
|
141701
141761
|
resolveUpdatesExternallyManaged: () => resolveUpdatesExternallyManaged,
|
|
@@ -145177,18 +145237,25 @@ function parseWorktreesFromPorcelain(porcelain) {
|
|
|
145177
145237
|
if (current.path) rows.push({ path: current.path, branch: current.branch });
|
|
145178
145238
|
return rows;
|
|
145179
145239
|
}
|
|
145240
|
+
function isRegenerableIgnoredPorcelainEntry(entry) {
|
|
145241
|
+
const path6 = entry.slice(3).replace(/\/$/, "");
|
|
145242
|
+
if (!path6 || path6.startsWith('"')) return false;
|
|
145243
|
+
const lastSegment = path6.split("/").at(-1);
|
|
145244
|
+
return lastSegment !== void 0 && REGENERABLE_IGNORED_DIR_NAMES.has(lastSegment);
|
|
145245
|
+
}
|
|
145180
145246
|
function classifyWorktreeRemovalContent(porcelain) {
|
|
145181
145247
|
const entries = porcelain.split(/\r?\n/).filter((line2) => line2.trim().length > 0);
|
|
145182
145248
|
if (entries.length === 0) return "clean";
|
|
145183
|
-
|
|
145249
|
+
if (entries.some((line2) => !line2.startsWith("!! "))) return "deliverable";
|
|
145250
|
+
return entries.every(isRegenerableIgnoredPorcelainEntry) ? "regenerable-ignored" : "ignored-only";
|
|
145184
145251
|
}
|
|
145185
145252
|
async function assertCleanForDefensiveRemoval(worktreePath) {
|
|
145186
145253
|
if (!existsSync42(worktreePath)) {
|
|
145187
|
-
return "clean";
|
|
145254
|
+
return { classification: "clean", entryCount: 0 };
|
|
145188
145255
|
}
|
|
145189
145256
|
let stdout;
|
|
145190
145257
|
try {
|
|
145191
|
-
({ stdout } = await execFileAsync7("git", ["status", "--porcelain=v1", "--ignored", "--untracked-files=normal"], {
|
|
145258
|
+
({ stdout } = await execFileAsync7("git", ["status", "--porcelain=v1", "--ignored=matching", "--untracked-files=normal"], {
|
|
145192
145259
|
cwd: worktreePath,
|
|
145193
145260
|
encoding: "utf-8",
|
|
145194
145261
|
timeout: 15e3,
|
|
@@ -145201,7 +145268,10 @@ async function assertCleanForDefensiveRemoval(worktreePath) {
|
|
|
145201
145268
|
if (classification === "deliverable") {
|
|
145202
145269
|
throw new Error(`preserving ${worktreePath}: uncommitted or ignored content present`);
|
|
145203
145270
|
}
|
|
145204
|
-
return
|
|
145271
|
+
return {
|
|
145272
|
+
classification,
|
|
145273
|
+
entryCount: stdout.split(/\r?\n/).filter((line2) => line2.trim().length > 0).length
|
|
145274
|
+
};
|
|
145205
145275
|
}
|
|
145206
145276
|
async function removeWorktree(input) {
|
|
145207
145277
|
const logger3 = {
|
|
@@ -145218,9 +145288,12 @@ async function removeWorktree(input) {
|
|
|
145218
145288
|
}
|
|
145219
145289
|
const requiresCleanWorktree = DEFENSIVE_REMOVAL_REASONS.has(input.reason);
|
|
145220
145290
|
let contentClassification;
|
|
145291
|
+
let contentEntryCount = 0;
|
|
145221
145292
|
if (requiresCleanWorktree) {
|
|
145222
145293
|
try {
|
|
145223
|
-
|
|
145294
|
+
const contentProbe = await assertCleanForDefensiveRemoval(input.worktreePath);
|
|
145295
|
+
contentClassification = contentProbe.classification;
|
|
145296
|
+
contentEntryCount = contentProbe.entryCount;
|
|
145224
145297
|
} catch (error2) {
|
|
145225
145298
|
const classification = error2 instanceof Error && error2.message.includes(": status probe failed (") ? "unverifiable" : "deliverable";
|
|
145226
145299
|
await input.audit?.git({
|
|
@@ -145237,6 +145310,17 @@ async function removeWorktree(input) {
|
|
|
145237
145310
|
throw error2;
|
|
145238
145311
|
}
|
|
145239
145312
|
if (contentClassification === "ignored-only" && !input.postLandingProof) {
|
|
145313
|
+
await input.audit?.git({
|
|
145314
|
+
type: "worktree:removal-preserved",
|
|
145315
|
+
target: input.worktreePath,
|
|
145316
|
+
metadata: {
|
|
145317
|
+
taskId: input.taskId,
|
|
145318
|
+
reason: input.reason,
|
|
145319
|
+
source: void 0,
|
|
145320
|
+
classification: "ignored-only",
|
|
145321
|
+
hasPostLandingProof: false
|
|
145322
|
+
}
|
|
145323
|
+
}).catch(() => void 0);
|
|
145240
145324
|
throw new Error(`preserving ${input.worktreePath}: uncommitted or ignored content present`);
|
|
145241
145325
|
}
|
|
145242
145326
|
}
|
|
@@ -145256,6 +145340,17 @@ async function removeWorktree(input) {
|
|
|
145256
145340
|
} catch {
|
|
145257
145341
|
}
|
|
145258
145342
|
};
|
|
145343
|
+
const recordRegenerableDiscard = async () => {
|
|
145344
|
+
if (contentClassification !== "regenerable-ignored") return;
|
|
145345
|
+
try {
|
|
145346
|
+
await input.audit?.git({
|
|
145347
|
+
type: "worktree:removal-discarded-regenerable-content",
|
|
145348
|
+
target: input.worktreePath,
|
|
145349
|
+
metadata: { taskId: input.taskId, reason: input.reason, entryCount: contentEntryCount }
|
|
145350
|
+
});
|
|
145351
|
+
} catch {
|
|
145352
|
+
}
|
|
145353
|
+
};
|
|
145259
145354
|
if (input.expectedOwnerTaskId && input.liveOwnerProbe) {
|
|
145260
145355
|
const reconciled = reconcileSelfOwnedActiveSessionForRemoval(
|
|
145261
145356
|
activeSessionRegistry,
|
|
@@ -145309,6 +145404,7 @@ async function removeWorktree(input) {
|
|
|
145309
145404
|
try {
|
|
145310
145405
|
await backend.remove(removeInput);
|
|
145311
145406
|
await recordIgnoredOnlyDiscard();
|
|
145407
|
+
await recordRegenerableDiscard();
|
|
145312
145408
|
if (input.audit) {
|
|
145313
145409
|
await input.audit.git({
|
|
145314
145410
|
type: backend.kind === "worktrunk" ? "worktree:worktrunk-remove" : "worktree:remove",
|
|
@@ -145336,6 +145432,7 @@ async function removeWorktree(input) {
|
|
|
145336
145432
|
try {
|
|
145337
145433
|
await native.remove(removeInput);
|
|
145338
145434
|
await recordIgnoredOnlyDiscard();
|
|
145435
|
+
await recordRegenerableDiscard();
|
|
145339
145436
|
await input.audit?.git({ type: "worktree:remove", target: input.worktreePath });
|
|
145340
145437
|
return { removed: true, classification: "removed" };
|
|
145341
145438
|
} catch (nativeError) {
|
|
@@ -145357,7 +145454,7 @@ function resolveWorktreeBackend(settings, deps = {}) {
|
|
|
145357
145454
|
}
|
|
145358
145455
|
return new NativeWorktreeBackend({ logger: deps.logger, settings, audit: deps.audit });
|
|
145359
145456
|
}
|
|
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;
|
|
145457
|
+
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
145458
|
var init_worktree_backend = __esm({
|
|
145362
145459
|
"../engine/src/worktree/worktree-backend.ts"() {
|
|
145363
145460
|
"use strict";
|
|
@@ -146097,6 +146194,27 @@ ${getErrorStderr(error2) ?? ""}`;
|
|
|
146097
146194
|
this.name = "ActiveSessionWorktreeRemovalError";
|
|
146098
146195
|
}
|
|
146099
146196
|
};
|
|
146197
|
+
REGENERABLE_IGNORED_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
146198
|
+
"node_modules",
|
|
146199
|
+
"dist",
|
|
146200
|
+
"build",
|
|
146201
|
+
"out",
|
|
146202
|
+
"target",
|
|
146203
|
+
"bin",
|
|
146204
|
+
"obj",
|
|
146205
|
+
"coverage",
|
|
146206
|
+
".next",
|
|
146207
|
+
".nuxt",
|
|
146208
|
+
".turbo",
|
|
146209
|
+
".svelte-kit",
|
|
146210
|
+
".parcel-cache",
|
|
146211
|
+
".pytest_cache",
|
|
146212
|
+
".mypy_cache",
|
|
146213
|
+
"__pycache__",
|
|
146214
|
+
".gradle",
|
|
146215
|
+
".venv",
|
|
146216
|
+
"venv"
|
|
146217
|
+
]);
|
|
146100
146218
|
}
|
|
146101
146219
|
});
|
|
146102
146220
|
|
|
@@ -146718,6 +146836,14 @@ function resolveAiMergeRootPath(rootDir, settings) {
|
|
|
146718
146836
|
function resolveLegacyAiMergeRootPath(rootDir) {
|
|
146719
146837
|
return join59(rootDir, ".fusion", "ai-merge");
|
|
146720
146838
|
}
|
|
146839
|
+
function resolveAiMergeSearchRoots(rootDir, settings) {
|
|
146840
|
+
const roots = [
|
|
146841
|
+
resolveAiMergeRootPath(rootDir, settings),
|
|
146842
|
+
resolveLegacyAiMergeRootPath(rootDir),
|
|
146843
|
+
...settings?.worktreesDir ? [] : [join59(resolveLegacyWorktreesDirLayout(rootDir), AI_MERGE_DIRNAME)]
|
|
146844
|
+
];
|
|
146845
|
+
return [...new Set(roots)];
|
|
146846
|
+
}
|
|
146721
146847
|
function resolveWorktreesDir(rootDir, settings, workspaceContext) {
|
|
146722
146848
|
return resolveWorktreesDirLayout(rootDir, settings, workspaceContext);
|
|
146723
146849
|
}
|
|
@@ -148194,7 +148320,7 @@ var init_plan_review_continuation = __esm({
|
|
|
148194
148320
|
});
|
|
148195
148321
|
|
|
148196
148322
|
// ../engine/src/execution/hold-release.ts
|
|
148197
|
-
import { createHash as
|
|
148323
|
+
import { createHash as createHash25 } from "node:crypto";
|
|
148198
148324
|
import { readFile as readFile36 } from "node:fs/promises";
|
|
148199
148325
|
function findColumn2(ir2, columnId) {
|
|
148200
148326
|
if (ir2.version !== "v2") return void 0;
|
|
@@ -148232,9 +148358,9 @@ async function checkAndRecordUnplannedExecutionBlock(store, task, ir2) {
|
|
|
148232
148358
|
promptContent = "";
|
|
148233
148359
|
}
|
|
148234
148360
|
}
|
|
148235
|
-
const promptMarker = promptContent.length > 0 ?
|
|
148361
|
+
const promptMarker = promptContent.length > 0 ? createHash25("sha256").update(promptContent).digest("hex") : "missing";
|
|
148236
148362
|
const dependencies = [...task.dependencies ?? []].sort();
|
|
148237
|
-
const episode =
|
|
148363
|
+
const episode = createHash25("sha256").update(JSON.stringify({
|
|
148238
148364
|
planReviewNode,
|
|
148239
148365
|
promptMarker,
|
|
148240
148366
|
dependencies,
|
|
@@ -153237,6 +153363,15 @@ async function withOAuthRefreshLock(authPath, providerId, refresh) {
|
|
|
153237
153363
|
await release3();
|
|
153238
153364
|
}
|
|
153239
153365
|
}
|
|
153366
|
+
async function withOAuthInstanceLoginLock(authPath, providerId, operation) {
|
|
153367
|
+
const safeProviderId = providerId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
153368
|
+
const release3 = await import_proper_lockfile.default.lock(`${authPath}.${safeProviderId}.instance-login`, AUTH_LOCK_OPTIONS);
|
|
153369
|
+
try {
|
|
153370
|
+
return await operation();
|
|
153371
|
+
} finally {
|
|
153372
|
+
await release3();
|
|
153373
|
+
}
|
|
153374
|
+
}
|
|
153240
153375
|
function readDefaultInstanceMap(data) {
|
|
153241
153376
|
const candidate = data.__fusionDefaultInstances;
|
|
153242
153377
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return {};
|
|
@@ -153526,7 +153661,7 @@ function createFusionAuthStorage() {
|
|
|
153526
153661
|
primary.reload();
|
|
153527
153662
|
const selectPersistedRefreshCredential = () => {
|
|
153528
153663
|
const storedCredential = primary.get(storageProvider);
|
|
153529
|
-
if (refreshLockProvider !== ANTHROPIC_PROVIDER_ID2) {
|
|
153664
|
+
if (storedCredential?.type === "oauth" || refreshLockProvider !== ANTHROPIC_PROVIDER_ID2) {
|
|
153530
153665
|
return storedCredential;
|
|
153531
153666
|
}
|
|
153532
153667
|
const legacyCredential = primary.get(ANTHROPIC_PROVIDER_ID2);
|
|
@@ -153656,18 +153791,16 @@ function createFusionAuthStorage() {
|
|
|
153656
153791
|
if (rawKey) return rawKey;
|
|
153657
153792
|
}
|
|
153658
153793
|
const subscriptionLoggedOut = loggedOutProviders.has(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153659
|
-
const
|
|
153794
|
+
const subscriptionCredential = subscriptionLoggedOut ? void 0 : selectStoredCredential(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153795
|
+
if (subscriptionCredential?.type === "oauth") {
|
|
153796
|
+
const subscriptionKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
|
|
153797
|
+
if (subscriptionKey) return subscriptionKey;
|
|
153798
|
+
}
|
|
153799
|
+
const legacyAnthropicOAuthCredential = rawProviderLoggedOut || subscriptionCredential ? void 0 : selectStoredCredentialByType(ANTHROPIC_PROVIDER_ID2, "oauth");
|
|
153660
153800
|
if (!subscriptionLoggedOut && legacyAnthropicOAuthCredential) {
|
|
153661
153801
|
const legacyKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_PROVIDER_ID2, legacyAnthropicOAuthCredential);
|
|
153662
153802
|
if (legacyKey) return legacyKey;
|
|
153663
153803
|
}
|
|
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
153804
|
if (preferSubscription) {
|
|
153672
153805
|
const rawKey = resolveRawApiKey();
|
|
153673
153806
|
if (rawKey) return rawKey;
|
|
@@ -153844,8 +153977,15 @@ function createFusionAuthStorage() {
|
|
|
153844
153977
|
return void 0;
|
|
153845
153978
|
}
|
|
153846
153979
|
if (sourceProvider !== ANTHROPIC_SUBSCRIPTION_PROVIDER_ID) {
|
|
153847
|
-
await
|
|
153848
|
-
|
|
153980
|
+
const legacyKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_PROVIDER_ID2, subscriptionCredential);
|
|
153981
|
+
primary.reload();
|
|
153982
|
+
const storedSubscription = primary.get(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153983
|
+
const refreshedLegacyCredential = primary.get(ANTHROPIC_PROVIDER_ID2);
|
|
153984
|
+
if (!storedSubscription && refreshedLegacyCredential?.type === "oauth") {
|
|
153985
|
+
await primary.set(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, refreshedLegacyCredential);
|
|
153986
|
+
loggedOutProviders.delete(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
|
|
153987
|
+
}
|
|
153988
|
+
return legacyKey;
|
|
153849
153989
|
}
|
|
153850
153990
|
return resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
|
|
153851
153991
|
}
|
|
@@ -153890,6 +154030,9 @@ var init_auth_storage = __esm({
|
|
|
153890
154030
|
}
|
|
153891
154031
|
data = {};
|
|
153892
154032
|
modelRuntime;
|
|
154033
|
+
async withProviderInstanceLoginLock(providerId, operation) {
|
|
154034
|
+
return withOAuthInstanceLoginLock(this.authPath, providerId, operation);
|
|
154035
|
+
}
|
|
153893
154036
|
ensureFile() {
|
|
153894
154037
|
const parent = dirname27(this.authPath);
|
|
153895
154038
|
if (!existsSync47(parent)) mkdirSync7(parent, { recursive: true, mode: 448 });
|
|
@@ -154596,7 +154739,7 @@ var init_gating_classifications = __esm({
|
|
|
154596
154739
|
});
|
|
154597
154740
|
|
|
154598
154741
|
// ../engine/src/agents/agent-action-gate.ts
|
|
154599
|
-
import { createHash as
|
|
154742
|
+
import { createHash as createHash26 } from "node:crypto";
|
|
154600
154743
|
function getExemptTools() {
|
|
154601
154744
|
if (!_exemptTools) {
|
|
154602
154745
|
_exemptTools = new Set(DEFAULT_EXEMPT_TOOLS);
|
|
@@ -154630,7 +154773,7 @@ function evaluateAgentActionGate(params) {
|
|
|
154630
154773
|
if (params.toolName === "bash") {
|
|
154631
154774
|
const command = extractShellCommand(args);
|
|
154632
154775
|
const git10 = classifyGitCommand(command);
|
|
154633
|
-
resourceId = command ? `cmd:${
|
|
154776
|
+
resourceId = command ? `cmd:${createHash26("sha256").update(command).digest("hex").slice(0, 16)}` : void 0;
|
|
154634
154777
|
if (git10?.write) {
|
|
154635
154778
|
category = "git_write";
|
|
154636
154779
|
operation = git10.operation;
|
|
@@ -176496,6 +176639,7 @@ async function connectMcpSessionTools(servers, opts = {}) {
|
|
|
176496
176639
|
const clients = [];
|
|
176497
176640
|
const closedClients = /* @__PURE__ */ new WeakSet();
|
|
176498
176641
|
const usedToolNames = /* @__PURE__ */ new Set();
|
|
176642
|
+
const serverByToolName = /* @__PURE__ */ new Map();
|
|
176499
176643
|
let disposed = false;
|
|
176500
176644
|
const closeOnce = async (client) => {
|
|
176501
176645
|
if (closedClients.has(client)) return;
|
|
@@ -176545,7 +176689,9 @@ async function connectMcpSessionTools(servers, opts = {}) {
|
|
|
176545
176689
|
opts.logger?.log?.(connectMsg);
|
|
176546
176690
|
}
|
|
176547
176691
|
for (const tool of listedTools) {
|
|
176548
|
-
|
|
176692
|
+
const wrappedTool = wrapMcpTool(server.name, tool, client, usedToolNames);
|
|
176693
|
+
tools.push(wrappedTool);
|
|
176694
|
+
serverByToolName.set(wrappedTool.name, server.name);
|
|
176549
176695
|
}
|
|
176550
176696
|
break;
|
|
176551
176697
|
} catch (error2) {
|
|
@@ -176572,7 +176718,7 @@ async function connectMcpSessionTools(servers, opts = {}) {
|
|
|
176572
176718
|
await closeAll();
|
|
176573
176719
|
}
|
|
176574
176720
|
}
|
|
176575
|
-
return { tools, connected, skipped, dispose: closeAll };
|
|
176721
|
+
return { tools, connected, skipped, serverByToolName, dispose: closeAll };
|
|
176576
176722
|
}
|
|
176577
176723
|
function normalizeMaxAttempts(value) {
|
|
176578
176724
|
if (value === void 0 || !Number.isFinite(value)) return DEFAULT_MAX_ATTEMPTS;
|
|
@@ -179706,8 +179852,10 @@ async function createPiAgentSessionRaw(options) {
|
|
|
179706
179852
|
const createSessionWithModel = async (modelOverride) => {
|
|
179707
179853
|
let mcpToolset;
|
|
179708
179854
|
const allowReadonlyMcpTools = options.allowMcpToolsInReadonly === true;
|
|
179709
|
-
|
|
179710
|
-
|
|
179855
|
+
const readonlyMcpServerAllowlist = options.readonlyMcpServerAllowlist === void 0 ? void 0 : new Set(options.readonlyMcpServerAllowlist.map((name2) => name2.trim()).filter(Boolean));
|
|
179856
|
+
const mcpServersToConnect = isReadonly && allowReadonlyMcpTools && readonlyMcpServerAllowlist !== void 0 ? forwardedMcpServers.filter((server) => readonlyMcpServerAllowlist.has(server.name)) : forwardedMcpServers;
|
|
179857
|
+
if (mcpServersToConnect.length > 0 && (!isReadonly || allowReadonlyMcpTools)) {
|
|
179858
|
+
mcpToolset = await connectMcpSessionTools(mcpServersToConnect, {
|
|
179711
179859
|
cwd: options.cwd,
|
|
179712
179860
|
clientFactory: options.mcpClientFactory,
|
|
179713
179861
|
logger: piLog,
|
|
@@ -179718,7 +179866,8 @@ async function createPiAgentSessionRaw(options) {
|
|
|
179718
179866
|
piLog.warn(`MCP session continuing with unavailable servers: count=${bootstrapFailures.length}`);
|
|
179719
179867
|
}
|
|
179720
179868
|
} else if (forwardedMcpServers.length > 0 && isReadonly) {
|
|
179721
|
-
|
|
179869
|
+
const reason = !allowReadonlyMcpTools ? "no-readonly-opt-in" : "readonly-allowlist-no-match";
|
|
179870
|
+
piLog.log(`readonly session \u2014 MCP servers (${forwardedMcpServers.length}) skipped: reason=${reason}`);
|
|
179722
179871
|
}
|
|
179723
179872
|
const mcpReadonlyTools = new Set(mcpToolset?.tools ?? []);
|
|
179724
179873
|
const candidateCustomTools = [
|
|
@@ -179727,7 +179876,9 @@ async function createPiAgentSessionRaw(options) {
|
|
|
179727
179876
|
];
|
|
179728
179877
|
const readonlyFilteredCustomTools = isReadonly ? filterCustomToolsForReadonly(
|
|
179729
179878
|
candidateCustomTools,
|
|
179730
|
-
allowReadonlyMcpTools ? {
|
|
179879
|
+
allowReadonlyMcpTools ? {
|
|
179880
|
+
allowTool: (tool) => readonlyMcpServerAllowlist === void 0 ? mcpReadonlyTools.has(tool) : readonlyMcpServerAllowlist.has(mcpToolset?.serverByToolName?.get(tool.name) ?? "")
|
|
179881
|
+
} : {}
|
|
179731
179882
|
) : { allowed: candidateCustomTools, denied: [] };
|
|
179732
179883
|
const allowlistFilteredCustomTools = {
|
|
179733
179884
|
...readonlyFilteredCustomTools,
|
|
@@ -180197,7 +180348,7 @@ var init_pi = __esm({
|
|
|
180197
180348
|
});
|
|
180198
180349
|
|
|
180199
180350
|
// ../engine/src/agents/agent-logger.ts
|
|
180200
|
-
import { createHash as
|
|
180351
|
+
import { createHash as createHash27 } from "node:crypto";
|
|
180201
180352
|
function truncateToolResultDetail(value) {
|
|
180202
180353
|
if (value.length <= TOOL_RESULT_DETAIL_LIMIT) return value;
|
|
180203
180354
|
return `${value.slice(0, TOOL_RESULT_DETAIL_LIMIT)}${TOOL_RESULT_DETAIL_TRUNCATION_NOTICE}`;
|
|
@@ -180305,7 +180456,7 @@ function summarizeToolArgs(name2, args) {
|
|
|
180305
180456
|
return `${key}=${clipToolArgValue(compactToolArgValue(args[key]), maximum)}`;
|
|
180306
180457
|
}).join(", ");
|
|
180307
180458
|
if (rendered.length <= TOOL_ARG_SUMMARY_MAX) return rendered;
|
|
180308
|
-
const hash3 =
|
|
180459
|
+
const hash3 = createHash27("sha256").update(fullArgsJson).digest("hex").slice(0, STRUCTURED_ARG_HASH_HEX_LEN);
|
|
180309
180460
|
const suffix = `\u2026#${hash3}`;
|
|
180310
180461
|
const keep = Math.max(0, TOOL_ARG_SUMMARY_MAX - suffix.length);
|
|
180311
180462
|
return `${rendered.slice(0, keep)}${suffix}`;
|
|
@@ -183013,7 +183164,7 @@ var init_retry_burned_logger = __esm({
|
|
|
183013
183164
|
|
|
183014
183165
|
// ../engine/src/merge/merge-dependency-sync.ts
|
|
183015
183166
|
import { exec as exec20 } from "node:child_process";
|
|
183016
|
-
import { createHash as
|
|
183167
|
+
import { createHash as createHash28 } from "node:crypto";
|
|
183017
183168
|
import { existsSync as existsSync50, readFileSync as readFileSync19, writeFileSync as writeFileSync6 } from "node:fs";
|
|
183018
183169
|
import { join as join69 } from "node:path";
|
|
183019
183170
|
import { promisify as promisify27 } from "node:util";
|
|
@@ -183046,7 +183197,7 @@ function computeLockfileHash(rootDir) {
|
|
|
183046
183197
|
const p2 = join69(rootDir, name2);
|
|
183047
183198
|
if (existsSync50(p2)) {
|
|
183048
183199
|
try {
|
|
183049
|
-
return
|
|
183200
|
+
return createHash28("sha256").update(readFileSync19(p2)).digest("hex");
|
|
183050
183201
|
} catch {
|
|
183051
183202
|
return null;
|
|
183052
183203
|
}
|
|
@@ -183176,7 +183327,7 @@ var init_merge_dependency_sync = __esm({
|
|
|
183176
183327
|
});
|
|
183177
183328
|
|
|
183178
183329
|
// ../engine/src/worktree/worktree-dependency-install.ts
|
|
183179
|
-
import { createHash as
|
|
183330
|
+
import { createHash as createHash29 } from "node:crypto";
|
|
183180
183331
|
import { existsSync as existsSync51, readFileSync as readFileSync20, readdirSync as readdirSync8, statSync as statSync11, writeFileSync as writeFileSync7 } from "node:fs";
|
|
183181
183332
|
import { delimiter as delimiter2, join as join70 } from "node:path";
|
|
183182
183333
|
function rootEntries(rootDir) {
|
|
@@ -183274,7 +183425,7 @@ function isCommandAvailable(binary, env = process.env) {
|
|
|
183274
183425
|
);
|
|
183275
183426
|
}
|
|
183276
183427
|
function hashParts(parts) {
|
|
183277
|
-
const hash3 =
|
|
183428
|
+
const hash3 = createHash29("sha256");
|
|
183278
183429
|
for (const [name2, value] of [...parts].sort(([left], [right]) => left.localeCompare(right))) {
|
|
183279
183430
|
hash3.update(name2).update("\0").update(value).update("\0");
|
|
183280
183431
|
}
|
|
@@ -185558,7 +185709,7 @@ var init_code_node_runner = __esm({
|
|
|
185558
185709
|
// ../engine/src/agent-tools.ts
|
|
185559
185710
|
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
185711
|
import { existsSync as existsSync53 } from "node:fs";
|
|
185561
|
-
import { createHash as
|
|
185712
|
+
import { createHash as createHash30, randomUUID as randomUUID48 } from "node:crypto";
|
|
185562
185713
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
185563
185714
|
import { extname as extname4, isAbsolute as isAbsolute14, join as join72, relative as relative13, resolve as resolve40, sep as sep11 } from "node:path";
|
|
185564
185715
|
import { Type as Type2 } from "@earendil-works/pi-ai";
|
|
@@ -185602,7 +185753,7 @@ async function readAgentMemoryWorkspaceLongTerm(rootDir, agentId) {
|
|
|
185602
185753
|
}
|
|
185603
185754
|
}
|
|
185604
185755
|
function qmdAgentMemoryCollectionName2(rootDir, agentId) {
|
|
185605
|
-
const hash3 =
|
|
185756
|
+
const hash3 = createHash30("sha1").update(`${rootDir}:${agentId}`).digest("hex").slice(0, 12);
|
|
185606
185757
|
return `fusion-agent-memory-${sanitizeAgentMemoryId(agentId).toLowerCase()}-${hash3}`;
|
|
185607
185758
|
}
|
|
185608
185759
|
function buildQmdAgentMemoryCollectionAddArgs(rootDir, agentId) {
|
|
@@ -185731,11 +185882,11 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
|
|
|
185731
185882
|
return;
|
|
185732
185883
|
}
|
|
185733
185884
|
const promise = (async () => {
|
|
185734
|
-
const { execFile:
|
|
185735
|
-
const { promisify:
|
|
185736
|
-
const
|
|
185885
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
185886
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
185887
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
185737
185888
|
try {
|
|
185738
|
-
await
|
|
185889
|
+
await execFileAsync37("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
|
|
185739
185890
|
cwd: rootDir,
|
|
185740
185891
|
timeout: 4e3,
|
|
185741
185892
|
maxBuffer: 512 * 1024
|
|
@@ -185748,8 +185899,8 @@ ${stderr}`)) {
|
|
|
185748
185899
|
throw error2;
|
|
185749
185900
|
}
|
|
185750
185901
|
}
|
|
185751
|
-
await
|
|
185752
|
-
await
|
|
185902
|
+
await execFileAsync37("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
|
|
185903
|
+
await execFileAsync37("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
185753
185904
|
})();
|
|
185754
185905
|
agentQmdRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
|
|
185755
185906
|
try {
|
|
@@ -185804,10 +185955,10 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
|
|
|
185804
185955
|
}
|
|
185805
185956
|
try {
|
|
185806
185957
|
await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
|
|
185807
|
-
const { execFile:
|
|
185808
|
-
const { promisify:
|
|
185809
|
-
const
|
|
185810
|
-
const { stdout } = await
|
|
185958
|
+
const { execFile: execFile43 } = await import("node:child_process");
|
|
185959
|
+
const { promisify: promisify91 } = await import("node:util");
|
|
185960
|
+
const execFileAsync37 = promisify91(execFile43);
|
|
185961
|
+
const { stdout } = await execFileAsync37("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
|
|
185811
185962
|
cwd: rootDir,
|
|
185812
185963
|
timeout: 4e3,
|
|
185813
185964
|
maxBuffer: 1024 * 1024
|
|
@@ -190384,7 +190535,7 @@ var init_workspace_review_remediation = __esm({
|
|
|
190384
190535
|
});
|
|
190385
190536
|
|
|
190386
190537
|
// ../engine/src/worktree/secrets-env-writer.ts
|
|
190387
|
-
import { createHash as
|
|
190538
|
+
import { createHash as createHash31 } from "node:crypto";
|
|
190388
190539
|
import { execFile as execFile17 } from "node:child_process";
|
|
190389
190540
|
import { promises as fs6 } from "node:fs";
|
|
190390
190541
|
import path3 from "node:path";
|
|
@@ -190393,7 +190544,7 @@ function isValidFilename(filename) {
|
|
|
190393
190544
|
return !!filename && !filename.includes("/") && !filename.includes("\\") && !filename.includes("..") && !filename.includes("\0") && filename !== FINGERPRINT_FILE;
|
|
190394
190545
|
}
|
|
190395
190546
|
function sha2562(content) {
|
|
190396
|
-
return
|
|
190547
|
+
return createHash31("sha256").update(Buffer.from(content, "utf8")).digest("hex");
|
|
190397
190548
|
}
|
|
190398
190549
|
function quote(value) {
|
|
190399
190550
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll(" ", "\\t")}"`;
|
|
@@ -199189,7 +199340,7 @@ var init_mesh_lease_manager = __esm({
|
|
|
199189
199340
|
});
|
|
199190
199341
|
|
|
199191
199342
|
// ../engine/src/merge/merger-integration-worktree.ts
|
|
199192
|
-
import { createHash as
|
|
199343
|
+
import { createHash as createHash33 } from "node:crypto";
|
|
199193
199344
|
import { exec as exec33, execFile as execFile26 } from "node:child_process";
|
|
199194
199345
|
import { promisify as promisify49 } from "node:util";
|
|
199195
199346
|
function quoteAutostashArg(value) {
|
|
@@ -199312,7 +199463,7 @@ async function gitDirtyFingerprintLocal(rootDir) {
|
|
|
199312
199463
|
)
|
|
199313
199464
|
]);
|
|
199314
199465
|
if (!diffOut && !statusOut) return "";
|
|
199315
|
-
return
|
|
199466
|
+
return createHash33("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
|
|
199316
199467
|
} catch {
|
|
199317
199468
|
return "";
|
|
199318
199469
|
}
|
|
@@ -200295,7 +200446,7 @@ import { execSync as execSync6, exec as exec35 } from "node:child_process";
|
|
|
200295
200446
|
import * as childProcess4 from "node:child_process";
|
|
200296
200447
|
import { promisify as promisify52 } from "node:util";
|
|
200297
200448
|
import { existsSync as existsSync61, readFileSync as readFileSync23, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
|
|
200298
|
-
import { createHash as
|
|
200449
|
+
import { createHash as createHash34 } from "node:crypto";
|
|
200299
200450
|
import { join as join80, resolve as resolve47 } from "node:path";
|
|
200300
200451
|
import { hostname as hostname3 } from "node:os";
|
|
200301
200452
|
import { Type as Type4 } from "typebox";
|
|
@@ -200550,7 +200701,7 @@ async function gitDirtyFingerprint(rootDir) {
|
|
|
200550
200701
|
)
|
|
200551
200702
|
]);
|
|
200552
200703
|
if (!diffOut && !statusOut) return "";
|
|
200553
|
-
return
|
|
200704
|
+
return createHash34("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
|
|
200554
200705
|
} catch {
|
|
200555
200706
|
return "";
|
|
200556
200707
|
}
|
|
@@ -209575,19 +209726,51 @@ async function captureBaseCommitSha(store, task, worktreePath, audit, options =
|
|
|
209575
209726
|
}
|
|
209576
209727
|
|
|
209577
209728
|
// ../engine/src/worktree/review-diff-fingerprint.ts
|
|
209578
|
-
import { createHash as
|
|
209729
|
+
import { createHash as createHash24 } from "node:crypto";
|
|
209579
209730
|
import { execFile as execFile8 } from "node:child_process";
|
|
209580
209731
|
import { promisify as promisify8 } from "node:util";
|
|
209581
209732
|
var execFileAsync5 = promisify8(execFile8);
|
|
209733
|
+
var REVIEW_DIFF_GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
209734
|
+
var REVIEW_DIFF_GIT_TIMEOUT_MS = 12e4;
|
|
209735
|
+
function gitCaptureOptions(cwd) {
|
|
209736
|
+
return {
|
|
209737
|
+
cwd,
|
|
209738
|
+
encoding: "utf8",
|
|
209739
|
+
maxBuffer: REVIEW_DIFF_GIT_MAX_BUFFER_BYTES,
|
|
209740
|
+
timeout: REVIEW_DIFF_GIT_TIMEOUT_MS
|
|
209741
|
+
};
|
|
209742
|
+
}
|
|
209743
|
+
function isGitDiffBufferOverflow(error2) {
|
|
209744
|
+
if (typeof error2 !== "object" || error2 === null) return false;
|
|
209745
|
+
const candidate = error2;
|
|
209746
|
+
return candidate.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" || typeof candidate.message === "string" && candidate.message.includes("maxBuffer");
|
|
209747
|
+
}
|
|
209582
209748
|
var MAX_REVIEW_CHANGED_FILES = 100;
|
|
209583
209749
|
var EMPTY_REVIEW_DIFF_FINGERPRINT = "empty-review-input:v1";
|
|
209750
|
+
async function resolveContentReviewInputProof(worktreePath, diffBaseCommitSha) {
|
|
209751
|
+
let baseRef;
|
|
209752
|
+
try {
|
|
209753
|
+
baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
|
|
209754
|
+
} catch {
|
|
209755
|
+
return { kind: "unprovable", reason: "no-diff-base" };
|
|
209756
|
+
}
|
|
209757
|
+
if (!baseRef) return { kind: "unprovable", reason: "no-diff-base" };
|
|
209758
|
+
const probe = await probeReviewDiffFingerprint(worktreePath, baseRef);
|
|
209759
|
+
if (probe.state === "empty") {
|
|
209760
|
+
return { kind: "fingerprint", fingerprint: EMPTY_REVIEW_DIFF_FINGERPRINT };
|
|
209761
|
+
}
|
|
209762
|
+
return probe.state === "fingerprint" ? { kind: "fingerprint", fingerprint: probe.fingerprint } : { kind: "unprovable", reason: probe.reason };
|
|
209763
|
+
}
|
|
209584
209764
|
async function probeReviewDiffFingerprint(worktreePath, baseRef, targetRef = "HEAD") {
|
|
209585
209765
|
if (!worktreePath || !baseRef) return { state: "unavailable", reason: "missing-worktree-or-base" };
|
|
209586
209766
|
try {
|
|
209587
|
-
const { stdout } = await execFileAsync5("git", ["diff", "--binary", `${baseRef}..${targetRef}`],
|
|
209588
|
-
return stdout ? { state: "fingerprint", fingerprint:
|
|
209589
|
-
} catch {
|
|
209590
|
-
return {
|
|
209767
|
+
const { stdout } = await execFileAsync5("git", ["diff", "--binary", `${baseRef}..${targetRef}`], gitCaptureOptions(worktreePath));
|
|
209768
|
+
return stdout ? { state: "fingerprint", fingerprint: createHash24("sha256").update(stdout).digest("hex") } : { state: "empty" };
|
|
209769
|
+
} catch (error2) {
|
|
209770
|
+
return {
|
|
209771
|
+
state: "unavailable",
|
|
209772
|
+
reason: isGitDiffBufferOverflow(error2) ? "git-diff-too-large" : "git-diff-failed"
|
|
209773
|
+
};
|
|
209591
209774
|
}
|
|
209592
209775
|
}
|
|
209593
209776
|
async function probeReviewChangesSinceCommit(worktreePath, reviewedCommitSha) {
|
|
@@ -209595,14 +209778,11 @@ async function probeReviewChangesSinceCommit(worktreePath, reviewedCommitSha) {
|
|
|
209595
209778
|
return { state: "unavailable", reason: "missing-worktree-or-reviewed-commit" };
|
|
209596
209779
|
}
|
|
209597
209780
|
try {
|
|
209598
|
-
await execFileAsync5("git", ["cat-file", "-e", `${reviewedCommitSha}^{commit}`],
|
|
209599
|
-
cwd: worktreePath,
|
|
209600
|
-
encoding: "utf8"
|
|
209601
|
-
});
|
|
209781
|
+
await execFileAsync5("git", ["cat-file", "-e", `${reviewedCommitSha}^{commit}`], gitCaptureOptions(worktreePath));
|
|
209602
209782
|
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`],
|
|
209783
|
+
execFileAsync5("git", ["rev-list", "--count", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath)),
|
|
209784
|
+
execFileAsync5("git", ["diff", "--name-only", "-z", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath)),
|
|
209785
|
+
execFileAsync5("git", ["diff", "--shortstat", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath))
|
|
209606
209786
|
]);
|
|
209607
209787
|
const commitCount = Number.parseInt(countOutput.trim(), 10);
|
|
209608
209788
|
if (!Number.isSafeInteger(commitCount) || commitCount < 0) {
|
|
@@ -209639,7 +209819,12 @@ import { promisify as promisify11 } from "node:util";
|
|
|
209639
209819
|
import { join as join57 } from "node:path";
|
|
209640
209820
|
var execFileAsync6 = promisify11(execFile9);
|
|
209641
209821
|
async function git(args, cwd) {
|
|
209642
|
-
const { stdout } = await execFileAsync6("git", args, {
|
|
209822
|
+
const { stdout } = await execFileAsync6("git", args, {
|
|
209823
|
+
cwd,
|
|
209824
|
+
encoding: "utf8",
|
|
209825
|
+
maxBuffer: REVIEW_DIFF_GIT_MAX_BUFFER_BYTES,
|
|
209826
|
+
timeout: REVIEW_DIFF_GIT_TIMEOUT_MS
|
|
209827
|
+
});
|
|
209643
209828
|
return stdout.trim();
|
|
209644
209829
|
}
|
|
209645
209830
|
async function captureWorkspaceReviewEvidence(options) {
|
|
@@ -209721,14 +209906,14 @@ async function captureMergeContentDescriptor(task, deps) {
|
|
|
209721
209906
|
|
|
209722
209907
|
// ../engine/src/project-engine.ts
|
|
209723
209908
|
init_integration_branch();
|
|
209724
|
-
import { execFile as
|
|
209725
|
-
import { promisify as
|
|
209909
|
+
import { execFile as execFile42 } from "node:child_process";
|
|
209910
|
+
import { promisify as promisify90 } from "node:util";
|
|
209726
209911
|
|
|
209727
209912
|
// ../engine/src/runtimes/in-process-runtime.ts
|
|
209728
209913
|
init_src2();
|
|
209729
209914
|
init_scheduler();
|
|
209730
209915
|
init_pi();
|
|
209731
|
-
import { createHash as
|
|
209916
|
+
import { createHash as createHash38 } from "node:crypto";
|
|
209732
209917
|
import { EventEmitter as EventEmitter27 } from "node:events";
|
|
209733
209918
|
|
|
209734
209919
|
// ../engine/src/executor/public-reexports.ts
|
|
@@ -211291,7 +211476,7 @@ var WorkflowGraphExecutor = class {
|
|
|
211291
211476
|
phase: "pre-merge",
|
|
211292
211477
|
source: "optional-group",
|
|
211293
211478
|
status: "skipped",
|
|
211294
|
-
bypassedBy:
|
|
211479
|
+
bypassedBy: FAST_MODE_BYPASS_ACTOR,
|
|
211295
211480
|
bypassedAt,
|
|
211296
211481
|
bypassReason: "Fast mode bypasses pre-merge workflow gates",
|
|
211297
211482
|
bypassedFromStatus: "absent",
|
|
@@ -211495,7 +211680,7 @@ var WorkflowGraphExecutor = class {
|
|
|
211495
211680
|
const stepFindings = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.findings) ? exitContextPatch.findings : void 0;
|
|
211496
211681
|
const repositoryReviewOutcomes = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.repositoryReviewOutcomes) ? exitContextPatch.repositoryReviewOutcomes : void 0;
|
|
211497
211682
|
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;
|
|
211683
|
+
const reviewInputFingerprint = requiresContentReviewProof(node.id, { reviewKind: this.workflowReviewKind(node) }) && typeof exitContextPatch?.reviewInputFingerprint === "string" ? exitContextPatch.reviewInputFingerprint : void 0;
|
|
211499
211684
|
const reviewedCommitSha = this.workflowReviewKind(node) && typeof exitContextPatch?.reviewedCommitSha === "string" ? exitContextPatch.reviewedCommitSha : void 0;
|
|
211500
211685
|
const supersededFindingSourceWorkflowStepId = this.workflowReviewKind(node) && typeof exitContextPatch?.supersededFindingSourceWorkflowStepId === "string" ? exitContextPatch.supersededFindingSourceWorkflowStepId : void 0;
|
|
211501
211686
|
const supersededFindingIds = supersededFindingSourceWorkflowStepId && this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.supersededFindingIds) ? exitContextPatch.supersededFindingIds.filter((id) => typeof id === "string") : void 0;
|
|
@@ -212234,7 +212419,7 @@ ${stepOutput}` : ""}`);
|
|
|
212234
212419
|
const findings = this.workflowReviewKind(node) && Array.isArray(contextPatch.findings) ? contextPatch.findings : void 0;
|
|
212235
212420
|
const repositoryReviewOutcomes = this.workflowReviewKind(node) && Array.isArray(contextPatch.repositoryReviewOutcomes) ? contextPatch.repositoryReviewOutcomes : void 0;
|
|
212236
212421
|
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;
|
|
212422
|
+
const reviewInputFingerprint = requiresContentReviewProof(node.id, { reviewKind: this.workflowReviewKind(node) }) && typeof contextPatch.reviewInputFingerprint === "string" ? contextPatch.reviewInputFingerprint : void 0;
|
|
212238
212423
|
const reviewedCommitSha = this.workflowReviewKind(node) && typeof contextPatch.reviewedCommitSha === "string" ? contextPatch.reviewedCommitSha : void 0;
|
|
212239
212424
|
const supersededFindingSourceWorkflowStepId = this.workflowReviewKind(node) && typeof contextPatch.supersededFindingSourceWorkflowStepId === "string" ? contextPatch.supersededFindingSourceWorkflowStepId : void 0;
|
|
212240
212425
|
const supersededFindingIds = supersededFindingSourceWorkflowStepId && this.workflowReviewKind(node) && Array.isArray(contextPatch.supersededFindingIds) ? contextPatch.supersededFindingIds.filter((id) => typeof id === "string") : void 0;
|
|
@@ -212756,7 +212941,7 @@ init_agent_tools();
|
|
|
212756
212941
|
init_agent_logger();
|
|
212757
212942
|
init_agent_usage_telemetry();
|
|
212758
212943
|
import { Type as Type3 } from "@earendil-works/pi-ai";
|
|
212759
|
-
import { createHash as
|
|
212944
|
+
import { createHash as createHash32 } from "node:crypto";
|
|
212760
212945
|
|
|
212761
212946
|
// ../engine/src/agents/approval-mail.ts
|
|
212762
212947
|
init_src2();
|
|
@@ -214385,7 +214570,7 @@ function truncatePrompt(text2, maxChars) {
|
|
|
214385
214570
|
... (truncated, ${text2.length} chars)`;
|
|
214386
214571
|
}
|
|
214387
214572
|
function shortContentHash(value) {
|
|
214388
|
-
return
|
|
214573
|
+
return createHash32("sha256").update(value).digest("hex").slice(0, 8);
|
|
214389
214574
|
}
|
|
214390
214575
|
function buildIdentitySnapshot(args) {
|
|
214391
214576
|
const { agent, resolvedInstructions, workspaceMemory } = args;
|
|
@@ -218766,6 +218951,51 @@ async function finalizeProvenAutoMergeTask({
|
|
|
218766
218951
|
}
|
|
218767
218952
|
}
|
|
218768
218953
|
|
|
218954
|
+
// ../engine/src/merge/stale-content-review-reroute.ts
|
|
218955
|
+
init_src2();
|
|
218956
|
+
function isContentReviewNode(node) {
|
|
218957
|
+
if (node.kind !== "optional-group" && node.kind !== "step-review") return false;
|
|
218958
|
+
const name2 = typeof node.config?.name === "string" ? node.config.name : "";
|
|
218959
|
+
return node.id === "code-review" || node.config?.reviewKind === "code" || /code review/i.test(name2);
|
|
218960
|
+
}
|
|
218961
|
+
async function rerouteSingularStaleContentToReview(store, task, options) {
|
|
218962
|
+
const mergeContent = options.mergeContent;
|
|
218963
|
+
if (mergeContent.kind !== "singular" || task.workspaceWorktrees !== void 0) {
|
|
218964
|
+
return { rerouted: false, reason: "not-singular" };
|
|
218965
|
+
}
|
|
218966
|
+
if (task.paused || task.userPaused || task.deletedAt || task.autoMerge === false) {
|
|
218967
|
+
return { rerouted: false, reason: "operator-held" };
|
|
218968
|
+
}
|
|
218969
|
+
if (mergeContent.diff.state !== "fingerprint") return { rerouted: false, reason: "no-progress" };
|
|
218970
|
+
const currentFingerprint = mergeContent.diff.fingerprint;
|
|
218971
|
+
const ir2 = await resolveWorkflowIrForTask(store, task.id);
|
|
218972
|
+
const selection = store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(task.id) : store.getTaskWorkflowSelection(task.id);
|
|
218973
|
+
const selected = selection?.stepIds ?? [];
|
|
218974
|
+
const nodes2 = ir2.nodes.filter((node2) => {
|
|
218975
|
+
if (!isContentReviewNode(node2) || !options.requiredPreMergeStepIds.has(node2.id)) return false;
|
|
218976
|
+
return node2.config?.defaultOn === true || selected.includes(node2.id);
|
|
218977
|
+
});
|
|
218978
|
+
const node = nodes2.find((candidate) => {
|
|
218979
|
+
const latest = task.workflowStepResults?.filter((result2) => result2.workflowStepId === candidate.id).at(-1);
|
|
218980
|
+
return latest?.reviewInputFingerprint !== currentFingerprint;
|
|
218981
|
+
});
|
|
218982
|
+
if (!node) return { rerouted: false, reason: nodes2.length ? "no-progress" : "no-review-route" };
|
|
218983
|
+
const items = await store.listWorkflowWorkItemsForTask(task.id);
|
|
218984
|
+
const result = await store.seedWorkspaceCodeReviewContinuationIfIdle({
|
|
218985
|
+
taskId: task.id,
|
|
218986
|
+
nodeId: node.id,
|
|
218987
|
+
kind: "task",
|
|
218988
|
+
state: "runnable",
|
|
218989
|
+
runId: `${task.id}:stale-content-review-reroute:${node.id}:${items.length}`,
|
|
218990
|
+
stableWorkflowRunId: `${task.id}:${ir2.name}`,
|
|
218991
|
+
continuationSequence: items.length,
|
|
218992
|
+
sourceColumn: task.column,
|
|
218993
|
+
targetColumn: node.column ?? task.column,
|
|
218994
|
+
irHash: computeWorkflowIrPin(ir2, node.id).irHash
|
|
218995
|
+
});
|
|
218996
|
+
return result.seeded ? { rerouted: true, reason: "seeded", nodeId: node.id, workflowStepId: node.id } : { rerouted: false, reason: "active-continuation", nodeId: node.id, workflowStepId: node.id };
|
|
218997
|
+
}
|
|
218998
|
+
|
|
218769
218999
|
// ../engine/src/healing/auto-recovery.ts
|
|
218770
219000
|
init_logger();
|
|
218771
219001
|
var autoRecoveryLog = createLogger("auto-recovery");
|
|
@@ -220175,9 +220405,6 @@ var BOARD_STALL_NOTIFICATION_COOLDOWN_MS = 60 * 6e4;
|
|
|
220175
220405
|
var DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
220176
220406
|
var PHANTOM_EXECUTOR_BINDING_AGE_MULTIPLIER = 3;
|
|
220177
220407
|
var MAX_NO_PROGRESS_RESUME_ATTEMPTS = 2;
|
|
220178
|
-
function resolveRepoLocalAiMergeRoot(rootDir, settings) {
|
|
220179
|
-
return resolveAiMergeRootPath(rootDir, settings);
|
|
220180
|
-
}
|
|
220181
220408
|
async function classifyOwnedLandedEvidenceForSelfHealing(rootDir, task, mergeTargetBranch) {
|
|
220182
220409
|
const { classifyOwnedLandedEvidence: classifyOwnedLandedEvidence2 } = await Promise.resolve().then(() => (init_merger(), merger_exports));
|
|
220183
220410
|
return classifyOwnedLandedEvidence2(rootDir, task, { mergeTargetBranch });
|
|
@@ -220354,6 +220581,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
220354
220581
|
symbolLockNoActionAudited = false;
|
|
220355
220582
|
maintenanceTickCounter = 0;
|
|
220356
220583
|
taskLifecycleRetentionLastPrunedAt = /* @__PURE__ */ new Map();
|
|
220584
|
+
staleContentRerouteAuditKeys = /* @__PURE__ */ new Set();
|
|
220357
220585
|
githubCheckStateRetentionLastPrunedAt = /* @__PURE__ */ new Map();
|
|
220358
220586
|
processBootStartedAt = Date.now();
|
|
220359
220587
|
lastDbCorruptionNotifiedAt = null;
|
|
@@ -221069,6 +221297,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
221069
221297
|
// flight" to all of them (the merge gate included), which is the two-hour
|
|
221070
221298
|
// stall-deadlock ride this sweep exists to prevent.
|
|
221071
221299
|
{ name: "reconcile-orphaned-pending-step-results", fn: () => this.reconcileOrphanedPendingStepResults().then(() => void 0) },
|
|
221300
|
+
{ name: "reconcile-unproven-review-approvals", fn: () => this.reconcileUnprovenReviewApprovals().then(() => void 0) },
|
|
221072
221301
|
/*
|
|
221073
221302
|
FNXC:WorkspaceContention 2026-08-23-08:00:
|
|
221074
221303
|
`contention-hold` is owned by an in-memory retry timer. After a process restart that
|
|
@@ -221949,6 +222178,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
221949
222178
|
Keep them adjacent and in this order.
|
|
221950
222179
|
*/
|
|
221951
222180
|
{ name: "reconcile-orphaned-pending-step-results", fn: () => this.reconcileOrphanedPendingStepResults() },
|
|
222181
|
+
{ name: "reconcile-unproven-review-approvals", fn: () => this.reconcileUnprovenReviewApprovals() },
|
|
221952
222182
|
{ name: "recover-failed-pre-merge-steps", fn: () => this.recoverReviewTasksWithFailedPreMergeSteps() },
|
|
221953
222183
|
{ name: "recover-missing-worktree-review-failures", fn: () => this.recoverMissingWorktreeReviewFailures() },
|
|
221954
222184
|
{ name: "recover-interrupted-merging", fn: () => this.recoverInterruptedMergingTasks() },
|
|
@@ -226395,6 +226625,95 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
226395
226625
|
return 0;
|
|
226396
226626
|
}
|
|
226397
226627
|
}
|
|
226628
|
+
/*
|
|
226629
|
+
FNXC:ReviewInputProof 2026-09-01-11:28:
|
|
226630
|
+
Prevention cannot release cards that already persisted a proofless `passed` content review. Repair
|
|
226631
|
+
only the invalid result in place, including when auto-merge is off, so automatic recovery can re-run
|
|
226632
|
+
eligible gates and a human-held card gains the failed result its audited bypass needs. The
|
|
226633
|
+
`needsOperatorBypass` label is therefore truthful rather than aspirational; no lifecycle state moves.
|
|
226634
|
+
|
|
226635
|
+
FNXC:ReviewInputProof 2026-09-01-11:57:
|
|
226636
|
+
Reconciliation must recompute from the lock-held task inside `updateTaskAtomic`; a graph writer can
|
|
226637
|
+
publish a proof-bound approval or another gate after the preliminary read, and a stale array write
|
|
226638
|
+
would discard that valid result. Re-check lane, user pause, workspace ownership, and session liveness
|
|
226639
|
+
in the callback, then log and audit only a repair whose atomic mutation actually applied.
|
|
226640
|
+
*/
|
|
226641
|
+
async reconcileUnprovenReviewApprovals() {
|
|
226642
|
+
try {
|
|
226643
|
+
const reviewColumns = await resolveProjectColumnsForRoles(this.store, REVIEW_ROLES);
|
|
226644
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
226645
|
+
for (const column of reviewColumns) {
|
|
226646
|
+
for (const task of await this.store.listTasks({ column, slim: true })) candidates.set(task.id, task);
|
|
226647
|
+
}
|
|
226648
|
+
const settings = await this.store.getSettings().catch(() => void 0);
|
|
226649
|
+
let repairedTasks = 0;
|
|
226650
|
+
const isSessionLive = (taskId) => {
|
|
226651
|
+
const livePaths = activeSessionRegistry.pathsForTask(taskId);
|
|
226652
|
+
return livePaths.some((path6) => activeSessionRegistry.isPathActive(path6)) || executingTaskLock.has(taskId) || this.options.isTaskActive?.(taskId) === true;
|
|
226653
|
+
};
|
|
226654
|
+
for (const candidate of candidates.values()) {
|
|
226655
|
+
if (candidate.userPaused === true || candidate.workspaceWorktrees !== void 0 || isSessionLive(candidate.id)) continue;
|
|
226656
|
+
if (!candidate.workflowStepResults?.some((result) => resolveUnprovenReviewApproval(result, { workspace: false }))) continue;
|
|
226657
|
+
const fresh = await this.store.getTask(candidate.id);
|
|
226658
|
+
if (!fresh || !reviewColumns.has(fresh.column) || fresh.userPaused === true || fresh.workspaceWorktrees !== void 0 || isSessionLive(fresh.id)) continue;
|
|
226659
|
+
let repair;
|
|
226660
|
+
try {
|
|
226661
|
+
await this.store.updateTaskAtomic(fresh.id, (live) => {
|
|
226662
|
+
repair = void 0;
|
|
226663
|
+
if (!reviewColumns.has(live.column) || live.userPaused === true || live.workspaceWorktrees !== void 0 || isSessionLive(live.id)) return null;
|
|
226664
|
+
const repairedStepIds = [];
|
|
226665
|
+
let repairReason;
|
|
226666
|
+
const results = (live.workflowStepResults ?? []).map((result) => {
|
|
226667
|
+
const resolution = resolveUnprovenReviewApproval(result, { workspace: false });
|
|
226668
|
+
if (!resolution) return result;
|
|
226669
|
+
repairedStepIds.push(result.workflowStepId);
|
|
226670
|
+
repairReason ??= resolution.reason;
|
|
226671
|
+
return resolution.downgraded;
|
|
226672
|
+
});
|
|
226673
|
+
if (repairedStepIds.length === 0 || !repairReason) return null;
|
|
226674
|
+
repair = {
|
|
226675
|
+
stepIds: repairedStepIds,
|
|
226676
|
+
reason: repairReason,
|
|
226677
|
+
column: live.column,
|
|
226678
|
+
resultCount: results.length,
|
|
226679
|
+
needsOperatorBypass: settings ? !allowsAutoMergeProcessing(live, settings) : void 0
|
|
226680
|
+
};
|
|
226681
|
+
return { workflowStepResults: results };
|
|
226682
|
+
});
|
|
226683
|
+
if (!repair) continue;
|
|
226684
|
+
repairedTasks += 1;
|
|
226685
|
+
} catch (error2) {
|
|
226686
|
+
log34.warn(`reconcileUnprovenReviewApprovals: failed for ${fresh.id}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
226687
|
+
continue;
|
|
226688
|
+
}
|
|
226689
|
+
await this.store.logEntry(
|
|
226690
|
+
fresh.id,
|
|
226691
|
+
`[pre-merge] Invalid proofless approval repaired for ${repair.stepIds.join(", ")}: ${repair.reason}`
|
|
226692
|
+
).catch(() => void 0);
|
|
226693
|
+
await emitBoundedRunAudit2(this.store, {
|
|
226694
|
+
taskId: fresh.id,
|
|
226695
|
+
agentId: "self-healing",
|
|
226696
|
+
runId: generateSyntheticRunId("reconcile-unproven-review-approval", fresh.id),
|
|
226697
|
+
domain: "database",
|
|
226698
|
+
mutationType: "task:reconcile-unproven-review-approval",
|
|
226699
|
+
target: fresh.id,
|
|
226700
|
+
metadata: {
|
|
226701
|
+
taskId: fresh.id,
|
|
226702
|
+
column: repair.column,
|
|
226703
|
+
workflowStepId: repair.stepIds[0],
|
|
226704
|
+
repairedCount: repair.stepIds.length,
|
|
226705
|
+
resultCount: repair.resultCount,
|
|
226706
|
+
needsOperatorBypass: repair.needsOperatorBypass
|
|
226707
|
+
}
|
|
226708
|
+
}, { log: log34 });
|
|
226709
|
+
}
|
|
226710
|
+
if (repairedTasks > 0) log34.log(`Repaired unproven review approvals on ${repairedTasks} task(s)`);
|
|
226711
|
+
return repairedTasks;
|
|
226712
|
+
} catch (error2) {
|
|
226713
|
+
log34.error(`reconcileUnprovenReviewApprovals failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
226714
|
+
return 0;
|
|
226715
|
+
}
|
|
226716
|
+
}
|
|
226398
226717
|
/**
|
|
226399
226718
|
* Backward lifecycle move gated on triple proof (FN-5335).
|
|
226400
226719
|
* When the unproven fallback predicate fails, emits `task:finalize-no-op-review-no-action` and skips lifecycle mutation.
|
|
@@ -226748,6 +227067,66 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
226748
227067
|
}
|
|
226749
227068
|
return allowsAutoMergeProcessing(task, settings) && resolveEffectiveAutoMerge(task, settings) !== false;
|
|
226750
227069
|
}
|
|
227070
|
+
/*
|
|
227071
|
+
FNXC:PreMergeApproval 2026-09-01-14:05:
|
|
227072
|
+
Self-healing must not treat a stale content-bound approval as mergeable just because the cheap
|
|
227073
|
+
blocker check lacks a fresh Git descriptor. Capture the same merge content the merge queue uses and
|
|
227074
|
+
seed the graph back at Code Review, so cards like FN-9234 stop looping through doomed merge retries.
|
|
227075
|
+
*/
|
|
227076
|
+
async routeStaleSingularApprovalBackToReview(task, reviewColumns, settings) {
|
|
227077
|
+
let mergeGate;
|
|
227078
|
+
try {
|
|
227079
|
+
mergeGate = await resolvePreMergeGateForTask(this.store, task.id, task.enabledWorkflowSteps, task);
|
|
227080
|
+
} catch {
|
|
227081
|
+
return false;
|
|
227082
|
+
}
|
|
227083
|
+
if (mergeGate.provenance === "default" && !mergeGate.selectionAbsent) return false;
|
|
227084
|
+
const mergeContent = await captureMergeContentDescriptor(task, {
|
|
227085
|
+
workspaceRootDir: this.options.rootDir,
|
|
227086
|
+
settings
|
|
227087
|
+
});
|
|
227088
|
+
const blocker = getTaskMergeBlocker(task, {
|
|
227089
|
+
reviewColumns,
|
|
227090
|
+
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
227091
|
+
mergeContent
|
|
227092
|
+
});
|
|
227093
|
+
if (blocker !== "task has a pre-merge approval recorded against different content" || mergeContent.kind !== "singular") {
|
|
227094
|
+
return false;
|
|
227095
|
+
}
|
|
227096
|
+
const reroute = await rerouteSingularStaleContentToReview(this.store, task, {
|
|
227097
|
+
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
227098
|
+
mergeContent
|
|
227099
|
+
}).catch(() => ({
|
|
227100
|
+
rerouted: false,
|
|
227101
|
+
reason: "no-progress",
|
|
227102
|
+
nodeId: void 0,
|
|
227103
|
+
workflowStepId: void 0
|
|
227104
|
+
}));
|
|
227105
|
+
if (reroute.rerouted) {
|
|
227106
|
+
await this.store.logEntry(task.id, "[pre-merge] Self-healing re-seeded Code Review after stale content evidence blocked merge.");
|
|
227107
|
+
log34.warn(`Stale content approval for ${task.id} re-seeded at ${reroute.nodeId ?? "code-review"}`);
|
|
227108
|
+
}
|
|
227109
|
+
const auditKey = `${task.id}:${reroute.reason}:${reroute.nodeId ?? ""}`;
|
|
227110
|
+
if (!this.staleContentRerouteAuditKeys.has(auditKey)) {
|
|
227111
|
+
this.staleContentRerouteAuditKeys.add(auditKey);
|
|
227112
|
+
await emitBoundedRunAudit2(this.store, {
|
|
227113
|
+
taskId: task.id,
|
|
227114
|
+
agentId: "self-healing",
|
|
227115
|
+
runId: generateSyntheticRunId("self-healing", task.id),
|
|
227116
|
+
domain: "database",
|
|
227117
|
+
mutationType: "task:merge-stale-content-review-rerouted",
|
|
227118
|
+
target: task.id,
|
|
227119
|
+
metadata: {
|
|
227120
|
+
taskId: task.id,
|
|
227121
|
+
nodeId: reroute.nodeId,
|
|
227122
|
+
workflowStepId: reroute.workflowStepId,
|
|
227123
|
+
reason: reroute.reason,
|
|
227124
|
+
source: "self-healing"
|
|
227125
|
+
}
|
|
227126
|
+
});
|
|
227127
|
+
}
|
|
227128
|
+
return true;
|
|
227129
|
+
}
|
|
226751
227130
|
/**
|
|
226752
227131
|
* Recover `in-review` tasks that are fully mergeable but never had
|
|
226753
227132
|
* `mergeTask()` invoked.
|
|
@@ -226801,6 +227180,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
|
|
|
226801
227180
|
for (const task of mergeable) {
|
|
226802
227181
|
const reviewColumns = await ownReviewLanesFor(task);
|
|
226803
227182
|
if (!reviewColumns.has(task.column)) continue;
|
|
227183
|
+
if (await this.routeStaleSingularApprovalBackToReview(task, reviewColumns, settings)) continue;
|
|
226804
227184
|
if (getTaskMergeBlocker(task, { reviewColumns }) !== void 0) continue;
|
|
226805
227185
|
laneQualifiedMergeable.push(task);
|
|
226806
227186
|
}
|
|
@@ -229367,8 +229747,7 @@ This review is not retried until its findings change. Re-run the review after ad
|
|
|
229367
229747
|
}
|
|
229368
229748
|
async listAiMergeWorktreeCandidates(taskId, settings) {
|
|
229369
229749
|
const roots = Array.from(/* @__PURE__ */ new Set([
|
|
229370
|
-
|
|
229371
|
-
resolveLegacyAiMergeRootPath(this.options.rootDir),
|
|
229750
|
+
...resolveAiMergeSearchRoots(this.options.rootDir, settings),
|
|
229372
229751
|
tmpdir8()
|
|
229373
229752
|
]));
|
|
229374
229753
|
const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
|
|
@@ -231902,9 +232281,7 @@ This review is not retried until its findings change. Re-run the review after ad
|
|
|
231902
232281
|
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
232282
|
}
|
|
231904
232283
|
const roots = Array.from(/* @__PURE__ */ new Set([
|
|
231905
|
-
|
|
231906
|
-
resolveLegacyAiMergeRootPath(this.options.rootDir),
|
|
231907
|
-
...settings.worktreesDir ? [] : [join81(resolveLegacyWorktreesDirLayout(this.options.rootDir), ".ai-merge")],
|
|
232284
|
+
...resolveAiMergeSearchRoots(this.options.rootDir, settings),
|
|
231908
232285
|
tmpdir8()
|
|
231909
232286
|
]));
|
|
231910
232287
|
const auditor = createRunAuditor(this.store, {
|
|
@@ -234559,7 +234936,7 @@ ${recommendation.description}`)) {
|
|
|
234559
234936
|
// ../engine/src/executor/execute-workflow-step.ts
|
|
234560
234937
|
init_src2();
|
|
234561
234938
|
import { exec as exec41 } from "node:child_process";
|
|
234562
|
-
import { promisify as
|
|
234939
|
+
import { promisify as promisify59 } from "node:util";
|
|
234563
234940
|
|
|
234564
234941
|
// ../engine/src/executor/shared-worker-tools.ts
|
|
234565
234942
|
init_agent_tools();
|
|
@@ -236418,6 +236795,47 @@ function isWorkflowStepSkillDiscoverable(skillName, additionalSkillPaths, ceSkil
|
|
|
236418
236795
|
);
|
|
236419
236796
|
}
|
|
236420
236797
|
|
|
236798
|
+
// ../engine/src/worktree/review-inline-fix-recapture.ts
|
|
236799
|
+
import { execFile as execFile29 } from "node:child_process";
|
|
236800
|
+
import { promisify as promisify58 } from "node:util";
|
|
236801
|
+
var execFileAsync23 = promisify58(execFile29);
|
|
236802
|
+
function classifyReviewInlineFixRecapture(input) {
|
|
236803
|
+
if (input.reviewKind === "plan") return { recapture: false, reason: "plan-domain" };
|
|
236804
|
+
if (input.verdict !== "APPROVE" && input.verdict !== "APPROVE_WITH_NOTES") {
|
|
236805
|
+
return { recapture: false, reason: "not-approval-verdict" };
|
|
236806
|
+
}
|
|
236807
|
+
if (!input.reviewedCommitSha || !input.currentHeadSha || !input.baseRef) {
|
|
236808
|
+
return { recapture: false, reason: "missing-anchor" };
|
|
236809
|
+
}
|
|
236810
|
+
if (input.reviewedCommitSha === input.currentHeadSha) return { recapture: false, reason: "head-unchanged" };
|
|
236811
|
+
if (input.fastForwardAdvance === void 0 || input.baseIsAncestor === void 0) {
|
|
236812
|
+
return { recapture: false, reason: "probe-unavailable" };
|
|
236813
|
+
}
|
|
236814
|
+
if (!input.fastForwardAdvance) return { recapture: false, reason: "history-rewritten" };
|
|
236815
|
+
if (!input.baseIsAncestor) return { recapture: false, reason: "base-not-ancestor" };
|
|
236816
|
+
if (!input.fingerprintProbeAvailable) return { recapture: false, reason: "probe-unavailable" };
|
|
236817
|
+
return { recapture: true, reason: "recaptured" };
|
|
236818
|
+
}
|
|
236819
|
+
async function readHeadSha(worktreePath) {
|
|
236820
|
+
if (!worktreePath) return void 0;
|
|
236821
|
+
try {
|
|
236822
|
+
const { stdout } = await execFileAsync23("git", ["rev-parse", "HEAD"], { cwd: worktreePath, encoding: "utf8" });
|
|
236823
|
+
return stdout.trim() || void 0;
|
|
236824
|
+
} catch {
|
|
236825
|
+
return void 0;
|
|
236826
|
+
}
|
|
236827
|
+
}
|
|
236828
|
+
async function isFastForwardAdvance(worktreePath, fromSha, toSha) {
|
|
236829
|
+
if (!worktreePath || !fromSha || !toSha) return void 0;
|
|
236830
|
+
try {
|
|
236831
|
+
await execFileAsync23("git", ["merge-base", "--is-ancestor", fromSha, toSha], { cwd: worktreePath, encoding: "utf8" });
|
|
236832
|
+
return true;
|
|
236833
|
+
} catch (error2) {
|
|
236834
|
+
const code = error2?.code;
|
|
236835
|
+
return code === 1 ? false : void 0;
|
|
236836
|
+
}
|
|
236837
|
+
}
|
|
236838
|
+
|
|
236421
236839
|
// ../engine/src/executor/optional-step-revision.ts
|
|
236422
236840
|
init_src2();
|
|
236423
236841
|
|
|
@@ -236575,7 +236993,7 @@ function buildGraphPlanReviewConvergenceContext(task, revisionKey) {
|
|
|
236575
236993
|
|
|
236576
236994
|
// ../engine/src/executor/execute-workflow-step.ts
|
|
236577
236995
|
init_agent_usage_telemetry();
|
|
236578
|
-
var execAsync38 =
|
|
236996
|
+
var execAsync38 = promisify59(exec41);
|
|
236579
236997
|
var WORKFLOW_STEP_NOTES_REPAIR_TIMEOUT_MS = 12e4;
|
|
236580
236998
|
function findReusableReviewResult(task, workflowStepId, reviewInputFingerprint, repositoryScopeRevision) {
|
|
236581
236999
|
if (!reviewInputFingerprint) return void 0;
|
|
@@ -236614,6 +237032,8 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236614
237032
|
const unattended = stepOptions?.unattended === true;
|
|
236615
237033
|
const workflowStepMetadata = workflowStep;
|
|
236616
237034
|
const optionalGroupId = workflowStepMetadata.optionalGroupId;
|
|
237035
|
+
const effectiveWorkflowStepId = optionalGroupId ?? workflowStep.id.replace(/^graph:/, "");
|
|
237036
|
+
const isContentBindingStep = requiresContentReviewProof(effectiveWorkflowStepId, workflowStepMetadata);
|
|
236617
237037
|
const isPlanReviewStep = workflowStep.id === "graph:plan-review-step" || workflowStep.name === "Plan Review" || optionalGroupId === PLAN_REVIEW_GROUP_ID;
|
|
236618
237038
|
const planReviewRevisionKey = optionalStepRevisionKey2(optionalGroupId, workflowStep.name);
|
|
236619
237039
|
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 +237044,8 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236624
237044
|
toolMode = "coding";
|
|
236625
237045
|
}
|
|
236626
237046
|
const requireExternalIntegrationEvidence = workflowStepMetadata.requireExternalIntegrationEvidence === true;
|
|
237047
|
+
const readonlyMcpServerAllowlist = toolMode === "readonly" ? [...new Set((workflowStepMetadata.readonlyMcpServers ?? []).map((name2) => name2.trim()).filter(Boolean))] : [];
|
|
237048
|
+
const allowReadonlyMcpTools = toolMode === "readonly" && readonlyMcpServerAllowlist.length > 0;
|
|
236627
237049
|
let workflowReviewSpecArtifact;
|
|
236628
237050
|
if (isReviewTypeWorkflowStep) {
|
|
236629
237051
|
try {
|
|
@@ -236642,7 +237064,7 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236642
237064
|
const workflowReviewSpecText = typeof workflowReviewSpecArtifact === "string" ? workflowReviewSpecArtifact : "";
|
|
236643
237065
|
const planReviewSpecText = isPlanReviewStep ? workflowReviewSpecText : "";
|
|
236644
237066
|
const latestTaskForUserComments = await deps.store.getTask(task.id).catch(() => task);
|
|
236645
|
-
const sameGateStepId =
|
|
237067
|
+
const sameGateStepId = effectiveWorkflowStepId;
|
|
236646
237068
|
const planReviewConvergenceContext = isPlanReviewStep ? buildGraphPlanReviewConvergenceContext(latestTaskForUserComments, planReviewRevisionKey) : "";
|
|
236647
237069
|
const planReviewEnvironmentCapabilities = isPlanReviewStep ? await probeEnvironmentCapabilities({
|
|
236648
237070
|
extraCommands: [
|
|
@@ -236690,21 +237112,44 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
|
|
|
236690
237112
|
let diffShortstat;
|
|
236691
237113
|
let reviewInputFingerprint;
|
|
236692
237114
|
let reviewedCommitSha;
|
|
237115
|
+
let baseRef;
|
|
236693
237116
|
try {
|
|
236694
|
-
|
|
236695
|
-
|
|
236696
|
-
|
|
236697
|
-
|
|
236698
|
-
|
|
236699
|
-
|
|
236700
|
-
|
|
237117
|
+
baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
|
|
237118
|
+
} catch {
|
|
237119
|
+
}
|
|
237120
|
+
if (isContentBindingStep && task.workspaceWorktrees === void 0) {
|
|
237121
|
+
const suppliedFingerprint = stepOptions?.reviewInputFingerprint?.trim();
|
|
237122
|
+
const proof = suppliedFingerprint ? { kind: "fingerprint", fingerprint: suppliedFingerprint } : await resolveContentReviewInputProof(worktreePath, diffBaseCommitSha);
|
|
237123
|
+
if (proof.kind === "unprovable") {
|
|
237124
|
+
const diagnostic = `${workflowStep.name} review input is unprovable (${proof.reason}); reviewer dispatch refused.`;
|
|
237125
|
+
await deps.store.logEntry(
|
|
237126
|
+
task.id,
|
|
237127
|
+
`[pre-merge] ${diagnostic}`,
|
|
237128
|
+
void 0,
|
|
237129
|
+
deps.getRunContextFor(task.id)
|
|
237130
|
+
);
|
|
237131
|
+
return { success: false, error: diagnostic, failureValue: "review-input-unprovable" };
|
|
237132
|
+
}
|
|
237133
|
+
reviewInputFingerprint = proof.fingerprint;
|
|
237134
|
+
} else if (baseRef) {
|
|
237135
|
+
try {
|
|
236701
237136
|
if (workflowStepMetadata.reviewKind === "code") {
|
|
236702
237137
|
reviewInputFingerprint = await computeCodeReviewInputFingerprint(worktreePath, baseRef);
|
|
236703
237138
|
} else if (isReviewTypeWorkflowStep) {
|
|
236704
237139
|
reviewInputFingerprint = await computeReviewDiffFingerprint(worktreePath, baseRef);
|
|
236705
237140
|
}
|
|
237141
|
+
} catch {
|
|
237142
|
+
}
|
|
237143
|
+
}
|
|
237144
|
+
if (baseRef) {
|
|
237145
|
+
try {
|
|
237146
|
+
const { stdout } = await execAsync38(`git diff --shortstat ${baseRef}..HEAD`, {
|
|
237147
|
+
cwd: worktreePath,
|
|
237148
|
+
encoding: "utf-8"
|
|
237149
|
+
});
|
|
237150
|
+
diffShortstat = stdout.trim() || void 0;
|
|
237151
|
+
} catch {
|
|
236706
237152
|
}
|
|
236707
|
-
} catch {
|
|
236708
237153
|
}
|
|
236709
237154
|
if (isReviewTypeWorkflowStep) {
|
|
236710
237155
|
try {
|
|
@@ -237014,6 +237459,12 @@ ${workflowStepUserCommentSection}` : ""}${priorFindingsBlock}
|
|
|
237014
237459
|
const workflowStepThinkingSource = workflowStep.thinkingLevel ?? (isReviewTypeWorkflowStep ? task.validatorThinkingLevel ?? task.thinkingLevel : task.thinkingLevel);
|
|
237015
237460
|
const workflowStepThinkingLevel = attemptLabel === "fallback" ? isReviewTypeWorkflowStep ? resolveValidatorFallbackThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorFallbackThinkingLevel(workflowStepThinkingSource, settings) : isReviewTypeWorkflowStep ? resolveValidatorThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorThinkingLevel(workflowStepThinkingSource, settings);
|
|
237016
237461
|
const workflowStepFallbackThinkingLevel = isReviewTypeWorkflowStep ? resolveValidatorFallbackThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorFallbackThinkingLevel(workflowStepThinkingSource, settings);
|
|
237462
|
+
if (allowReadonlyMcpTools) {
|
|
237463
|
+
await deps.store.logEntry(
|
|
237464
|
+
task.id,
|
|
237465
|
+
`Workflow step '${workflowStep.name}' enabled read-only MCP servers: ${readonlyMcpServerAllowlist.join(", ")}`
|
|
237466
|
+
);
|
|
237467
|
+
}
|
|
237017
237468
|
const { session } = await createResolvedAgentSession({
|
|
237018
237469
|
sessionPurpose: "executor",
|
|
237019
237470
|
taskExecutionSession: true,
|
|
@@ -237034,6 +237485,10 @@ ${workflowStepUserCommentSection}` : ""}${priorFindingsBlock}
|
|
|
237034
237485
|
settings,
|
|
237035
237486
|
taskEnv: stepEnv,
|
|
237036
237487
|
mcpServers: await deps.resolveMcpServers(void 0),
|
|
237488
|
+
...allowReadonlyMcpTools ? {
|
|
237489
|
+
allowMcpToolsInReadonly: true,
|
|
237490
|
+
readonlyMcpServerAllowlist
|
|
237491
|
+
} : {},
|
|
237037
237492
|
// FNXC:SessionRouting 2026-06-24-11:20:
|
|
237038
237493
|
// #1675: propagate task id so workflow-step requests carry the same
|
|
237039
237494
|
// X-Session-Id/X-Session-Affinity as the primary session.
|
|
@@ -237249,6 +237704,60 @@ ${detectedQuestion}
|
|
|
237249
237704
|
});
|
|
237250
237705
|
}
|
|
237251
237706
|
const revisionRequested = effectiveVerdict === "REVISE";
|
|
237707
|
+
if (isReviewTypeWorkflowStep && !isPlanReviewStep && !revisionRequested) {
|
|
237708
|
+
const priorReviewedCommitSha = reviewedCommitSha;
|
|
237709
|
+
const currentHeadSha = await readHeadSha(worktreePath);
|
|
237710
|
+
const fastForwardAdvance = await isFastForwardAdvance(worktreePath, priorReviewedCommitSha, currentHeadSha);
|
|
237711
|
+
const baseIsAncestor = await isFastForwardAdvance(worktreePath, baseRef, currentHeadSha);
|
|
237712
|
+
const decision = classifyReviewInlineFixRecapture({
|
|
237713
|
+
verdict: effectiveVerdict,
|
|
237714
|
+
reviewKind: workflowStepMetadata.reviewKind,
|
|
237715
|
+
reviewedCommitSha: priorReviewedCommitSha,
|
|
237716
|
+
currentHeadSha,
|
|
237717
|
+
baseRef,
|
|
237718
|
+
fastForwardAdvance,
|
|
237719
|
+
baseIsAncestor,
|
|
237720
|
+
fingerprintProbeAvailable: true
|
|
237721
|
+
});
|
|
237722
|
+
if (decision.recapture) {
|
|
237723
|
+
try {
|
|
237724
|
+
const recapturedFingerprint = workflowStepMetadata.reviewKind === "code" ? await computeCodeReviewInputFingerprint(worktreePath, baseRef) : await computeReviewDiffFingerprint(worktreePath, baseRef);
|
|
237725
|
+
const finalDecision = classifyReviewInlineFixRecapture({
|
|
237726
|
+
verdict: effectiveVerdict,
|
|
237727
|
+
reviewKind: workflowStepMetadata.reviewKind,
|
|
237728
|
+
reviewedCommitSha: priorReviewedCommitSha,
|
|
237729
|
+
currentHeadSha,
|
|
237730
|
+
baseRef,
|
|
237731
|
+
fastForwardAdvance,
|
|
237732
|
+
baseIsAncestor,
|
|
237733
|
+
fingerprintProbeAvailable: recapturedFingerprint !== void 0
|
|
237734
|
+
});
|
|
237735
|
+
if (finalDecision.recapture && currentHeadSha) {
|
|
237736
|
+
reviewInputFingerprint = recapturedFingerprint;
|
|
237737
|
+
reviewedCommitSha = currentHeadSha;
|
|
237738
|
+
const resolvedInReviewFindingCount = parsed.findings?.filter((finding) => finding.resolution === "resolved-in-review").length ?? 0;
|
|
237739
|
+
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})`);
|
|
237740
|
+
const runContext = deps.getRunContextFor(task.id);
|
|
237741
|
+
if (runContext) await emitBoundedRunAudit2(deps.store, {
|
|
237742
|
+
taskId: task.id,
|
|
237743
|
+
agentId: runContext.agentId,
|
|
237744
|
+
runId: runContext.runId,
|
|
237745
|
+
domain: "git",
|
|
237746
|
+
mutationType: "task:review-input-recaptured",
|
|
237747
|
+
target: task.id,
|
|
237748
|
+
metadata: {
|
|
237749
|
+
taskId: task.id,
|
|
237750
|
+
workflowStepId: workflowStep.id,
|
|
237751
|
+
verdict: effectiveVerdict,
|
|
237752
|
+
resolvedInReviewFindingCount,
|
|
237753
|
+
reason: finalDecision.reason
|
|
237754
|
+
}
|
|
237755
|
+
});
|
|
237756
|
+
}
|
|
237757
|
+
} catch {
|
|
237758
|
+
}
|
|
237759
|
+
}
|
|
237760
|
+
}
|
|
237252
237761
|
if (workflowStep.requiresBrowser === true) {
|
|
237253
237762
|
await logBrowserVerificationActivity(`[browser-verification] finished browser verification for task ${task.id}: verdict ${effectiveVerdict}`);
|
|
237254
237763
|
}
|
|
@@ -237953,10 +238462,10 @@ init_branch_conflicts();
|
|
|
237953
238462
|
init_integration_branch();
|
|
237954
238463
|
init_logger();
|
|
237955
238464
|
import { exec as exec42 } from "node:child_process";
|
|
237956
|
-
import { promisify as
|
|
238465
|
+
import { promisify as promisify60 } from "node:util";
|
|
237957
238466
|
import { existsSync as existsSync66 } from "node:fs";
|
|
237958
238467
|
import { rm as rm11 } from "node:fs/promises";
|
|
237959
|
-
var execAsync39 =
|
|
238468
|
+
var execAsync39 = promisify60(exec42);
|
|
237960
238469
|
async function tryCreateWorktree(deps, branch, path6, taskId, startPoint, attemptNumber = 0, recoveryDepth = 0, allowSiblingBranchRename = false, settings = {}) {
|
|
237961
238470
|
await assertWorktreePathNotNested(deps.rootDir, deps.store, path6, taskId);
|
|
237962
238471
|
const installGuardOrCleanup = async () => {
|
|
@@ -238244,10 +238753,10 @@ init_src2();
|
|
|
238244
238753
|
init_worktree_pool();
|
|
238245
238754
|
init_logger();
|
|
238246
238755
|
import { exec as exec43 } from "node:child_process";
|
|
238247
|
-
import { promisify as
|
|
238756
|
+
import { promisify as promisify61 } from "node:util";
|
|
238248
238757
|
import { existsSync as existsSync67, lstatSync as lstatSync3, realpathSync as realpathSync11 } from "node:fs";
|
|
238249
238758
|
import { rm as rm12 } from "node:fs/promises";
|
|
238250
|
-
var execAsync40 =
|
|
238759
|
+
var execAsync40 = promisify61(exec43);
|
|
238251
238760
|
async function cleanupConflictingWorktree(deps, worktreePath, branch, taskId) {
|
|
238252
238761
|
await deps.reconcileSelfOwnedBeforeRemove(worktreePath, taskId);
|
|
238253
238762
|
const activeOwner = await deps.findActiveWorktreeOwner(worktreePath, taskId);
|
|
@@ -238364,10 +238873,10 @@ init_worktree_stale_lock();
|
|
|
238364
238873
|
init_integration_branch();
|
|
238365
238874
|
init_logger();
|
|
238366
238875
|
import { exec as exec44 } from "node:child_process";
|
|
238367
|
-
import { promisify as
|
|
238876
|
+
import { promisify as promisify62 } from "node:util";
|
|
238368
238877
|
import { existsSync as existsSync68 } from "node:fs";
|
|
238369
238878
|
import { isAbsolute as isAbsolute22 } from "node:path";
|
|
238370
|
-
var execAsync41 =
|
|
238879
|
+
var execAsync41 = promisify62(exec44);
|
|
238371
238880
|
async function resolveWorktreeStartPoint(rootDir, store, startPoint, taskId) {
|
|
238372
238881
|
const command = isAbsolute22(startPoint) && existsSync68(startPoint) ? `git -C "${startPoint}" rev-parse --verify HEAD^{commit}` : `git rev-parse --verify "${startPoint}^{commit}"`;
|
|
238373
238882
|
try {
|
|
@@ -238569,8 +239078,8 @@ init_effective_settings();
|
|
|
238569
239078
|
init_worktree_pinning();
|
|
238570
239079
|
init_logger();
|
|
238571
239080
|
import { exec as exec45 } from "node:child_process";
|
|
238572
|
-
import { promisify as
|
|
238573
|
-
var execAsync42 =
|
|
239081
|
+
import { promisify as promisify63 } from "node:util";
|
|
239082
|
+
var execAsync42 = promisify63(exec45);
|
|
238574
239083
|
async function reclaimExistingWorktree(deps, task, livePath, branch, tipSha, count2, settings) {
|
|
238575
239084
|
const targetPath = preservedWorktreeTargetPathForTask(task.id, livePath, settings, deps.rootDir);
|
|
238576
239085
|
const normalizedPath = await deps.normalizeReclaimableWorktreePath(livePath, targetPath, task.id, settings);
|
|
@@ -238803,7 +239312,7 @@ init_worktree_names();
|
|
|
238803
239312
|
init_logger();
|
|
238804
239313
|
init_run_audit();
|
|
238805
239314
|
import { exec as exec47 } from "node:child_process";
|
|
238806
|
-
import { promisify as
|
|
239315
|
+
import { promisify as promisify66 } from "node:util";
|
|
238807
239316
|
import { existsSync as existsSync71 } from "node:fs";
|
|
238808
239317
|
|
|
238809
239318
|
// ../engine/src/executor/session-worktree-paths.ts
|
|
@@ -238931,11 +239440,11 @@ function classifyWorkspaceZeroAcquire(task, options) {
|
|
|
238931
239440
|
}
|
|
238932
239441
|
|
|
238933
239442
|
// ../engine/src/execution/external-execution-checkout.ts
|
|
238934
|
-
import { execFile as
|
|
239443
|
+
import { execFile as execFile30 } from "node:child_process";
|
|
238935
239444
|
import { existsSync as existsSync69, realpathSync as realpathSync13, statSync as statSync14 } from "node:fs";
|
|
238936
239445
|
import { isAbsolute as isAbsolute23 } from "node:path";
|
|
238937
|
-
import { promisify as
|
|
238938
|
-
var
|
|
239446
|
+
import { promisify as promisify64 } from "node:util";
|
|
239447
|
+
var execFileAsync24 = promisify64(execFile30);
|
|
238939
239448
|
function readSourceMetadata(task) {
|
|
238940
239449
|
if (!task || typeof task !== "object") return void 0;
|
|
238941
239450
|
const sourceMetadata = task.sourceMetadata;
|
|
@@ -238954,7 +239463,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
|
|
|
238954
239463
|
return { valid: false, reason: `checkoutPath is not a directory: ${checkoutPath}` };
|
|
238955
239464
|
}
|
|
238956
239465
|
const canonicalCheckout = realpathSync13(checkoutPath);
|
|
238957
|
-
const { stdout: topLevelOutput } = await
|
|
239466
|
+
const { stdout: topLevelOutput } = await execFileAsync24("git", ["rev-parse", "--show-toplevel"], {
|
|
238958
239467
|
cwd: canonicalCheckout,
|
|
238959
239468
|
encoding: "utf-8",
|
|
238960
239469
|
timeout: 1e4
|
|
@@ -238967,7 +239476,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
|
|
|
238967
239476
|
reason: `checkoutPath must be the Git top-level (observed ${canonicalTopLevel})`
|
|
238968
239477
|
};
|
|
238969
239478
|
}
|
|
238970
|
-
const { stdout: branchOutput } = await
|
|
239479
|
+
const { stdout: branchOutput } = await execFileAsync24("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
238971
239480
|
cwd: canonicalCheckout,
|
|
238972
239481
|
encoding: "utf-8",
|
|
238973
239482
|
timeout: 1e4
|
|
@@ -238977,7 +239486,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
|
|
|
238977
239486
|
return { valid: false, reason: "checkoutPath must have a checked-out branch" };
|
|
238978
239487
|
}
|
|
238979
239488
|
if (options.requireClean) {
|
|
238980
|
-
const { stdout: statusOutput } = await
|
|
239489
|
+
const { stdout: statusOutput } = await execFileAsync24("git", ["status", "--porcelain=v1"], {
|
|
238981
239490
|
cwd: canonicalCheckout,
|
|
238982
239491
|
encoding: "utf-8",
|
|
238983
239492
|
timeout: 1e4
|
|
@@ -239040,9 +239549,9 @@ async function resolveAuthoritativeExternalExecutionRoute(store, task) {
|
|
|
239040
239549
|
import { exec as exec46 } from "node:child_process";
|
|
239041
239550
|
import { existsSync as existsSync70, promises as fs7 } from "node:fs";
|
|
239042
239551
|
import path4 from "node:path";
|
|
239043
|
-
import { promisify as
|
|
239552
|
+
import { promisify as promisify65 } from "node:util";
|
|
239044
239553
|
init_worktree_paths();
|
|
239045
|
-
var execAsync43 =
|
|
239554
|
+
var execAsync43 = promisify65(exec46);
|
|
239046
239555
|
var probeOptions = { encoding: "utf-8", timeout: 1e4, maxBuffer: 1024 * 1024 };
|
|
239047
239556
|
function workspaceExecutionAnchor(task) {
|
|
239048
239557
|
const executionValues = [task.firstExecutionAt, task.executionStartedAt].map((value) => typeof value === "string" ? Date.parse(value) : Number.NaN).filter(Number.isFinite);
|
|
@@ -239162,7 +239671,7 @@ async function detectWorkspaceMainCheckoutWork(deps, task, repos, declaredScope)
|
|
|
239162
239671
|
}
|
|
239163
239672
|
|
|
239164
239673
|
// ../engine/src/executor/worktree-verify-invariants.ts
|
|
239165
|
-
var execAsync44 =
|
|
239674
|
+
var execAsync44 = promisify66(exec47);
|
|
239166
239675
|
async function verifyWorktreeInvariants(deps, task, worktreePathOverride, allowReanchor = true, options) {
|
|
239167
239676
|
const workspaceConfig = deps.ensureWorkspaceConfig ? await deps.ensureWorkspaceConfig() : deps.workspaceConfig;
|
|
239168
239677
|
const settings = await deps.store.getSettings();
|
|
@@ -239567,14 +240076,14 @@ async function emitWorktreeReanchoredAudit(deps, taskId, fromPath, toPath, sourc
|
|
|
239567
240076
|
}
|
|
239568
240077
|
|
|
239569
240078
|
// ../engine/src/executor/worktree-task-done-scope-leak.ts
|
|
239570
|
-
import { execFile as
|
|
240079
|
+
import { execFile as execFile31 } from "node:child_process";
|
|
239571
240080
|
import { access as access9 } from "node:fs/promises";
|
|
239572
|
-
import { promisify as
|
|
240081
|
+
import { promisify as promisify67 } from "node:util";
|
|
239573
240082
|
init_logger();
|
|
239574
|
-
var
|
|
240083
|
+
var execFileAsync25 = promisify67(execFile31);
|
|
239575
240084
|
async function verifyRepositoryCaptureEvidence(worktreePath) {
|
|
239576
240085
|
await access9(worktreePath);
|
|
239577
|
-
const { stdout } = await
|
|
240086
|
+
const { stdout } = await execFileAsync25("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
239578
240087
|
cwd: worktreePath,
|
|
239579
240088
|
encoding: "utf8"
|
|
239580
240089
|
});
|
|
@@ -239591,7 +240100,7 @@ async function captureRepositoryChangeEvidence(worktreePath, baseCommitSha) {
|
|
|
239591
240100
|
} else {
|
|
239592
240101
|
commands.push(["rev-parse", "--verify", "HEAD"]);
|
|
239593
240102
|
}
|
|
239594
|
-
const results = await Promise.all(commands.map((args) =>
|
|
240103
|
+
const results = await Promise.all(commands.map((args) => execFileAsync25("git", args, {
|
|
239595
240104
|
cwd: worktreePath,
|
|
239596
240105
|
encoding: "utf8"
|
|
239597
240106
|
})));
|
|
@@ -239725,8 +240234,8 @@ async function evaluateTaskDoneScopeLeak(deps, task, worktreePath, promptContent
|
|
|
239725
240234
|
init_branch_attribution();
|
|
239726
240235
|
init_logger();
|
|
239727
240236
|
import { exec as exec48 } from "node:child_process";
|
|
239728
|
-
import { promisify as
|
|
239729
|
-
var execAsync45 =
|
|
240237
|
+
import { promisify as promisify68 } from "node:util";
|
|
240238
|
+
var execAsync45 = promisify68(exec48);
|
|
239730
240239
|
async function captureModifiedFiles(worktreePath, baseCommitSha, taskId, audit, source = "unspecified") {
|
|
239731
240240
|
try {
|
|
239732
240241
|
const baseRef = await resolveDiffBaseRef(worktreePath, baseCommitSha);
|
|
@@ -240024,6 +240533,27 @@ ${result.review}`);
|
|
|
240024
240533
|
summarySections.push(`[${repoRel}] ${result.verdict}: ${result.summary}`);
|
|
240025
240534
|
}
|
|
240026
240535
|
const aggregateVerdict = reviewedResults.some(({ result }) => result.verdict === "RETHINK") ? "RETHINK" : reviewedResults.some(({ result }) => result.verdict === "REVISE") ? "REVISE" : reviewedResults.some(({ result }) => !isApprovalFamilyVerdict(result.verdict)) ? "UNAVAILABLE" : "APPROVE";
|
|
240536
|
+
let publishedModifiedFiles = modifiedFiles;
|
|
240537
|
+
if (isApprovalFamilyVerdict(aggregateVerdict) && evidence && options.workspaceRootDir) {
|
|
240538
|
+
try {
|
|
240539
|
+
const refreshed = await captureWorkspaceReviewEvidence({ task, workspaceRootDir: options.workspaceRootDir, settings: options.settings ?? {} });
|
|
240540
|
+
if (refreshed.outOfScopeRepositories.size > 0) {
|
|
240541
|
+
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 };
|
|
240542
|
+
}
|
|
240543
|
+
for (const updated of refreshed.repositories) {
|
|
240544
|
+
const original = evidence.repositories.find((candidate) => candidate.repository === updated.repository);
|
|
240545
|
+
const worktreePath = workspaceWorktrees[updated.repository]?.worktreePath;
|
|
240546
|
+
const outcome = repositoryReviewOutcomes.find((candidate) => candidate.repository === updated.repository && candidate.status === "REVIEWED");
|
|
240547
|
+
if (!original || !worktreePath || !updated.fingerprint || !outcome || !repositoryScope.has(updated.repository)) continue;
|
|
240548
|
+
if (await isFastForwardAdvance(worktreePath, original.branch, updated.branch)) {
|
|
240549
|
+
repositoryDiffFingerprints[updated.repository] = updated.fingerprint;
|
|
240550
|
+
outcome.fingerprint = updated.fingerprint;
|
|
240551
|
+
}
|
|
240552
|
+
}
|
|
240553
|
+
publishedModifiedFiles = refreshed.modifiedFiles;
|
|
240554
|
+
} catch {
|
|
240555
|
+
}
|
|
240556
|
+
}
|
|
240027
240557
|
const blockingRepositories = reviewedResults.filter(({ result }) => !isApprovalFamilyVerdict(result.verdict)).map(({ repository }) => repository);
|
|
240028
240558
|
const blockingSummary = blockingRepositories.length > 0 ? `blocking repositories: ${blockingRepositories.join(", ")}` : `all ${repoKeys.length} modified in-scope repositories approved`;
|
|
240029
240559
|
const coverageNotice = noVerdictRepositories.length > 0 ? `
|
|
@@ -240035,7 +240565,7 @@ Not covered by a verdict: ${noVerdictRepositories.join(", ")}.` : "";
|
|
|
240035
240565
|
${reviewSections.join("\n\n")}`,
|
|
240036
240566
|
summary: `${aggregateVerdict} \u2014 ${blockingSummary} \u2014 ${summarySections.join(" | ")}`,
|
|
240037
240567
|
repositoryDiffFingerprints,
|
|
240038
|
-
repositoryModifiedFiles:
|
|
240568
|
+
repositoryModifiedFiles: publishedModifiedFiles,
|
|
240039
240569
|
repositoryReviewOutcomes,
|
|
240040
240570
|
...findings.length > 0 ? { findings } : {},
|
|
240041
240571
|
repositoryScopeRevision
|
|
@@ -240357,9 +240887,9 @@ init_worktree_names();
|
|
|
240357
240887
|
init_worktree_pool();
|
|
240358
240888
|
init_logger();
|
|
240359
240889
|
import { exec as exec49 } from "node:child_process";
|
|
240360
|
-
import { promisify as
|
|
240890
|
+
import { promisify as promisify69 } from "node:util";
|
|
240361
240891
|
init_lifecycle_columns();
|
|
240362
|
-
var execAsync46 =
|
|
240892
|
+
var execAsync46 = promisify69(exec49);
|
|
240363
240893
|
async function handleDepAbortCleanup(deps, taskId, worktreePath) {
|
|
240364
240894
|
executorLog.log(`${taskId} dependency added \u2014 work discarded, moved to triage for re-planning`);
|
|
240365
240895
|
const task = await deps.store.getTask(taskId);
|
|
@@ -240935,8 +241465,8 @@ async function advanceNoMergeWorkflowToCompleteColumn(store, task) {
|
|
|
240935
241465
|
init_logger();
|
|
240936
241466
|
import { exec as exec50 } from "node:child_process";
|
|
240937
241467
|
import { existsSync as existsSync73, statSync as statSync15 } from "node:fs";
|
|
240938
|
-
import { promisify as
|
|
240939
|
-
var execAsync47 =
|
|
241468
|
+
import { promisify as promisify70 } from "node:util";
|
|
241469
|
+
var execAsync47 = promisify70(exec50);
|
|
240940
241470
|
async function runTaskStep(deps, task, stepIndex, opts = {}) {
|
|
240941
241471
|
const { store, worktreePath } = deps;
|
|
240942
241472
|
const gitRevParse = deps.gitRevParse ?? defaultGitRevParse;
|
|
@@ -243022,8 +243552,8 @@ async function recoverFailedPreMergeWorkflowStep(deps, task) {
|
|
|
243022
243552
|
init_src2();
|
|
243023
243553
|
init_logger();
|
|
243024
243554
|
import { exec as exec51 } from "node:child_process";
|
|
243025
|
-
import { promisify as
|
|
243026
|
-
var execAsync48 =
|
|
243555
|
+
import { promisify as promisify71 } from "node:util";
|
|
243556
|
+
var execAsync48 = promisify71(exec51);
|
|
243027
243557
|
async function reconcileStepsFromGitHistory(deps, taskId, detail, worktreePath) {
|
|
243028
243558
|
const baseCommitSha = detail.baseCommitSha;
|
|
243029
243559
|
if (!baseCommitSha) return;
|
|
@@ -245347,7 +245877,14 @@ async function persistWorkflowStepResultWithOutcome(deps, taskId, result, fence
|
|
|
245347
245877
|
scopeSuperseded = true;
|
|
245348
245878
|
return null;
|
|
245349
245879
|
}
|
|
245350
|
-
const
|
|
245880
|
+
const unprovenApproval = resolveUnprovenReviewApproval(result, {
|
|
245881
|
+
workspace: current.workspaceWorktrees !== void 0
|
|
245882
|
+
});
|
|
245883
|
+
const built = buildWorkflowStepResultPatch(
|
|
245884
|
+
current,
|
|
245885
|
+
unprovenApproval?.downgraded ?? result,
|
|
245886
|
+
isPlanReviewResult
|
|
245887
|
+
);
|
|
245351
245888
|
activityResult = built.resultToPersist;
|
|
245352
245889
|
activityResults = built.results;
|
|
245353
245890
|
return built.patch;
|
|
@@ -245384,21 +245921,30 @@ async function persistWorkflowStepResultWithOutcome(deps, taskId, result, fence
|
|
|
245384
245921
|
if (scopeSuperseded) return { scopeCurrent: false, persisted: false };
|
|
245385
245922
|
if (fenceRefused) return { scopeCurrent: true, persisted: false };
|
|
245386
245923
|
const persistedResult = activityResults?.find((entry) => entry.workflowStepId === result.workflowStepId) ?? activityResult;
|
|
245387
|
-
|
|
245388
|
-
|
|
245924
|
+
const approvalDowngraded = result.status === "passed" && persistedResult.status === "failed" && result.reviewInputFingerprint === void 0 && persistedResult.verdict === void 0;
|
|
245925
|
+
if (approvalDowngraded) {
|
|
245926
|
+
await deps.store.logEntry(
|
|
245927
|
+
taskId,
|
|
245928
|
+
`[pre-merge] ${result.workflowStepName} approval invalidated: ${persistedResult.notes ?? persistedResult.output ?? "review input proof missing"}`,
|
|
245929
|
+
void 0,
|
|
245930
|
+
deps.getRunContextFor(taskId)
|
|
245931
|
+
).catch(() => void 0);
|
|
245932
|
+
}
|
|
245933
|
+
if (isTerminalStepResult(persistedResult)) {
|
|
245934
|
+
const passed = persistedResult.status === "passed" || persistedResult.status === "skipped" || persistedResult.verdict === "APPROVE" || persistedResult.verdict === "APPROVE_WITH_NOTES" || persistedResult.verdict === "CLOSE_NO_OP";
|
|
245389
245935
|
try {
|
|
245390
245936
|
await deps.store.recordAgentActivity({
|
|
245391
245937
|
type: passed ? "workflow:gate-passed" : "workflow:gate-failed",
|
|
245392
245938
|
attributionClaim: resolveWorkflowGateActivityClaim(
|
|
245393
|
-
deps.workflowGateActivityPrincipals?.get(`${taskId}\0${
|
|
245939
|
+
deps.workflowGateActivityPrincipals?.get(`${taskId}\0${persistedResult.workflowStepId}`) ?? deps.activeWorkflowPrincipals?.get(taskId)?.agentId,
|
|
245394
245940
|
live?.assignedAgentId
|
|
245395
245941
|
),
|
|
245396
245942
|
taskId,
|
|
245397
|
-
occurredAt:
|
|
245398
|
-
discriminator: `${
|
|
245399
|
-
metadata: buildWorkflowGateActivityMetadata(
|
|
245943
|
+
occurredAt: persistedResult.completedAt ?? persistedResult.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
245944
|
+
discriminator: `${persistedResult.workflowStepId}:${persistedResult.startedAt ?? persistedResult.completedAt ?? persistedResult.status}`,
|
|
245945
|
+
metadata: buildWorkflowGateActivityMetadata(persistedResult, persistedResult)
|
|
245400
245946
|
});
|
|
245401
|
-
deps.workflowGateActivityPrincipals?.delete(`${taskId}\0${
|
|
245947
|
+
deps.workflowGateActivityPrincipals?.delete(`${taskId}\0${persistedResult.workflowStepId}`);
|
|
245402
245948
|
} catch (error2) {
|
|
245403
245949
|
executorLog.warn(`[agent-activity] ${taskId}: failed to record workflow gate activity: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
245404
245950
|
}
|
|
@@ -247323,8 +247869,8 @@ async function runSpawnedChild(deps, agentId, childSession, taskPrompt) {
|
|
|
247323
247869
|
|
|
247324
247870
|
// ../engine/src/auto-recovery-handlers/file-scope.ts
|
|
247325
247871
|
import { exec as exec52 } from "node:child_process";
|
|
247326
|
-
import { promisify as
|
|
247327
|
-
var execAsync49 =
|
|
247872
|
+
import { promisify as promisify72 } from "node:util";
|
|
247873
|
+
var execAsync49 = promisify72(exec52);
|
|
247328
247874
|
var FileScopeAutoRecoveryHandler = class {
|
|
247329
247875
|
constructor(deps) {
|
|
247330
247876
|
this.deps = deps;
|
|
@@ -247349,8 +247895,8 @@ init_integration_branch();
|
|
|
247349
247895
|
init_logger();
|
|
247350
247896
|
import { exec as exec53 } from "node:child_process";
|
|
247351
247897
|
import { existsSync as existsSync76 } from "node:fs";
|
|
247352
|
-
import { promisify as
|
|
247353
|
-
var execAsync50 =
|
|
247898
|
+
import { promisify as promisify73 } from "node:util";
|
|
247899
|
+
var execAsync50 = promisify73(exec53);
|
|
247354
247900
|
var baseLog2 = createLogger("auto-recovery:branch-worktree");
|
|
247355
247901
|
var GIT_TIMEOUT_MS8 = 3e4;
|
|
247356
247902
|
var GIT_MAX_BUFFER6 = 10 * 1024 * 1024;
|
|
@@ -248340,8 +248886,8 @@ init_src2();
|
|
|
248340
248886
|
init_worktree_names();
|
|
248341
248887
|
init_logger();
|
|
248342
248888
|
import { exec as exec54 } from "node:child_process";
|
|
248343
|
-
import { promisify as
|
|
248344
|
-
var execAsync51 =
|
|
248889
|
+
import { promisify as promisify74 } from "node:util";
|
|
248890
|
+
var execAsync51 = promisify74(exec54);
|
|
248345
248891
|
async function resetStepsIfWorkLost(deps, task) {
|
|
248346
248892
|
const completedSteps = task.steps.filter(
|
|
248347
248893
|
(s3) => s3.status === "done" || s3.status === "in-progress"
|
|
@@ -248416,8 +248962,8 @@ init_worktree_names();
|
|
|
248416
248962
|
init_worktree_paths();
|
|
248417
248963
|
init_logger();
|
|
248418
248964
|
import { exec as exec55 } from "node:child_process";
|
|
248419
|
-
import { promisify as
|
|
248420
|
-
var execAsync52 =
|
|
248965
|
+
import { promisify as promisify75 } from "node:util";
|
|
248966
|
+
var execAsync52 = promisify75(exec55);
|
|
248421
248967
|
var WORKSPACE_ISOLATION_UNSUPPORTED_MESSAGE = "per-instance worktree isolation is not supported for workspace projects";
|
|
248422
248968
|
function buildForeachWorktreeDeps(deps, task, runId) {
|
|
248423
248969
|
const taskId = task.id;
|
|
@@ -248610,7 +249156,7 @@ init_src2();
|
|
|
248610
249156
|
// ../engine/src/executor/derive-remediation-steps.ts
|
|
248611
249157
|
init_src2();
|
|
248612
249158
|
init_merger_file_scope();
|
|
248613
|
-
import { createHash as
|
|
249159
|
+
import { createHash as createHash35 } from "node:crypto";
|
|
248614
249160
|
var fileReference = /(?:^|[\s(])([\w@./-]+\.(?:[cm]?[jt]sx?|json|md|css|html|yml|yaml))(?::(\d+))?/gm;
|
|
248615
249161
|
var ansiEscapeSequence = /\u001B\[[0-?]*[ -/]*[@-~]/g;
|
|
248616
249162
|
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 +249169,7 @@ function normalizeVerificationEvidence(output) {
|
|
|
248623
249169
|
}
|
|
248624
249170
|
function verificationEvidenceDigest(output) {
|
|
248625
249171
|
const evidence = normalizeVerificationEvidence(output);
|
|
248626
|
-
return evidence ?
|
|
249172
|
+
return evidence ? createHash35("sha256").update(evidence).digest("hex").slice(0, 16) : void 0;
|
|
248627
249173
|
}
|
|
248628
249174
|
function verificationCandidates(input) {
|
|
248629
249175
|
const detail = input.verificationCommandLabel ?? "verification command";
|
|
@@ -252011,6 +252557,8 @@ async function runGraphCustomNode(deps, node, nodeTask, settings, columnBinding,
|
|
|
252011
252557
|
}
|
|
252012
252558
|
const optionalGroupId = typeof graphContext?.[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] === "string" ? graphContext[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] : void 0;
|
|
252013
252559
|
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;
|
|
252560
|
+
const effectiveStepId = optionalGroupId ?? node.id;
|
|
252561
|
+
const isContentBindingStep = requiresContentReviewProof(effectiveStepId, { reviewKind: declaredReviewKind });
|
|
252014
252562
|
if (isFastExecutionMode(live) && graphContext?.["workflow:fast-lane-active"] === true && isFastLaneSkippableCustomNode(node, { optionalGroupId })) {
|
|
252015
252563
|
executorLog.debug(`${live.id}: fast mode \u2014 skipping custom graph node '${node.id}'`);
|
|
252016
252564
|
await deps.store.logEntry(
|
|
@@ -252205,6 +252753,7 @@ ${prompt}`;
|
|
|
252205
252753
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
252206
252754
|
const stepSkillName = executorKind === "skill" && typeof cfg.skillName === "string" && cfg.skillName.trim() ? cfg.skillName.trim() : void 0;
|
|
252207
252755
|
const stepThinkingLevel = typeof cfg.thinkingLevel === "string" && WORKFLOW_THINKING_LEVEL_SET2.has(cfg.thinkingLevel) ? cfg.thinkingLevel : void 0;
|
|
252756
|
+
const readonlyMcpServers = Array.isArray(cfg.readonlyMcpServers) ? [...new Set(cfg.readonlyMcpServers.filter((name2) => typeof name2 === "string").map((name2) => name2.trim()).filter(Boolean))] : [];
|
|
252208
252757
|
const step = {
|
|
252209
252758
|
id: `graph:${node.id}`,
|
|
252210
252759
|
name: typeof cfg.name === "string" && cfg.name.trim() ? cfg.name : node.id,
|
|
@@ -252221,7 +252770,8 @@ ${prompt}`;
|
|
|
252221
252770
|
...stepSkillName ? { skillName: stepSkillName } : {},
|
|
252222
252771
|
...cfg.requiresBrowser === true ? { requiresBrowser: true } : {},
|
|
252223
252772
|
...modelProvider && modelId ? { modelProvider, modelId } : {},
|
|
252224
|
-
...stepThinkingLevel ? { thinkingLevel: stepThinkingLevel } : {}
|
|
252773
|
+
...stepThinkingLevel ? { thinkingLevel: stepThinkingLevel } : {},
|
|
252774
|
+
...readonlyMcpServers.length > 0 ? { readonlyMcpServers } : {}
|
|
252225
252775
|
};
|
|
252226
252776
|
if (cfg.summaryTarget === "task") {
|
|
252227
252777
|
step.summaryTarget = "task";
|
|
@@ -252335,12 +252885,36 @@ ${prompt}`;
|
|
|
252335
252885
|
outcome = buildWorkspaceReviewOutcome(aggregate, { superseded: reviewSuperseded });
|
|
252336
252886
|
}
|
|
252337
252887
|
} else {
|
|
252338
|
-
|
|
252339
|
-
|
|
252340
|
-
|
|
252341
|
-
|
|
252342
|
-
|
|
252343
|
-
|
|
252888
|
+
const dispatchSingularStep = async (reviewInputFingerprint) => {
|
|
252889
|
+
if (mode === "script") {
|
|
252890
|
+
const scriptOutcome = await deps.executeScriptWorkflowStep(live, step, worktreePath, settings, nodeEnv);
|
|
252891
|
+
return reviewInputFingerprint === void 0 ? scriptOutcome : { ...scriptOutcome, reviewInputFingerprint };
|
|
252892
|
+
}
|
|
252893
|
+
return deps.executeWorkflowStep(live, step, worktreePath, settings, nodeEnv, {
|
|
252894
|
+
unattended,
|
|
252895
|
+
principalAgentId,
|
|
252896
|
+
outputLanguage,
|
|
252897
|
+
...nodeSessionBoundary ? { sessionBoundary: nodeSessionBoundary } : {},
|
|
252898
|
+
...reviewInputFingerprint !== void 0 ? { reviewInputFingerprint } : {}
|
|
252899
|
+
});
|
|
252900
|
+
};
|
|
252901
|
+
if (isContentBindingStep && !workspaceConfig) {
|
|
252902
|
+
const proof = await resolveContentReviewInputProof(worktreePath, executionTarget.baseCommitSha);
|
|
252903
|
+
if (proof.kind === "unprovable") {
|
|
252904
|
+
const diagnostic = `${step.name} review input is unprovable (${proof.reason}); reviewer dispatch refused.`;
|
|
252905
|
+
await deps.store.logEntry(
|
|
252906
|
+
live.id,
|
|
252907
|
+
`[pre-merge] ${diagnostic}`,
|
|
252908
|
+
void 0,
|
|
252909
|
+
deps.getRunContextFor(live.id)
|
|
252910
|
+
);
|
|
252911
|
+
outcome = { success: false, error: diagnostic, failureValue: "review-input-unprovable" };
|
|
252912
|
+
} else {
|
|
252913
|
+
outcome = await dispatchSingularStep(proof.fingerprint);
|
|
252914
|
+
}
|
|
252915
|
+
} else {
|
|
252916
|
+
outcome = await dispatchSingularStep();
|
|
252917
|
+
}
|
|
252344
252918
|
}
|
|
252345
252919
|
if (declaredReviewKind && typeof outcome.output === "string") {
|
|
252346
252920
|
const rawReviewOutput = outcome.output;
|
|
@@ -253328,7 +253902,7 @@ async function runImplementationPhase(deps, task, prepared) {
|
|
|
253328
253902
|
// ../engine/src/executor/run-implementation.ts
|
|
253329
253903
|
init_src2();
|
|
253330
253904
|
import { exec as exec56 } from "node:child_process";
|
|
253331
|
-
import { promisify as
|
|
253905
|
+
import { promisify as promisify77 } from "node:util";
|
|
253332
253906
|
import { existsSync as existsSync80 } from "node:fs";
|
|
253333
253907
|
import { join as join91 } from "node:path";
|
|
253334
253908
|
import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
|
|
@@ -254203,11 +254777,11 @@ init_logger();
|
|
|
254203
254777
|
// ../engine/src/merge/merger-orphan-rehome.ts
|
|
254204
254778
|
init_src2();
|
|
254205
254779
|
init_merger_ref_update_advance();
|
|
254206
|
-
import { execFile as
|
|
254207
|
-
import { promisify as
|
|
254208
|
-
var
|
|
254780
|
+
import { execFile as execFile32 } from "node:child_process";
|
|
254781
|
+
import { promisify as promisify76 } from "node:util";
|
|
254782
|
+
var execFileAsync26 = promisify76(execFile32);
|
|
254209
254783
|
async function runGit5(args, cwd) {
|
|
254210
|
-
const { stdout } = await
|
|
254784
|
+
const { stdout } = await execFileAsync26("git", args, {
|
|
254211
254785
|
cwd,
|
|
254212
254786
|
encoding: "utf-8",
|
|
254213
254787
|
timeout: 3e4
|
|
@@ -254216,7 +254790,7 @@ async function runGit5(args, cwd) {
|
|
|
254216
254790
|
}
|
|
254217
254791
|
async function isAncestor3(repoDir, ancestor, descendant) {
|
|
254218
254792
|
try {
|
|
254219
|
-
await
|
|
254793
|
+
await execFileAsync26(
|
|
254220
254794
|
"git",
|
|
254221
254795
|
["merge-base", "--is-ancestor", ancestor, descendant],
|
|
254222
254796
|
{ cwd: repoDir, encoding: "utf-8", timeout: 3e4 }
|
|
@@ -254320,7 +254894,7 @@ init_run_audit();
|
|
|
254320
254894
|
init_worktree_acquisition();
|
|
254321
254895
|
init_worktree_paths();
|
|
254322
254896
|
init_worktree_pool();
|
|
254323
|
-
var execAsync53 =
|
|
254897
|
+
var execAsync53 = promisify77(exec56);
|
|
254324
254898
|
var MAX_TASK_DONE_SESSION_RETRIES = 3;
|
|
254325
254899
|
async function parkExternalSessionObstacle(deps, taskId, errorMessage) {
|
|
254326
254900
|
const obstacle = classifyExternalObstacle(errorMessage);
|
|
@@ -260093,8 +260667,8 @@ init_active_session_registry();
|
|
|
260093
260667
|
init_agent_session_helpers();
|
|
260094
260668
|
init_logger();
|
|
260095
260669
|
init_effective_settings();
|
|
260096
|
-
import { execFile as
|
|
260097
|
-
import { promisify as
|
|
260670
|
+
import { execFile as execFile33 } from "node:child_process";
|
|
260671
|
+
import { promisify as promisify78 } from "node:util";
|
|
260098
260672
|
|
|
260099
260673
|
// ../engine/src/agents/workflow-agent-capacity.ts
|
|
260100
260674
|
var WorkflowAgentCapacity = class _WorkflowAgentCapacity {
|
|
@@ -260171,7 +260745,7 @@ var WorkflowAgentCapacity = class _WorkflowAgentCapacity {
|
|
|
260171
260745
|
};
|
|
260172
260746
|
|
|
260173
260747
|
// ../engine/src/executor/wire-executor-lifecycle.ts
|
|
260174
|
-
var
|
|
260748
|
+
var execFileAsync27 = promisify78(execFile33);
|
|
260175
260749
|
async function releaseWorkspaceAcquireClaims(store, taskId) {
|
|
260176
260750
|
for (const entry of activeSessionRegistry.entriesByKind("workspace-repo-acquire")) {
|
|
260177
260751
|
if (entry.taskId === taskId) activeSessionRegistry.unregisterPath(entry.path);
|
|
@@ -260263,7 +260837,7 @@ function wireExecutorLifecycle(deps) {
|
|
|
260263
260837
|
if (await canonicalizeWorktreePath(entry.worktreePath) === await canonicalizeWorktreePath(entry.repoRootDir)) throw new Error("Refusing to remove workspace repository root");
|
|
260264
260838
|
activeSessionRegistry.unregisterPath(entry.worktreePath);
|
|
260265
260839
|
await removeWorktree({ worktreePath: entry.worktreePath, rootDir: entry.repoRootDir, settings: await deps.store.getSettings(), taskId: task.id, reason: RemovalReason.ExecutorDispose, force: true });
|
|
260266
|
-
await
|
|
260840
|
+
await execFileAsync27("git", ["branch", "-D", entry.branch], { cwd: entry.repoRootDir, timeout: 12e4, maxBuffer: 10 * 1024 * 1024 });
|
|
260267
260841
|
if (task.workspaceWorktrees) for (const repoRel of [entry.repoRel, ...entry.aliasRepoRels]) delete task.workspaceWorktrees[repoRel];
|
|
260268
260842
|
removed.push(entry.repoRel);
|
|
260269
260843
|
} catch (error2) {
|
|
@@ -262939,9 +263513,9 @@ var BUNDLED_CLI_ADAPTERS = Object.freeze([
|
|
|
262939
263513
|
|
|
262940
263514
|
// ../engine/src/cli-agent/resume-coordinator.ts
|
|
262941
263515
|
import { existsSync as existsSync83 } from "node:fs";
|
|
262942
|
-
import { execFile as
|
|
262943
|
-
import { promisify as
|
|
262944
|
-
var
|
|
263516
|
+
import { execFile as execFile34 } from "node:child_process";
|
|
263517
|
+
import { promisify as promisify79 } from "node:util";
|
|
263518
|
+
var execFileAsync28 = promisify79(execFile34);
|
|
262945
263519
|
var ORPHANED_LIVE_STATES = /* @__PURE__ */ new Set([
|
|
262946
263520
|
"starting",
|
|
262947
263521
|
"ready",
|
|
@@ -262952,7 +263526,7 @@ var DEFAULT_MAX_RESUME_ATTEMPTS = 2;
|
|
|
262952
263526
|
var DEFAULT_RESUME_BACKOFF_BASE_MS = 1e3;
|
|
262953
263527
|
async function defaultIsWorktreeDirty(worktreePath) {
|
|
262954
263528
|
try {
|
|
262955
|
-
const { stdout } = await
|
|
263529
|
+
const { stdout } = await execFileAsync28("git", ["status", "--porcelain"], {
|
|
262956
263530
|
cwd: worktreePath
|
|
262957
263531
|
});
|
|
262958
263532
|
return stdout.trim().length > 0;
|
|
@@ -265301,7 +265875,7 @@ init_notifier();
|
|
|
265301
265875
|
|
|
265302
265876
|
// ../engine/src/healing/stuck-task-detector.ts
|
|
265303
265877
|
init_logger();
|
|
265304
|
-
import { createHash as
|
|
265878
|
+
import { createHash as createHash36 } from "node:crypto";
|
|
265305
265879
|
var stuckLog = createLogger("stuck-detector");
|
|
265306
265880
|
var LOOP_ACTIVITY_THRESHOLD = 60;
|
|
265307
265881
|
var LOOP_IGNORED_STEP_MIN = 10;
|
|
@@ -265312,7 +265886,7 @@ var TOOL_DETAIL_HASH_HEX_LEN = 16;
|
|
|
265312
265886
|
var NO_PROGRESS_CHURN_THRESHOLD = 25;
|
|
265313
265887
|
var VERIFICATION_DEADLINE_GRACE_MS = 5e3;
|
|
265314
265888
|
function hashToolDetail(detail) {
|
|
265315
|
-
return
|
|
265889
|
+
return createHash36("sha256").update(detail).digest("hex").slice(0, TOOL_DETAIL_HASH_HEX_LEN);
|
|
265316
265890
|
}
|
|
265317
265891
|
function buildToolFingerprint(toolName, toolDetail) {
|
|
265318
265892
|
const name2 = toolName.trim().toLowerCase() || "tool";
|
|
@@ -268021,7 +268595,7 @@ var MissionAutopilot = class {
|
|
|
268021
268595
|
// ../engine/src/missions/mission-execution-loop.ts
|
|
268022
268596
|
init_src2();
|
|
268023
268597
|
import { EventEmitter as EventEmitter26 } from "node:events";
|
|
268024
|
-
import { createHash as
|
|
268598
|
+
import { createHash as createHash37 } from "node:crypto";
|
|
268025
268599
|
|
|
268026
268600
|
// ../engine/src/missions/mission-verification.ts
|
|
268027
268601
|
init_sandbox();
|
|
@@ -268033,8 +268607,8 @@ import { promises as fs9 } from "node:fs";
|
|
|
268033
268607
|
import os7 from "node:os";
|
|
268034
268608
|
import path5 from "node:path";
|
|
268035
268609
|
import { exec as exec58 } from "node:child_process";
|
|
268036
|
-
import { promisify as
|
|
268037
|
-
var execAsync54 =
|
|
268610
|
+
import { promisify as promisify80 } from "node:util";
|
|
268611
|
+
var execAsync54 = promisify80(exec58);
|
|
268038
268612
|
var verifyLog = createLogger("mission-verify");
|
|
268039
268613
|
var GitCheckoutMaterializer = class {
|
|
268040
268614
|
async materialize(rootDir, revision) {
|
|
@@ -268083,8 +268657,8 @@ init_fallback_model_observer();
|
|
|
268083
268657
|
init_mcp_resolution();
|
|
268084
268658
|
init_run_audit();
|
|
268085
268659
|
import { exec as exec59 } from "node:child_process";
|
|
268086
|
-
import { promisify as
|
|
268087
|
-
var execAsync55 =
|
|
268660
|
+
import { promisify as promisify81 } from "node:util";
|
|
268661
|
+
var execAsync55 = promisify81(exec59);
|
|
268088
268662
|
function quoteShellArg8(value) {
|
|
268089
268663
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
268090
268664
|
}
|
|
@@ -268094,7 +268668,7 @@ var MAX_VALIDATION_RESPONSE_BYTES = 256 * 1024;
|
|
|
268094
268668
|
var MAX_VALIDATION_JSON_CANDIDATES = 8;
|
|
268095
268669
|
var VALIDATION_FAILURE_BUDGET_PER_FINGERPRINT = 3;
|
|
268096
268670
|
function fingerprintMissionValidationInput(landedSha, provider, modelId, systemPrompt, userPrompt) {
|
|
268097
|
-
return
|
|
268671
|
+
return createHash37("sha256").update(Buffer.from(JSON.stringify(["mission-validation-input-v1", landedSha, provider, modelId, systemPrompt, userPrompt]), "utf8")).digest("hex");
|
|
268098
268672
|
}
|
|
268099
268673
|
var MissionExecutionLoop = class extends EventEmitter26 {
|
|
268100
268674
|
running = false;
|
|
@@ -269802,7 +270376,7 @@ import { exec as exec60 } from "node:child_process";
|
|
|
269802
270376
|
import { existsSync as existsSync84 } from "node:fs";
|
|
269803
270377
|
import { readFile as readFile50, writeFile as writeFile29, rm as rm16 } from "node:fs/promises";
|
|
269804
270378
|
import { join as join94 } from "node:path";
|
|
269805
|
-
import { promisify as
|
|
270379
|
+
import { promisify as promisify82 } from "node:util";
|
|
269806
270380
|
|
|
269807
270381
|
// ../engine/src/triage-domain/triage-preflight.ts
|
|
269808
270382
|
var BUG_FIX_REGEX = /typecheck error|compile error|broken|regression|lint error/i;
|
|
@@ -273020,7 +273594,7 @@ ${lines.join("\n")}` }],
|
|
|
273020
273594
|
written,
|
|
273021
273595
|
{
|
|
273022
273596
|
cwd: this.rootDir,
|
|
273023
|
-
exec:
|
|
273597
|
+
exec: promisify82(exec60)
|
|
273024
273598
|
}
|
|
273025
273599
|
),
|
|
273026
273600
|
new Promise((resolve52) => setTimeout(() => resolve52(null), 15e3))
|
|
@@ -273797,7 +274371,7 @@ function stableNotificationJson(value) {
|
|
|
273797
274371
|
return `{${fields.join(",")}}`;
|
|
273798
274372
|
}
|
|
273799
274373
|
function buildCliAgentNotificationDedupeKey(input) {
|
|
273800
|
-
const notificationFingerprint =
|
|
274374
|
+
const notificationFingerprint = createHash38("sha256").update(stableNotificationJson(input.info.notification ?? null)).digest("hex").slice(0, 16);
|
|
273801
274375
|
const waitingEpoch = input.session?.updatedAt ?? "unknown-waiting-epoch";
|
|
273802
274376
|
return [
|
|
273803
274377
|
"cli-agent",
|
|
@@ -278487,8 +279061,8 @@ init_src2();
|
|
|
278487
279061
|
init_agent_user_comments();
|
|
278488
279062
|
init_worktree_names();
|
|
278489
279063
|
init_integration_branch();
|
|
278490
|
-
import { execFile as
|
|
278491
|
-
import { promisify as
|
|
279064
|
+
import { execFile as execFile39 } from "node:child_process";
|
|
279065
|
+
import { promisify as promisify87 } from "node:util";
|
|
278492
279066
|
import { realpathSync as realpathSync15, readdirSync as readdirSync13 } from "node:fs";
|
|
278493
279067
|
import { mkdtemp as mkdtemp5 } from "node:fs/promises";
|
|
278494
279068
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
@@ -278497,10 +279071,10 @@ init_workspace_base_branch();
|
|
|
278497
279071
|
init_merger_ref_update_advance();
|
|
278498
279072
|
|
|
278499
279073
|
// ../engine/src/merge/merger-ai-squash-gates.ts
|
|
278500
|
-
import { execFile as
|
|
278501
|
-
import { promisify as
|
|
279074
|
+
import { execFile as execFile35 } from "node:child_process";
|
|
279075
|
+
import { promisify as promisify83 } from "node:util";
|
|
278502
279076
|
init_merger_file_scope();
|
|
278503
|
-
var
|
|
279077
|
+
var execFileAsync29 = promisify83(execFile35);
|
|
278504
279078
|
function resolveRepoDeclaredScopeTransform({ repoRel, repoKeys }) {
|
|
278505
279079
|
return {
|
|
278506
279080
|
transform(scope) {
|
|
@@ -278531,8 +279105,8 @@ async function enforceAiMergeSquashGates(params) {
|
|
|
278531
279105
|
});
|
|
278532
279106
|
} catch (error2) {
|
|
278533
279107
|
if (!(error2 instanceof FileScopeViolationError)) throw error2;
|
|
278534
|
-
await
|
|
278535
|
-
await
|
|
279108
|
+
await execFileAsync29("git", ["reset", "--hard", params.tipSha], { cwd: params.mergeRoot });
|
|
279109
|
+
await execFileAsync29("git", ["clean", "-fd"], { cwd: params.mergeRoot });
|
|
278536
279110
|
try {
|
|
278537
279111
|
await params.store.updateTask(params.taskId, { aiMergeReviewReconciliation: null });
|
|
278538
279112
|
} catch {
|
|
@@ -278721,10 +279295,10 @@ function resolveWorkspaceMergeReadiness(task, freshModifiedRepositories, netZero
|
|
|
278721
279295
|
}
|
|
278722
279296
|
|
|
278723
279297
|
// ../engine/src/merge/workspace-fence-ref.ts
|
|
278724
|
-
import { execFile as
|
|
278725
|
-
import { createHash as
|
|
278726
|
-
import { promisify as
|
|
278727
|
-
var
|
|
279298
|
+
import { execFile as execFile36 } from "node:child_process";
|
|
279299
|
+
import { createHash as createHash39 } from "node:crypto";
|
|
279300
|
+
import { promisify as promisify84 } from "node:util";
|
|
279301
|
+
var execFileAsync30 = promisify84(execFile36);
|
|
278728
279302
|
var WorkspaceFenceRefError = class extends Error {
|
|
278729
279303
|
constructor(message, kind) {
|
|
278730
279304
|
super(message);
|
|
@@ -278733,7 +279307,7 @@ var WorkspaceFenceRefError = class extends Error {
|
|
|
278733
279307
|
}
|
|
278734
279308
|
};
|
|
278735
279309
|
async function git6(args, cwd) {
|
|
278736
|
-
const { stdout } = await
|
|
279310
|
+
const { stdout } = await execFileAsync30("git", args, {
|
|
278737
279311
|
cwd,
|
|
278738
279312
|
encoding: "utf8",
|
|
278739
279313
|
maxBuffer: 1024 * 1024
|
|
@@ -278746,7 +279320,7 @@ async function remoteRefSha(remote, ref, cwd) {
|
|
|
278746
279320
|
return /^[0-9a-f]{40,64}$/i.test(sha ?? "") ? sha : void 0;
|
|
278747
279321
|
}
|
|
278748
279322
|
function workspaceLandFenceRef(repoRelPath) {
|
|
278749
|
-
const slug2 =
|
|
279323
|
+
const slug2 = createHash39("sha256").update(repoRelPath).digest("hex").slice(0, 24);
|
|
278750
279324
|
return `refs/fusion/workspace-lease/${slug2}`;
|
|
278751
279325
|
}
|
|
278752
279326
|
function mergeDispatchFenceRef(taskId) {
|
|
@@ -278755,7 +279329,7 @@ function mergeDispatchFenceRef(taskId) {
|
|
|
278755
279329
|
async function createFenceObject(cwd, handle2) {
|
|
278756
279330
|
const tree = await git6(["hash-object", "-w", "-t", "tree", "/dev/null"], cwd);
|
|
278757
279331
|
const message = `workspace lease ${handle2.leaseKey} ${handle2.owner.taskId} ${handle2.owner.nodeId} ${handle2.owner.incarnationId} ${handle2.fenceToken}`;
|
|
278758
|
-
const { stdout } = await
|
|
279332
|
+
const { stdout } = await execFileAsync30("git", [
|
|
278759
279333
|
"-c",
|
|
278760
279334
|
"user.name=Fusion",
|
|
278761
279335
|
"-c",
|
|
@@ -278890,9 +279464,9 @@ async function publishWorkspaceIntegrationRef(input) {
|
|
|
278890
279464
|
init_push_after_merge_policy();
|
|
278891
279465
|
|
|
278892
279466
|
// ../engine/src/merge/workspace-integration-target.ts
|
|
278893
|
-
import { execFile as
|
|
278894
|
-
import { promisify as
|
|
278895
|
-
var
|
|
279467
|
+
import { execFile as execFile37 } from "node:child_process";
|
|
279468
|
+
import { promisify as promisify85 } from "node:util";
|
|
279469
|
+
var execFileAsync31 = promisify85(execFile37);
|
|
278896
279470
|
var WorkspaceEnvironmentError = class extends Error {
|
|
278897
279471
|
constructor(repository, resource, action, message) {
|
|
278898
279472
|
super(message);
|
|
@@ -278912,7 +279486,7 @@ var WorkspaceIntegrationTargetError = class extends WorkspaceEnvironmentError {
|
|
|
278912
279486
|
}
|
|
278913
279487
|
};
|
|
278914
279488
|
async function git7(args, cwd) {
|
|
278915
|
-
const { stdout } = await
|
|
279489
|
+
const { stdout } = await execFileAsync31("git", args, { cwd, encoding: "utf8" });
|
|
278916
279490
|
return stdout.trim();
|
|
278917
279491
|
}
|
|
278918
279492
|
async function resolveWorkspaceIntegrationTarget(input) {
|
|
@@ -278959,17 +279533,17 @@ init_worktree_paths();
|
|
|
278959
279533
|
|
|
278960
279534
|
// ../engine/src/merge/merger-ai-worktree.ts
|
|
278961
279535
|
init_active_session_registry();
|
|
278962
|
-
import { execFile as
|
|
279536
|
+
import { execFile as execFile38 } from "node:child_process";
|
|
278963
279537
|
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
279538
|
import { rm as rm17 } from "node:fs/promises";
|
|
278965
279539
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
278966
279540
|
import { isAbsolute as isAbsolute27, join as join96, relative as relative23 } from "node:path";
|
|
278967
|
-
import { promisify as
|
|
279541
|
+
import { promisify as promisify86 } from "node:util";
|
|
278968
279542
|
init_worktree_paths();
|
|
278969
279543
|
init_worktree_removal_retry();
|
|
278970
|
-
var
|
|
279544
|
+
var execFileAsync32 = promisify86(execFile38);
|
|
278971
279545
|
async function git8(args, cwd, opts = {}) {
|
|
278972
|
-
const { stdout } = await
|
|
279546
|
+
const { stdout } = await execFileAsync32("git", args, {
|
|
278973
279547
|
cwd,
|
|
278974
279548
|
encoding: "utf-8",
|
|
278975
279549
|
timeout: opts.timeout ?? 12e4,
|
|
@@ -278998,14 +279572,7 @@ function ensureAiMergeRootIgnored(projectRootDir, settings) {
|
|
|
278998
279572
|
if (!existsSync87(excludePath)) return;
|
|
278999
279573
|
try {
|
|
279000
279574
|
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
|
-
}
|
|
279575
|
+
const entries = resolveAiMergeSearchRoots(projectRootDir, settings).map((root) => relative23(projectRootDir, root)).filter((root) => root && !root.startsWith("..") && !isAbsolute27(root)).map((root) => `${root.replaceAll("\\", "/")}/`);
|
|
279009
279576
|
const missing = entries.filter((entry) => !current.split(/\r?\n/).includes(entry));
|
|
279010
279577
|
if (missing.length > 0) {
|
|
279011
279578
|
appendFileSync2(excludePath, `${current.endsWith("\n") ? "" : "\n"}${missing.join("\n")}
|
|
@@ -279021,7 +279588,7 @@ function resolveAiMergeRoot(projectRootDir, settings) {
|
|
|
279021
279588
|
return root;
|
|
279022
279589
|
}
|
|
279023
279590
|
function getAiMergeTempSearchRoots(projectRootDir, settings) {
|
|
279024
|
-
const roots = [resolveAiMergeRoot(projectRootDir, settings),
|
|
279591
|
+
const roots = [resolveAiMergeRoot(projectRootDir, settings), ...resolveAiMergeSearchRoots(projectRootDir, settings), tmpdir11()];
|
|
279025
279592
|
const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
|
|
279026
279593
|
if (testWorkerRoot) {
|
|
279027
279594
|
try {
|
|
@@ -279074,7 +279641,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log4
|
|
|
279074
279641
|
let alreadyAbsent = false;
|
|
279075
279642
|
try {
|
|
279076
279643
|
cleanupAttempted = true;
|
|
279077
|
-
await
|
|
279644
|
+
await execFileAsync32("git", ["worktree", "remove", "--force", canonicalPath], {
|
|
279078
279645
|
cwd: projectRootDir,
|
|
279079
279646
|
timeout: 3e4
|
|
279080
279647
|
});
|
|
@@ -279105,7 +279672,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log4
|
|
|
279105
279672
|
}
|
|
279106
279673
|
if (cleanupAttempted) {
|
|
279107
279674
|
try {
|
|
279108
|
-
await
|
|
279675
|
+
await execFileAsync32("git", ["worktree", "prune"], { cwd: projectRootDir, timeout: 3e4 });
|
|
279109
279676
|
} catch (err) {
|
|
279110
279677
|
await log42(`AI merge pre-merge prune: git worktree prune failed: ${describeCleanupError(err)}`);
|
|
279111
279678
|
}
|
|
@@ -279514,7 +280081,7 @@ function short(sha) {
|
|
|
279514
280081
|
}
|
|
279515
280082
|
|
|
279516
280083
|
// ../engine/src/merge/merger-ai.ts
|
|
279517
|
-
var
|
|
280084
|
+
var execFileAsync33 = promisify87(execFile39);
|
|
279518
280085
|
var aiMergeLog = createLogger("merger-ai");
|
|
279519
280086
|
async function resolveNoOpFinalizeGateIds3(store, task) {
|
|
279520
280087
|
const selection = store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(task.id) : store.getTaskWorkflowSelection?.(task.id);
|
|
@@ -279540,7 +280107,7 @@ function writeTransientMergeStatus(store, taskId, signal, status) {
|
|
|
279540
280107
|
return fence.write("lifecycle", () => store.updateTask(taskId, { status }).catch(() => void 0));
|
|
279541
280108
|
}
|
|
279542
280109
|
async function git9(args, cwd, opts = {}) {
|
|
279543
|
-
const { stdout } = await
|
|
280110
|
+
const { stdout } = await execFileAsync33("git", args, {
|
|
279544
280111
|
cwd,
|
|
279545
280112
|
encoding: "utf-8",
|
|
279546
280113
|
timeout: opts.timeout ?? 12e4,
|
|
@@ -279581,7 +280148,7 @@ function boundBlockingReviewReasons(reasons) {
|
|
|
279581
280148
|
}
|
|
279582
280149
|
function listAiMergeWorktreeCandidates(taskId, projectRootDir, settings) {
|
|
279583
280150
|
const prefix = `fusion-ai-merge-${taskId.toLowerCase()}-`;
|
|
279584
|
-
const roots = Array.from(/* @__PURE__ */ new Set([resolveAiMergeRoot(projectRootDir, settings),
|
|
280151
|
+
const roots = Array.from(/* @__PURE__ */ new Set([resolveAiMergeRoot(projectRootDir, settings), ...resolveAiMergeSearchRoots(projectRootDir, settings), tmpdir12()]));
|
|
279585
280152
|
const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
|
|
279586
280153
|
if (testWorkerRoot) {
|
|
279587
280154
|
try {
|
|
@@ -282166,8 +282733,8 @@ init_transient_merge_error_classifier();
|
|
|
282166
282733
|
|
|
282167
282734
|
// ../engine/src/remote-access/remote-tunnel-service.ts
|
|
282168
282735
|
init_logger();
|
|
282169
|
-
import { execFile as
|
|
282170
|
-
import { promisify as
|
|
282736
|
+
import { execFile as execFile41 } from "node:child_process";
|
|
282737
|
+
import { promisify as promisify89 } from "node:util";
|
|
282171
282738
|
|
|
282172
282739
|
// ../engine/src/local-dashboard-port.ts
|
|
282173
282740
|
var DEFAULT_DASHBOARD_PORT = 4040;
|
|
@@ -282180,8 +282747,8 @@ function getLocalDashboardPort() {
|
|
|
282180
282747
|
init_src2();
|
|
282181
282748
|
init_logger();
|
|
282182
282749
|
import { EventEmitter as EventEmitter28 } from "node:events";
|
|
282183
|
-
import { exec as exec61, execFile as
|
|
282184
|
-
import { promisify as
|
|
282750
|
+
import { exec as exec61, execFile as execFile40, spawn as spawn8 } from "node:child_process";
|
|
282751
|
+
import { promisify as promisify88 } from "node:util";
|
|
282185
282752
|
|
|
282186
282753
|
// ../engine/src/remote-access/provider-adapters.ts
|
|
282187
282754
|
import { accessSync, constants as fsConstants5 } from "node:fs";
|
|
@@ -282349,8 +282916,8 @@ var DEFAULT_MAX_LOG_ENTRIES = 400;
|
|
|
282349
282916
|
var DEFAULT_STOP_TIMEOUT_MS2 = 5e3;
|
|
282350
282917
|
var DEFAULT_RESTART_BASE_DELAY_MS = 1e3;
|
|
282351
282918
|
var DEFAULT_RESTART_MAX_DELAY_MS = 3e4;
|
|
282352
|
-
var
|
|
282353
|
-
var execAsync56 =
|
|
282919
|
+
var execFileAsync34 = promisify88(execFile40);
|
|
282920
|
+
var execAsync56 = promisify88(exec61);
|
|
282354
282921
|
function serveConfigScopes(config3) {
|
|
282355
282922
|
const foreground = Object.values(config3.Foreground ?? {}).filter(
|
|
282356
282923
|
(scope) => Boolean(scope)
|
|
@@ -282500,7 +283067,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
282500
283067
|
return null;
|
|
282501
283068
|
}
|
|
282502
283069
|
try {
|
|
282503
|
-
const { stdout } = await
|
|
283070
|
+
const { stdout } = await execFileAsync34("tailscale", ["status", "--json"], { timeout: 3e3 });
|
|
282504
283071
|
const data = JSON.parse(String(stdout));
|
|
282505
283072
|
const dnsName = data.Self?.DNSName?.replace(/\.$/, "");
|
|
282506
283073
|
if (!dnsName) {
|
|
@@ -282523,7 +283090,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
282523
283090
|
];
|
|
282524
283091
|
for (const resetCommand of resetCommands) {
|
|
282525
283092
|
try {
|
|
282526
|
-
await
|
|
283093
|
+
await execFileAsync34(resetCommand.command, resetCommand.args, { timeout: 5e3 });
|
|
282527
283094
|
return;
|
|
282528
283095
|
} catch {
|
|
282529
283096
|
}
|
|
@@ -282629,7 +283196,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
282629
283196
|
async detectActiveFunnel() {
|
|
282630
283197
|
let stdout = "";
|
|
282631
283198
|
try {
|
|
282632
|
-
const result = await
|
|
283199
|
+
const result = await execFileAsync34("tailscale", ["serve", "status", "--json"], { timeout: 5e3 });
|
|
282633
283200
|
stdout = String(result.stdout ?? "");
|
|
282634
283201
|
} catch (error2) {
|
|
282635
283202
|
const failure = error2;
|
|
@@ -283045,7 +283612,7 @@ var TunnelProcessManager = class extends EventEmitter28 {
|
|
|
283045
283612
|
};
|
|
283046
283613
|
|
|
283047
283614
|
// ../engine/src/remote-access/remote-tunnel-service.ts
|
|
283048
|
-
var
|
|
283615
|
+
var execFileAsync35 = promisify89(execFile41);
|
|
283049
283616
|
var isRemoteActive = (ra) => ra?.activeProvider != null && (ra.providers[ra.activeProvider]?.enabled ?? false);
|
|
283050
283617
|
var RemoteTunnelService = class {
|
|
283051
283618
|
manager = new TunnelProcessManager();
|
|
@@ -283394,7 +283961,7 @@ var RemoteTunnelService = class {
|
|
|
283394
283961
|
async checkTailscaleDaemonReady() {
|
|
283395
283962
|
let stdout = "";
|
|
283396
283963
|
try {
|
|
283397
|
-
const result = await
|
|
283964
|
+
const result = await execFileAsync35("tailscale", ["status", "--json"], {
|
|
283398
283965
|
timeout: 5e3,
|
|
283399
283966
|
maxBuffer: 8 * 1024 * 1024
|
|
283400
283967
|
});
|
|
@@ -283442,7 +284009,7 @@ var RemoteTunnelService = class {
|
|
|
283442
284009
|
async checkExecutableAvailable(command) {
|
|
283443
284010
|
const checker = process.platform === "win32" ? "where" : "which";
|
|
283444
284011
|
try {
|
|
283445
|
-
await
|
|
284012
|
+
await execFileAsync35(checker, [command]);
|
|
283446
284013
|
return { available: true };
|
|
283447
284014
|
} catch {
|
|
283448
284015
|
return {
|
|
@@ -283625,7 +284192,7 @@ function emitMergeRequestShadowDequeueParityAudit(store, legacyTaskId, shadowTas
|
|
|
283625
284192
|
metadata: { legacyTaskId, shadowTaskId, agree }
|
|
283626
284193
|
}, { log: runtimeLog });
|
|
283627
284194
|
}
|
|
283628
|
-
var
|
|
284195
|
+
var execFileAsync36 = promisify90(execFile42);
|
|
283629
284196
|
var MERGE_HANDOFF_GRACE_MS = 300;
|
|
283630
284197
|
function isActiveMergeRequestState(state) {
|
|
283631
284198
|
return state === "running" || state === "retrying";
|
|
@@ -283671,7 +284238,7 @@ async function verifyMergeConfirmedReachability(args) {
|
|
|
283671
284238
|
return { reachable: true, skipped: "no-integration-branch" };
|
|
283672
284239
|
}
|
|
283673
284240
|
try {
|
|
283674
|
-
await
|
|
284241
|
+
await execFileAsync36("git", ["cat-file", "-e", `${commitSha}^{commit}`], {
|
|
283675
284242
|
cwd,
|
|
283676
284243
|
timeout: 1e4
|
|
283677
284244
|
});
|
|
@@ -283680,7 +284247,7 @@ async function verifyMergeConfirmedReachability(args) {
|
|
|
283680
284247
|
return { reachable: false, reason: "commit-missing", diagnostic };
|
|
283681
284248
|
}
|
|
283682
284249
|
try {
|
|
283683
|
-
await
|
|
284250
|
+
await execFileAsync36(
|
|
283684
284251
|
"git",
|
|
283685
284252
|
["merge-base", "--is-ancestor", commitSha, `refs/heads/${integrationBranch}`],
|
|
283686
284253
|
{ cwd, timeout: 1e4 }
|
|
@@ -283756,6 +284323,7 @@ var ProjectEngine = class _ProjectEngine {
|
|
|
283756
284323
|
}
|
|
283757
284324
|
});
|
|
283758
284325
|
}
|
|
284326
|
+
staleContentRerouteAuditKeys = /* @__PURE__ */ new Set();
|
|
283759
284327
|
runtime;
|
|
283760
284328
|
started = false;
|
|
283761
284329
|
specDriftReconciler;
|
|
@@ -285552,11 +286120,44 @@ ${detail}`);
|
|
|
285552
286120
|
workspaceRootDir: this.config.workingDirectory,
|
|
285553
286121
|
settings
|
|
285554
286122
|
});
|
|
285555
|
-
|
|
286123
|
+
const blocker = getTaskMergeBlocker(task, {
|
|
285556
286124
|
reviewColumns: mergeGate.reviewColumns.size > 0 ? mergeGate.reviewColumns : /* @__PURE__ */ new Set(["in-review"]),
|
|
285557
286125
|
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
285558
286126
|
mergeContent
|
|
285559
286127
|
});
|
|
286128
|
+
if (blocker === "task has a pre-merge approval recorded against different content" && mergeContent.kind === "singular") {
|
|
286129
|
+
const reroute = await rerouteSingularStaleContentToReview(store, task, {
|
|
286130
|
+
requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
|
|
286131
|
+
mergeContent
|
|
286132
|
+
}).catch(() => ({
|
|
286133
|
+
rerouted: false,
|
|
286134
|
+
reason: "no-progress",
|
|
286135
|
+
nodeId: void 0,
|
|
286136
|
+
workflowStepId: void 0
|
|
286137
|
+
}));
|
|
286138
|
+
if (reroute.rerouted) {
|
|
286139
|
+
await store.logEntry(task.id, `[pre-merge] Code Review re-entry is owned by the workflow graph after stale content evidence was refused.`);
|
|
286140
|
+
}
|
|
286141
|
+
const auditKey = `${task.id}:${reroute.reason}`;
|
|
286142
|
+
if (!this.staleContentRerouteAuditKeys.has(auditKey)) {
|
|
286143
|
+
this.staleContentRerouteAuditKeys.add(auditKey);
|
|
286144
|
+
await emitBoundedRunAudit2(store, {
|
|
286145
|
+
taskId: task.id,
|
|
286146
|
+
agentId: "merge-gate",
|
|
286147
|
+
runId: `${task.id}:merge-gate`,
|
|
286148
|
+
domain: "database",
|
|
286149
|
+
mutationType: "task:merge-stale-content-review-rerouted",
|
|
286150
|
+
target: task.id,
|
|
286151
|
+
metadata: {
|
|
286152
|
+
taskId: task.id,
|
|
286153
|
+
nodeId: reroute.nodeId,
|
|
286154
|
+
workflowStepId: reroute.workflowStepId,
|
|
286155
|
+
reason: reroute.reason
|
|
286156
|
+
}
|
|
286157
|
+
});
|
|
286158
|
+
}
|
|
286159
|
+
}
|
|
286160
|
+
return blocker;
|
|
285560
286161
|
}
|
|
285561
286162
|
/**
|
|
285562
286163
|
* Remove and return the highest-priority taskId from the merge queue.
|
|
@@ -286402,7 +287003,7 @@ ${detail}`);
|
|
|
286402
287003
|
}
|
|
286403
287004
|
const checklist = planConfirmedMergeChecklistReconciliation(task);
|
|
286404
287005
|
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);
|
|
287006
|
+
const steps = (task.steps ?? []).map((step, index2) => checklist.skippedStepIndexes.includes(index2) ? { ...step, status: "skipped" } : step);
|
|
286406
287007
|
const workflowStepResults = (task.workflowStepResults ?? []).map((result) => checklist.reconciledWorkflowStepIds.includes(result.workflowStepId) ? { ...result, status: "skipped" } : result);
|
|
286407
287008
|
await store.updateTask(taskId, { steps, workflowStepResults });
|
|
286408
287009
|
task.steps = steps;
|