diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index c0edca894b1..b8ff8c60782 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -45,34 +45,32 @@ inputs: type: string required: false BALLERINA_AUTH_ORG: - default: true type: string BALLERINA_AUTH_CLIENT_ID: - default: true type: string + BALLERINA_DEV_COPLIOT_ROOT_URL: + type: string + BALLERINA_DEV_COPLIOT_AUTH_ORG: + type: string + BALLERINA_DEV_COPLIOT_AUTH_CLIENT_ID: + type: string + BALLERINA_DEV_COPLIOT_AUTH_REDIRECT_URL: + type: string MI_AUTH_ORG: - default: true type: string MI_AUTH_CLIENT_ID: - default: true type: string PLATFORM_DEFAULT_GHAPP_CLIENT_ID: - default: true type: string PLATFORM_DEFAULT_DEVANT_ASGARDEO_CLIENT_ID: - default: true type: string PLATFORM_STAGE_GHAPP_CLIENT_ID: - default: true type: string PLATFORM_STAGE_DEVANT_ASGARDEO_CLIENT_ID: - default: true type: string PLATFORM_DEV_GHAPP_CLIENT_ID: - default: true type: string PLATFORM_DEV_DEVANT_ASGARDEO_CLIENT_ID: - default: true type: string runs: @@ -167,6 +165,10 @@ runs: isPreRelease: ${{ inputs.isPreRelease == 'true' }} BALLERINA_AUTH_ORG: ${{ inputs.BALLERINA_AUTH_ORG }} BALLERINA_AUTH_CLIENT_ID: ${{ inputs.BALLERINA_AUTH_CLIENT_ID }} + BALLERINA_DEV_COPLIOT_ROOT_URL: ${{ inputs.BALLERINA_DEV_COPLIOT_ROOT_URL }} + BALLERINA_DEV_COPLIOT_AUTH_ORG: ${{ inputs.BALLERINA_DEV_COPLIOT_AUTH_ORG }} + BALLERINA_DEV_COPLIOT_AUTH_CLIENT_ID: ${{ inputs.BALLERINA_DEV_COPLIOT_AUTH_CLIENT_ID }} + BALLERINA_DEV_COPLIOT_AUTH_REDIRECT_URL: ${{ inputs.BALLERINA_DEV_COPLIOT_AUTH_REDIRECT_URL }} MI_AUTH_ORG: ${{ inputs.MI_AUTH_ORG }} MI_AUTH_CLIENT_ID: ${{ inputs.MI_AUTH_CLIENT_ID }} PLATFORM_DEFAULT_GHAPP_CLIENT_ID: ${{ inputs.PLATFORM_DEFAULT_GHAPP_CLIENT_ID }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb1f7b7c52f..8522f3cb7c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -205,6 +205,10 @@ jobs: token: ${{ secrets.CHOREO_BOT_TOKEN }} BALLERINA_AUTH_ORG: ${{ secrets.BALLERINA_AUTH_ORG }} BALLERINA_AUTH_CLIENT_ID: ${{ secrets.BALLERINA_AUTH_CLIENT_ID }} + BALLERINA_DEV_COPLIOT_ROOT_URL: ${{ secrets.BALLERINA_DEV_COPLIOT_ROOT_URL }} + BALLERINA_DEV_COPLIOT_AUTH_ORG: ${{ secrets.BALLERINA_DEV_COPLIOT_AUTH_ORG }} + BALLERINA_DEV_COPLIOT_AUTH_CLIENT_ID: ${{ secrets.BALLERINA_DEV_COPLIOT_AUTH_CLIENT_ID }} + BALLERINA_DEV_COPLIOT_AUTH_REDIRECT_URL: ${{ secrets.BALLERINA_DEV_COPLIOT_AUTH_REDIRECT_URL }} MI_AUTH_ORG: ${{ secrets.MI_AUTH_ORG }} MI_AUTH_CLIENT_ID: ${{ secrets.MI_AUTH_CLIENT_ID }} PLATFORM_DEFAULT_GHAPP_CLIENT_ID: ${{ secrets.PLATFORM_DEFAULT_GHAPP_CLIENT_ID }} diff --git a/workspaces/ballerina/ballerina-extension/.env.example b/workspaces/ballerina/ballerina-extension/.env.example index a216162b012..f50f4148a2b 100644 --- a/workspaces/ballerina/ballerina-extension/.env.example +++ b/workspaces/ballerina/ballerina-extension/.env.example @@ -11,5 +11,3 @@ BALLERINA_DEV_COPLIOT_ROOT_URL= BALLERINA_DEV_COPLIOT_AUTH_ORG= BALLERINA_DEV_COPLIOT_AUTH_CLIENT_ID= BALLERINA_DEV_COPLIOT_AUTH_REDIRECT_URL= -BALLERINA_DEV_COPLIOT_CODE_API_KEY= -BALLERINA_DEV_COPLIOT_ASK_API_KEY= \ No newline at end of file diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts index 8f441d2b558..d0b054519f9 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/AgentExecutor.ts @@ -56,7 +56,7 @@ function determineAffectedPackages( console.log(`[determineAffectedPackages] Temp project path: ${tempProjectPath}`); // For non-workspace scenario (single package) - if (!ctx.workspacePath || projects.length === 1) { + if (!ctx.workspacePath) { console.log(`[determineAffectedPackages] Non-workspace scenario, using temp project path: ${tempProjectPath}`); affectedPackages.add(tempProjectPath); return Array.from(affectedPackages); diff --git a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/utils.ts b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/utils.ts index 85f801886c5..9b8c0b6ffcb 100644 --- a/workspaces/ballerina/ballerina-extension/src/features/ai/agent/utils.ts +++ b/workspaces/ballerina/ballerina-extension/src/features/ai/agent/utils.ts @@ -14,11 +14,12 @@ // specific language governing permissions and limitations // under the License. -import { SourceFile, FileChanges, CodeContext, ProjectSource, ExecutionContext } from "@wso2/ballerina-core"; +import { SourceFile, FileChanges, CodeContext, ProjectSource, ExecutionContext, PROJECT_KIND } from "@wso2/ballerina-core"; import { addToIntegration } from "../../../rpc-managers/ai-panel/utils"; import * as fs from "fs"; import * as path from "path"; import type { TextEdit } from "vscode-languageserver-protocol"; +import { StateMachine } from "../../../stateMachine"; /** * File extensions to include in codebase structure @@ -215,34 +216,22 @@ export function formatCodebaseStructure(projects: ProjectSource[]): string { text += "You do not need to acknowledge or list these files in your response. "; text += "This information is provided for your awareness only.\n\n"; - if (projects.length === 1) { - // Single project case: show project name and files with content - const project = projects[0]; - const files = collectFilesFromProject(project); + const context = StateMachine.context(); + const isWorkspace = context.projectInfo?.projectKind === PROJECT_KIND.WORKSPACE_PROJECT; + for (const project of projects) { + const files = collectFilesFromProject(project, isWorkspace); + const activeStatus = project.isActive ? ' active="true"' : ""; - text += `\n`; + text += `\n`; text += "\n"; text += files.map(formatFileWithContent).join("\n"); text += "\n\n"; text += "\n"; - } else { - // Multi-workspace project case: show all projects with active status - // Include packagePath prefix in file paths for clarity - for (const project of projects) { - const files = collectFilesFromProject(project, true); - const activeStatus = project.isActive ? ' active="true"' : ""; - - text += `\n`; - text += "\n"; - text += files.map(formatFileWithContent).join("\n"); - text += "\n\n"; - text += "\n"; - } } text += ""; - if (projects.length > 0) { + if (isWorkspace) { text += `Note: This is a Ballerina workspace with multiple packages. File paths are prefixed with their package paths (e.g., "mainpackage/main.bal"). Files from external packages (not the active package) are marked with the externalPackageName attribute (e.g., ). You can import these packages by just using the package name (e.g., import otherpackage;). diff --git a/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts b/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts index b3d0001a10a..7a271dee1c2 100644 --- a/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts +++ b/workspaces/ballerina/ballerina-extension/src/rpc-managers/visualizer/rpc-manager.ts @@ -295,14 +295,11 @@ export class VisualizerRpcManager implements VisualizerAPI { reviewAccepted(): void { // When user accepts changes in review mode, navigate back to normal view console.log("Review accepted - changes will be kept"); - // Navigate to package overview or appropriate view - const isWithinBallerinaWorkspace = !!StateMachine.context().workspacePath; + // Navigate to package overview openView( EVENT_TYPE.OPEN_VIEW, { - view: isWithinBallerinaWorkspace - ? MACHINE_VIEW.WorkspaceOverview - : MACHINE_VIEW.PackageOverview + view: MACHINE_VIEW.PackageOverview } ); } diff --git a/workspaces/ballerina/ballerina-visualizer/src/views/ReviewMode/index.tsx b/workspaces/ballerina/ballerina-visualizer/src/views/ReviewMode/index.tsx index 1b1b99846f7..b791928f2ca 100644 --- a/workspaces/ballerina/ballerina-visualizer/src/views/ReviewMode/index.tsx +++ b/workspaces/ballerina/ballerina-visualizer/src/views/ReviewMode/index.tsx @@ -181,7 +181,7 @@ function convertToReviewView(diff: SemanticDiff, projectPath: string, packageNam const fileName = diff.uri.split("/").pop() || diff.uri; const changeTypeStr = getChangeTypeString(diff.changeType); const nodeKindStr = getNodeKindString(diff.nodeKind); - + // Include package name in label if provided (for multi-package scenarios) const changeLabel = packageName ? `${changeTypeStr}: ${nodeKindStr} in ${packageName}/${fileName}` @@ -209,7 +209,7 @@ async function fetchSemanticDiff(rpcClient: any, projectPath: string): Promise { console.log(`[ReviewMode] Fetching semantic diffs for ${packagePaths.length} packages:`, packagePaths); @@ -241,12 +241,12 @@ async function fetchSemanticDiffForMultiplePackages( function getPackageName(path: string): string { const parts = path.split("/"); const lastPart = parts[parts.length - 1]; - + // If the last part is a .bal file, the package name is the directory before it - if (lastPart && lastPart.endsWith('.bal')) { + if (lastPart && lastPart.endsWith(".bal")) { return parts[parts.length - 2] || path; } - + // Otherwise, the last part is the package name return lastPart || path; } @@ -276,7 +276,7 @@ export function ReviewMode(): JSX.Element { const loadSemanticDiff = useCallback(async () => { try { setIsLoading(true); - + // First fetch the active temp directory path const tempDirPath = await rpcClient.getAiPanelRpcClient().getActiveTempDir(); if (!tempDirPath) { @@ -308,7 +308,10 @@ export function ReviewMode(): JSX.Element { // Use affected packages if available, otherwise fallback to temp directory const packagesToReview = isWorkspaceProject ? fetchedPackages : [tempDirPath]; - console.log(`[ReviewMode] Reviewing ${packagesToReview.length} package(s) in ${isWorkspaceProject ? 'workspace' : 'single'} project:`, packagesToReview); + console.log( + `[ReviewMode] Reviewing ${packagesToReview.length} package(s) in ${isWorkspaceProject ? "workspace" : "single"} project:`, + packagesToReview, + ); // Fetch semantic diffs for all affected packages // For workspace projects, always fetch for each package even if only one is affected @@ -326,13 +329,10 @@ export function ReviewMode(): JSX.Element { if (semanticDiffResponse.loadDesignDiagrams && semanticDiffResponse.semanticDiffs.length > 0) { // For workspace projects, create a component diagram for each affected package // For single package projects, create one component diagram - packagesToReview.forEach((packagePath) => { const packageName = getPackageName(packagePath); - const label = isWorkspaceProject - ? `Design Diagram - ${packageName}` - : "Design Diagram"; - + const label = isWorkspaceProject ? `Design Diagram - ${packageName}` : "Design Diagram"; + allViews.push({ type: DiagramType.COMPONENT, filePath: packagePath, @@ -362,9 +362,9 @@ export function ReviewMode(): JSX.Element { // Find the package that contains this file for (const pkgPath of packagesToReview) { // Normalize paths and check if diff.uri starts with package path - const normalizedUri = diff.uri.replace(/\\/g, '/'); - const normalizedPkgPath = pkgPath.replace(/\\/g, '/'); - if (normalizedUri.startsWith(normalizedPkgPath + '/') || normalizedUri === normalizedPkgPath) { + const normalizedUri = diff.uri.replace(/\\/g, "/"); + const normalizedPkgPath = pkgPath.replace(/\\/g, "/"); + if (normalizedUri.startsWith(normalizedPkgPath + "/") || normalizedUri === normalizedPkgPath) { belongsToPackage = pkgPath; packageName = getPackageName(pkgPath); break; @@ -541,7 +541,14 @@ export function ReviewMode(): JSX.Element { Review Mode} + actions={ + <> + Review Mode + + + + + } hideBack={true} hideUndoRedo={true} /> @@ -598,7 +605,7 @@ export function ReviewMode(): JSX.Element { <> {isWorkspace && currentPackageName && ( - + {currentPackageName} )}