Skip to content

Commit 933d57b

Browse files
Merge pull request #109 from haifeng-li-at-salesforce/generateProjectRuntime
Magen: Generate project within GraphNode instead of Tool
2 parents 6831612 + 6eedd63 commit 933d57b

File tree

10 files changed

+1736
-852
lines changed

10 files changed

+1736
-852
lines changed

packages/mobile-native-mcp-server/src/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { UtilsXcodeAddFilesTool } from './tools/utils/utils-xcode-add-files/tool
1515
import { SFMobileNativeDeploymentTool } from './tools/run/sfmobile-native-deployment/tool.js';
1616
import { SFMobileNativeBuildTool } from './tools/plan/sfmobile-native-build/tool.js';
1717
import { SFMobileNativeBuildRecoveryTool } from './tools/plan/sfmobile-native-build-recovery/tool.js';
18-
import { SFMobileNativeProjectGenerationTool } from './tools/plan/sfmobile-native-project-generation/tool.js';
1918
import { MobileNativeOrchestrator } from './tools/workflow/sfmobile-native-project-manager/tool.js';
2019
import { SFMobileNativeCompletionTool } from './tools/workflow/sfmobile-native-completion/tool.js';
2120
import { SFMobileNativeFailureTool } from './tools/workflow/sfmobile-native-failure/tool.js';
@@ -53,7 +52,6 @@ const orchestrator = new MobileNativeOrchestrator(server);
5352
const getInputTool = createSFMobileNativeGetInputTool(server);
5453
const inputExtractionTool = createSFMobileNativeInputExtractionTool(server);
5554
const templateSelectionTool = new SFMobileNativeTemplateSelectionTool(server);
56-
const projectGenerationTool = new SFMobileNativeProjectGenerationTool(server);
5755
const buildTool = new SFMobileNativeBuildTool(server);
5856
const buildRecoveryTool = new SFMobileNativeBuildRecoveryTool(server);
5957
const deploymentTool = new SFMobileNativeDeploymentTool(server);
@@ -74,7 +72,6 @@ orchestrator.register(orchestratorAnnotations);
7472
getInputTool.register(readOnlyAnnotations);
7573
inputExtractionTool.register(readOnlyAnnotations);
7674
templateSelectionTool.register(readOnlyAnnotations);
77-
projectGenerationTool.register(readOnlyAnnotations);
7875
buildTool.register(readOnlyAnnotations);
7976
buildRecoveryTool.register(readOnlyAnnotations);
8077
deploymentTool.register(readOnlyAnnotations);

packages/mobile-native-mcp-server/src/tools/plan/sfmobile-native-project-generation/metadata.ts

Lines changed: 0 additions & 61 deletions
This file was deleted.

packages/mobile-native-mcp-server/src/tools/plan/sfmobile-native-project-generation/tool.ts

Lines changed: 0 additions & 90 deletions
This file was deleted.

packages/mobile-native-mcp-server/src/workflow/graph.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { CheckAndroidSetupExtractedRouter } from './nodes/checkAndroidSetupExtra
3232
import { ExtractAndroidSetupNode } from './nodes/extractAndroidSetup.js';
3333
import { PluginCheckNode } from './nodes/checkPluginSetup.js';
3434
import { CheckPluginValidatedRouter } from './nodes/checkPluginValidatedRouter.js';
35+
import { CheckProjectGenerationRouter } from './nodes/checkProjectGenerationRouter.js';
3536
import {
3637
createGetUserInputNode,
3738
createUserInputExtractionNode,
@@ -98,6 +99,11 @@ const checkAndroidSetupExtractedRouter = new CheckAndroidSetupExtractedRouter(
9899
failureNode.name
99100
);
100101

102+
const checkProjectGenerationRouter = new CheckProjectGenerationRouter(
103+
buildValidationNode.name,
104+
failureNode.name
105+
);
106+
101107
const checkBuildSuccessfulRouter = new CheckBuildSuccessfulRouter(
102108
deploymentNode.name,
103109
buildRecoveryNode.name,
@@ -151,7 +157,7 @@ export const mobileNativeWorkflow = new StateGraph(MobileNativeWorkflowState)
151157
checkTemplatePropertiesFulfilledRouter.execute
152158
)
153159
.addEdge(templatePropertiesUserInputNode.name, templatePropertiesExtractionNode.name)
154-
.addEdge(projectGenerationNode.name, buildValidationNode.name)
160+
.addConditionalEdges(projectGenerationNode.name, checkProjectGenerationRouter.execute)
155161
// Build validation with recovery loop (similar to user input loop)
156162
.addConditionalEdges(buildValidationNode.name, checkBuildSuccessfulRouter.execute)
157163
.addEdge(buildRecoveryNode.name, buildValidationNode.name)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2025, salesforce.com, inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: MIT
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6+
*/
7+
8+
import { State } from '../metadata.js';
9+
import { createComponentLogger } from '@salesforce/magen-mcp-workflow';
10+
11+
/**
12+
* Conditional router edge to check if project generation was successful.
13+
* Routes based on whether the projectPath was set and no fatal errors occurred.
14+
*/
15+
export class CheckProjectGenerationRouter {
16+
private readonly successNodeName: string;
17+
private readonly failureNodeName: string;
18+
private readonly logger = createComponentLogger('CheckProjectGenerationRouter');
19+
20+
/**
21+
* Creates a new CheckProjectGenerationRouter.
22+
*
23+
* @param successNodeName - The name of the node to route to if project generation was successful (build validation)
24+
* @param failureNodeName - The name of the node to route to if generation failed
25+
*/
26+
constructor(successNodeName: string, failureNodeName: string) {
27+
this.successNodeName = successNodeName;
28+
this.failureNodeName = failureNodeName;
29+
}
30+
31+
execute = (state: State): string => {
32+
// Check if project generation was successful by verifying projectPath exists
33+
// and no fatal errors occurred
34+
const hasProjectPath = Boolean(state.projectPath);
35+
const hasFatalErrors = Boolean(
36+
state.workflowFatalErrorMessages && state.workflowFatalErrorMessages.length > 0
37+
);
38+
39+
if (hasProjectPath && !hasFatalErrors) {
40+
this.logger.info(
41+
`Project generation successful at ${state.projectPath}, routing to build validation`
42+
);
43+
return this.successNodeName;
44+
}
45+
46+
// If projectPath is missing or there are fatal errors, route to failure
47+
const reason = hasFatalErrors
48+
? `Fatal errors occurred: ${state.workflowFatalErrorMessages?.join(', ')}`
49+
: 'Project path not set after generation';
50+
51+
this.logger.warn(`Project generation failed. Reason: ${reason}. Routing to failure.`);
52+
return this.failureNodeName;
53+
};
54+
}

0 commit comments

Comments
 (0)