diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 24d0c2d2c..0c05e6334 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -13,7 +13,7 @@ This is the **GitHub Copilot for Eclipse** plugin - an Eclipse IDE extension tha - **Multi-Platform Support**: Windows, macOS (x64/aarch64), and Linux (x64/aarch64) ### Tech Stack -- **Java**: Primary language (Java 17+, with Eclipse 4.31+ requiring Java 21+) +- **Java**: Primary language (Java 21+, with Eclipse 4.38+ requiring Java 21+) - **Eclipse RCP/OSGi**: Plugin architecture using Eclipse platform APIs - **Maven/Tycho**: Build system for Eclipse plugin development - **LSP4E**: Language Server Protocol integration for Eclipse @@ -46,7 +46,7 @@ You MUST verify compilation and code quality before declaring work complete! - Root POM coordinates multi-module build with Tycho - Each bundle/feature/test has its own POM inheriting from root - Checkstyle validation runs during `verify` phase -- Target platform defined in `base.target`, `target-terminal.target`, `target-tm-terminal.target` +- Target platform defined in `target-platforms/2025-12.target` ### Code Change Review Trigger @@ -117,12 +117,6 @@ The project follows Eclipse plugin conventions with multiple OSGi bundles: - **Service**: `IRunInTerminalTool` implementation - **Dependencies**: `org.eclipse.terminal.*` packages -**`com.microsoft.copilot.eclipse.ui.terminal.tm`** - TM Terminal integration (legacy) -- **Package**: `com.microsoft.copilot.eclipse.ui.terminal.tm` -- **Purpose**: Implementation for TM Terminal (Eclipse 4.36 and lower) -- **Service**: `IRunInTerminalTool` implementation -- **Dependencies**: `org.eclipse.tm.terminal.*` packages - #### Platform-Specific Agent Bundles These bundles contain the Node.js-based Copilot language server agent for each platform: @@ -569,7 +563,7 @@ distinguish repeated controls with stable context or an ordinal **When** writing tests → use JUnit 5 for core logic; integration tests for Eclipse integration -**When** adding dependencies → only add necessary bundles; check `base.target` for Eclipse 2024-03 version constraints +**When** adding dependencies → only add necessary bundles; check `target-platforms/2025-12.target` for Eclipse 2025-12 version constraints **When** targeting Eclipse versions → support multiple versions when possible diff --git a/.github/skills/ui-action/REFERENCE.md b/.github/skills/ui-action/REFERENCE.md index 65d4fb3ef..22eda5bb4 100644 --- a/.github/skills/ui-action/REFERENCE.md +++ b/.github/skills/ui-action/REFERENCE.md @@ -8,7 +8,7 @@ with `useUIHarness=true` and `useUIThread=false`. It loads the JSON array from artifacts, and fails the Maven build if any failed step has `failFast` enabled. Before the bot starts, the runner pre-populates configuration-scope preferences -so Quick Start, What's New, Welcome, and "Terminal Support Unavailable" dialogs +so Quick Start, What's New, and Welcome dialogs do not block normal probes. `screenshot` and failure screenshots capture the active workbench shell with diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3823ab471..7d45575de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,10 +32,10 @@ jobs: working-directory: com.microsoft.copilot.eclipse.core/copilot-agent run: npm i -f - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: maven diff --git a/.gitignore b/.gitignore index 650f8dc02..a792baab1 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,6 @@ replay_pid* # whatisnew html file in runtime **/whatisnew.html -# Terminal bundles -**/terminal-bundles/*.jar - # Fragment bundle copilot-agent directories com.microsoft.copilot.eclipse.core.agent.linux.x64/copilot-agent/ com.microsoft.copilot.eclipse.core.agent.linux.aarch64/copilot-agent/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e78e21d46..4ee7f13dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,10 +16,10 @@ When you submit a pull request, a CLA bot will automatically determine whether y ### Prerequisites -- **Java 17** or later (CI uses Temurin 17; use a newer JDK if required by your Eclipse IDE) +- **Java 21** or later (CI uses Temurin 21; use a newer JDK if required by your Eclipse IDE) - **Maven 3.8+** (or use the provided Maven wrapper `./mvnw`) - **Node.js 22.13** or later, with npm -- **Eclipse IDE for Eclipse Committers 2024-03** or later (for development) +- **Eclipse IDE for Eclipse Committers 2025-12** or later (for development) - Recommended: **Eclipse Checkstyle plugin** for code style compliance (e.g. install from update site: https://checkstyle.org/eclipse-cs-update-site/) @@ -60,9 +60,8 @@ The installable P2 repository is generated in `com.microsoft.copilot.eclipse.rep activate the check box *Search for nested projects*, and finish the wizard. * Do also import the agent bundle for your OS (e.g., `com.microsoft.copilot.eclipse.core.agent.win32`) after building the project with npm and maven or import all OS-specific agent bundles. -2. Activate one of the target platforms, i.e. open one of the target definition files and select `Set As Active Target Platform`. - * target-terminal.target (Eclipse 4.37+) - * target-tm-terminal.target (Eclipse 4.36 and earlier) +2. Activate the target platform, i.e. open the target definition file `target-platforms/2025-12.target` + (Eclipse 2025-12 / 4.38, providing the modern `org.eclipse.terminal.*` bundles) and select `Set As Active Target Platform`. 3. For using the Checkstyle configuration (assuming you have installed the Eclipse Checkstyle plugin, see prerequisites), add a new named Checkstyle configuration. * Select *Window > Preferences > Checkstyle* and press the *New...* button. @@ -112,8 +111,7 @@ The project is a multi-module Maven/Tycho build consisting of OSGi bundles: | `com.microsoft.copilot.eclipse.ui` | User interface: chat view, completion UI, agent tools | | `com.microsoft.copilot.eclipse.ui.jobs` | Copilot Jobs view integration | | `com.microsoft.copilot.eclipse.terminal.api` | Terminal tool API definitions | -| `com.microsoft.copilot.eclipse.ui.terminal` | Terminal integration (Eclipse 4.37+) | -| `com.microsoft.copilot.eclipse.ui.terminal.tm` | TM Terminal integration (Eclipse 4.36 and earlier) | +| `com.microsoft.copilot.eclipse.ui.terminal` | Terminal integration (runs on Eclipse >= 2025-09 / 4.37) | | `com.microsoft.copilot.eclipse.branding` | Product branding and about dialog | | `com.microsoft.copilot.eclipse.core.agent.*` | Platform-specific Copilot language server agent bundles | | `com.microsoft.copilot.eclipse.feature` | Eclipse feature definition | diff --git a/base.target b/base.target deleted file mode 100644 index a6fc6705a..000000000 --- a/base.target +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.mockito - mockito-core - 5.14.2 - jar - - - org.mockito - mockito-junit-jupiter - 5.14.2 - jar - - - org.objenesis - objenesis - 3.4 - jar - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/com.microsoft.copilot.eclipse.core.agent.linux.aarch64/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core.agent.linux.aarch64/META-INF/MANIFEST.MF index eb31b095a..b08c1bcf5 100644 --- a/com.microsoft.copilot.eclipse.core.agent.linux.aarch64/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core.agent.linux.aarch64/META-INF/MANIFEST.MF @@ -6,5 +6,5 @@ Automatic-Module-Name: com.microsoft.copilot.eclipse.core.agent.linux.aarch64 Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot Fragment-Host: com.microsoft.copilot.eclipse.core -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Eclipse-PlatformFilter: (&(osgi.os=linux)(osgi.arch=aarch64)) diff --git a/com.microsoft.copilot.eclipse.core.agent.linux.x64/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core.agent.linux.x64/META-INF/MANIFEST.MF index d422d0113..855176ae8 100644 --- a/com.microsoft.copilot.eclipse.core.agent.linux.x64/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core.agent.linux.x64/META-INF/MANIFEST.MF @@ -6,5 +6,5 @@ Automatic-Module-Name: com.microsoft.copilot.eclipse.core.agent.linux.x64 Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot Fragment-Host: com.microsoft.copilot.eclipse.core -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Eclipse-PlatformFilter: (&(osgi.os=linux)(osgi.arch=x86_64)) diff --git a/com.microsoft.copilot.eclipse.core.agent.macosx.aarch64/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core.agent.macosx.aarch64/META-INF/MANIFEST.MF index 4e91f8354..eaae707a2 100644 --- a/com.microsoft.copilot.eclipse.core.agent.macosx.aarch64/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core.agent.macosx.aarch64/META-INF/MANIFEST.MF @@ -6,5 +6,5 @@ Automatic-Module-Name: com.microsoft.copilot.eclipse.core.agent.macosx.aarch64 Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot Fragment-Host: com.microsoft.copilot.eclipse.core -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Eclipse-PlatformFilter: (&(osgi.os=macosx) (osgi.arch=aarch64)) diff --git a/com.microsoft.copilot.eclipse.core.agent.macosx.x64/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core.agent.macosx.x64/META-INF/MANIFEST.MF index f00dbc951..387ad4ddb 100644 --- a/com.microsoft.copilot.eclipse.core.agent.macosx.x64/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core.agent.macosx.x64/META-INF/MANIFEST.MF @@ -6,5 +6,5 @@ Automatic-Module-Name: com.microsoft.copilot.eclipse.core.agent.macosx.x64 Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot Fragment-Host: com.microsoft.copilot.eclipse.core -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Eclipse-PlatformFilter: (&(osgi.os=macosx)(osgi.arch=x86_64)) diff --git a/com.microsoft.copilot.eclipse.core.agent.win32/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core.agent.win32/META-INF/MANIFEST.MF index e8f912c1d..11d3e10d1 100644 --- a/com.microsoft.copilot.eclipse.core.agent.win32/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core.agent.win32/META-INF/MANIFEST.MF @@ -6,5 +6,5 @@ Automatic-Module-Name: com.microsoft.copilot.eclipse.core.agent.win32 Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot Fragment-Host: com.microsoft.copilot.eclipse.core -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Eclipse-PlatformFilter: (osgi.os=win32) diff --git a/com.microsoft.copilot.eclipse.core.test/.classpath b/com.microsoft.copilot.eclipse.core.test/.classpath index 38f401ad4..766df48f2 100644 --- a/com.microsoft.copilot.eclipse.core.test/.classpath +++ b/com.microsoft.copilot.eclipse.core.test/.classpath @@ -1,11 +1,15 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.jdt.core.prefs index 21eccc094..a98206bc4 100644 --- a/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.core.test/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 diff --git a/com.microsoft.copilot.eclipse.core.test/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core.test/META-INF/MANIFEST.MF index ebf877391..e4eedf0c0 100644 --- a/com.microsoft.copilot.eclipse.core.test/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core.test/META-INF/MANIFEST.MF @@ -4,7 +4,7 @@ Bundle-Name: com.microsoft.copilot.eclipse.core.test Bundle-SymbolicName: com.microsoft.copilot.eclipse.core.test;singleton:=true Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Fragment-Host: com.microsoft.copilot.eclipse.core Automatic-Module-Name: com.microsoft.copilot.eclipse.core.test Import-Package: org.objenesis;version="[3.4.0,4.0.0)", diff --git a/com.microsoft.copilot.eclipse.core.test/build.properties b/com.microsoft.copilot.eclipse.core.test/build.properties index 100b378a5..3cb14ae9c 100644 --- a/com.microsoft.copilot.eclipse.core.test/build.properties +++ b/com.microsoft.copilot.eclipse.core.test/build.properties @@ -1,5 +1,5 @@ -source.. = src -output.. = target/classes +source.. = src/ +output.. = target/classes/ bin.includes = META-INF/,\ . diff --git a/com.microsoft.copilot.eclipse.core/.classpath b/com.microsoft.copilot.eclipse.core/.classpath index 8d8612144..b1415d56b 100644 --- a/com.microsoft.copilot.eclipse.core/.classpath +++ b/com.microsoft.copilot.eclipse.core/.classpath @@ -1,7 +1,11 @@ - - - - - - - + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.jdt.core.prefs index 21eccc094..2fc4a03ea 100644 --- a/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.core/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,17 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 diff --git a/com.microsoft.copilot.eclipse.core/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.core/META-INF/MANIFEST.MF index e96a614f6..b78d04d83 100644 --- a/com.microsoft.copilot.eclipse.core/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.core/META-INF/MANIFEST.MF @@ -23,10 +23,10 @@ Export-Package: com.microsoft.copilot.eclipse.core, com.microsoft.copilot.eclipse.core.lsp.protocol.quota, com.microsoft.copilot.eclipse.core.lsp.protocol.tools, com.microsoft.copilot.eclipse.core.nes;x-friends:="com.microsoft.copilot.eclipse.ui", - com.microsoft.copilot.eclipse.core.persistence;x-friends:="com.microsoft.copilot.eclipse.ui,com.microsoft.copilot.eclipse.core.test,com.microsoft.copilot.eclipse.core.utils", + com.microsoft.copilot.eclipse.core.persistence;x-friends:="com.microsoft.copilot.eclipse.ui,com.microsoft.copilot.eclipse.core.test,com.microsoft.copilot.eclipse.core.utils", com.microsoft.copilot.eclipse.core.utils Bundle-Activator: com.microsoft.copilot.eclipse.core.CopilotCore -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Automatic-Module-Name: com.microsoft.copilot.eclipse.core Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.ui, diff --git a/com.microsoft.copilot.eclipse.core/build.properties b/com.microsoft.copilot.eclipse.core/build.properties index d6219466d..326a0702b 100644 --- a/com.microsoft.copilot.eclipse.core/build.properties +++ b/com.microsoft.copilot.eclipse.core/build.properties @@ -1,5 +1,5 @@ -source.. = src -output.. = target/classes +source.. = src/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java index 73817770d..954a67ad2 100644 --- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java +++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java @@ -50,7 +50,6 @@ private Constants() { public static final String AUTO_SHOW_WHAT_IS_NEW = "autoShowWhatsNew"; public static final String AUTO_BREAKPOINT_RESPONSE = "autoBreakpointResponse"; public static final String GITHUB_JOBS_VIEW_ID = "com.microsoft.copilot.eclipse.ui.jobs.JobsView"; - public static final String SUPPRESS_TERMINAL_DEPENDENCY_DIALOG = "suppressTerminalDependencyDialog"; // Auto-Approve settings public static final String AUTO_APPROVE_TERMINAL_RULES = "autoApproveTerminalRules"; diff --git a/com.microsoft.copilot.eclipse.feature/feature.xml b/com.microsoft.copilot.eclipse.feature/feature.xml index 6cdfb8113..980f3c9b0 100644 --- a/com.microsoft.copilot.eclipse.feature/feature.xml +++ b/com.microsoft.copilot.eclipse.feature/feature.xml @@ -56,6 +56,10 @@ For the purpose of improving GitHub Copilot, Microsoft and GitHub may share with id="com.microsoft.copilot.eclipse.terminal.api" version="0.0.0"/> + + diff --git a/com.microsoft.copilot.eclipse.repository/category.xml b/com.microsoft.copilot.eclipse.repository/category.xml index 78f864fa1..3b147199d 100644 --- a/com.microsoft.copilot.eclipse.repository/category.xml +++ b/com.microsoft.copilot.eclipse.repository/category.xml @@ -3,5 +3,15 @@ + + + + + + + + + - \ No newline at end of file + + diff --git a/com.microsoft.copilot.eclipse.swtbot.test/.classpath b/com.microsoft.copilot.eclipse.swtbot.test/.classpath index 38f401ad4..766df48f2 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/.classpath +++ b/com.microsoft.copilot.eclipse.swtbot.test/.classpath @@ -1,11 +1,15 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.jdt.core.prefs index 62ef3488c..23fa13b17 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.swtbot.test/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 diff --git a/com.microsoft.copilot.eclipse.swtbot.test/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.swtbot.test/META-INF/MANIFEST.MF index 468b60478..3a2731834 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.swtbot.test/META-INF/MANIFEST.MF @@ -4,7 +4,7 @@ Bundle-Name: com.microsoft.copilot.eclipse.swtbot.test Bundle-SymbolicName: com.microsoft.copilot.eclipse.swtbot.test;singleton:=true Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Automatic-Module-Name: com.microsoft.copilot.eclipse.swtbot.test Require-Bundle: org.eclipse.swtbot.swt.finder;bundle-version="4.1.0", org.eclipse.swtbot.eclipse.finder;bundle-version="4.1.0", diff --git a/com.microsoft.copilot.eclipse.swtbot.test/build.properties b/com.microsoft.copilot.eclipse.swtbot.test/build.properties index 8e6b406ec..73ec1c618 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/build.properties +++ b/com.microsoft.copilot.eclipse.swtbot.test/build.properties @@ -1,5 +1,5 @@ -source.. = src -output.. = target/classes +source.. = src/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.microsoft.copilot.eclipse.swtbot.test/src/com/microsoft/copilot/eclipse/swtbot/test/probe/ProbeRunner.java b/com.microsoft.copilot.eclipse.swtbot.test/src/com/microsoft/copilot/eclipse/swtbot/test/probe/ProbeRunner.java index f64e037c0..1a2a2c746 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/src/com/microsoft/copilot/eclipse/swtbot/test/probe/ProbeRunner.java +++ b/com.microsoft.copilot.eclipse.swtbot.test/src/com/microsoft/copilot/eclipse/swtbot/test/probe/ProbeRunner.java @@ -64,9 +64,8 @@ public static void assumeScript() { /** * Pre-populates the Copilot UI plugin's configuration-scope preferences so the - * workbench-startup logic in {@code CopilotUi#showHintIfNecessary} and - * {@code MissingTerminalDependenciesDialog#showIfNotSuppressed} skip their - * "first run" dialogs (Quick Start, What's New, Terminal Support Unavailable). + * workbench-startup logic in {@code CopilotUi#showHintIfNecessary} skips its + * "first run" dialogs (Quick Start, What's New). * Runs before the workbench bot exists; best-effort — any failure is logged * and the probe continues. */ @@ -76,7 +75,6 @@ private static void suppressNuisancePreferences() { prefs.putInt(Constants.COPILOT_QUICK_START_VERSION, Constants.CURRENT_COPILOT_QUICK_START_VERSION); prefs.putBoolean(Constants.AUTO_SHOW_WHAT_IS_NEW, false); prefs.put(Constants.LAST_USED_COPILOT_PLUGIN_VERSION, currentUiBundleMajorMinor()); - prefs.putBoolean(Constants.SUPPRESS_TERMINAL_DEPENDENCY_DIALOG, true); prefs.flush(); } catch (BackingStoreException | RuntimeException e) { System.err.println("[ProbeRunner] Failed to preset nuisance-dialog preferences: " + e); diff --git a/com.microsoft.copilot.eclipse.swtbot.test/test-plans/byok/byok.md b/com.microsoft.copilot.eclipse.swtbot.test/test-plans/byok/byok.md index cd05b935a..0fe960804 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/test-plans/byok/byok.md +++ b/com.microsoft.copilot.eclipse.swtbot.test/test-plans/byok/byok.md @@ -55,7 +55,7 @@ Not exercised in this plan (separate scenarios): - For Ollama-specific TCs: Ollama 0.6.4 or newer is running and has at least one installed model. - No previously opened Preferences dialog. The probe runner pre-suppresses - Quick Start, What's New, Welcome, and "Terminal Support Unavailable" + Quick Start, What's New, and Welcome pop-ups — keep that contract when authoring follow-up plans. - Each TC starts from a freshly launched workbench (the probe sandbox satisfies this automatically). When running manually, close the diff --git a/com.microsoft.copilot.eclipse.swtbot.test/test-plans/chat-send-receive/chat-send-receive.md b/com.microsoft.copilot.eclipse.swtbot.test/test-plans/chat-send-receive/chat-send-receive.md index 3aee9d818..0622d09ff 100644 --- a/com.microsoft.copilot.eclipse.swtbot.test/test-plans/chat-send-receive/chat-send-receive.md +++ b/com.microsoft.copilot.eclipse.swtbot.test/test-plans/chat-send-receive/chat-send-receive.md @@ -40,8 +40,8 @@ Not exercised in TC-001 (separate scenarios): - Network access to `api.githubcopilot.com` (and the GitHub auth host if a token refresh is needed). - No modal dialogs queued on workbench startup. The probe runner - pre-populates preferences to suppress Quick Start, What's New, Welcome, and - "Terminal Support Unavailable" pop-ups; authoring additional tests on top + pre-populates preferences to suppress Quick Start, What's New, and + Welcome pop-ups; authoring additional tests on top of this scenario should keep that contract. --- diff --git a/com.microsoft.copilot.eclipse.terminal.api/.classpath b/com.microsoft.copilot.eclipse.terminal.api/.classpath index 8d8612144..b1415d56b 100644 --- a/com.microsoft.copilot.eclipse.terminal.api/.classpath +++ b/com.microsoft.copilot.eclipse.terminal.api/.classpath @@ -1,7 +1,11 @@ - - - - - - - + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.jdt.core.prefs index 62ef3488c..23fa13b17 100644 --- a/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.terminal.api/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 diff --git a/com.microsoft.copilot.eclipse.terminal.api/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.terminal.api/META-INF/MANIFEST.MF index fbcc5c79a..9a0d746cf 100644 --- a/com.microsoft.copilot.eclipse.terminal.api/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.terminal.api/META-INF/MANIFEST.MF @@ -7,7 +7,7 @@ Bundle-Vendor: GitHub Copilot Export-Package: com.microsoft.copilot.eclipse.terminal.api Automatic-Module-Name: com.microsoft.copilot.eclipse.terminal.api Bundle-ActivationPolicy: lazy -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Import-Package: org.osgi.framework;version="[1.10.0,2.0.0)" Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.30.0,4.0.0)", com.microsoft.copilot.eclipse.core;bundle-version="0.21.0", diff --git a/com.microsoft.copilot.eclipse.terminal.api/build.properties b/com.microsoft.copilot.eclipse.terminal.api/build.properties index f38581b94..eb7c4c161 100644 --- a/com.microsoft.copilot.eclipse.terminal.api/build.properties +++ b/com.microsoft.copilot.eclipse.terminal.api/build.properties @@ -1,5 +1,5 @@ source.. = src/ -output.. = bin/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ scripts/ diff --git a/com.microsoft.copilot.eclipse.terminal.api/src/com/microsoft/copilot/eclipse/terminal/api/TerminalServiceManager.java b/com.microsoft.copilot.eclipse.terminal.api/src/com/microsoft/copilot/eclipse/terminal/api/TerminalServiceManager.java index 8d1c39fc4..2532a89fb 100644 --- a/com.microsoft.copilot.eclipse.terminal.api/src/com/microsoft/copilot/eclipse/terminal/api/TerminalServiceManager.java +++ b/com.microsoft.copilot.eclipse.terminal.api/src/com/microsoft/copilot/eclipse/terminal/api/TerminalServiceManager.java @@ -1,500 +1,151 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package com.microsoft.copilot.eclipse.terminal.api; - -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.jar.JarInputStream; -import java.util.jar.Manifest; - -import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.osgi.util.ManifestElement; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; -import org.osgi.framework.FrameworkEvent; -import org.osgi.framework.FrameworkListener; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.Version; -import org.osgi.framework.wiring.FrameworkWiring; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; - -import com.microsoft.copilot.eclipse.core.CopilotCore; -import com.microsoft.copilot.eclipse.core.utils.PlatformUtils; - -/** - * Central manager for terminal services. Handles service discovery, bundle installation. - */ -public class TerminalServiceManager { - - private static final String TERMINAL_BUNDLES_PATH = "terminal-bundles/"; - private static final String MODERN_TERMINAL_BUNDLE_JAR = "com.microsoft.copilot.eclipse.ui.terminal.jar"; - private static final String TM_TERMINAL_BUNDLE_JAR = "com.microsoft.copilot.eclipse.ui.terminal.tm.jar"; - private static final String MODERN_TERMINAL_BUNDLE_ID = "com.microsoft.copilot.eclipse.ui.terminal"; - private static final String TM_TERMINAL_BUNDLE_ID = "com.microsoft.copilot.eclipse.ui.terminal.tm"; - private static final String MODERN_TERMINAL_TYPE = "Terminal Feature"; - private static final String TM_TERMINAL_TYPE = "TM Terminal"; - private static final Version TARGET_PLATFORM_VERSION = new Version(4, 37, 0); - - /** - * Static inner class for lazy initialization of singleton instance. - */ - private static class InstanceHolder { - private static final TerminalServiceManager INSTANCE = createInstance(); - - private static TerminalServiceManager createInstance() { - Bundle apiBundle = FrameworkUtil.getBundle(TerminalServiceManager.class); - if (apiBundle != null) { - BundleContext context = apiBundle.getBundleContext(); - if (context != null) { - TerminalServiceManager instance = new TerminalServiceManager(context); - instance.start(); - return instance; - } - } - return null; - } - } - - private final BundleContext bundleContext; - private ServiceTracker serviceTracker; - private final AtomicBoolean installationAttempted = new AtomicBoolean(false); - private final CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>(); - private volatile IRunInTerminalTool currentService = null; - private volatile List cachedMissingDependencies = null; - private final boolean isModernTerminal; - - /** - * Interface for listening to terminal service availability changes. - */ - public interface TerminalServiceListener { - /** - * Called when a terminal service becomes available. - * - * @param service the available terminal service - */ - void onServiceAvailable(IRunInTerminalTool service); - - /** - * Called when terminal dependencies are missing and need user action. - * - * @param terminalType the type of terminal (e.g., "Terminal Feature" or "TM Terminal") - * @param missingDependencies list of missing bundle symbolic names - */ - void onMissingDependencies(String terminalType, List missingDependencies); - } - - private TerminalServiceManager(BundleContext bundleContext) { - this.bundleContext = bundleContext; - this.isModernTerminal = detectModernTerminal(); - } - - /** - * Get the singleton instance of TerminalServiceManager. - */ - public static TerminalServiceManager getInstance() { - return InstanceHolder.INSTANCE; - } - - /** - * Add a listener for terminal service events. - */ - public void addListener(TerminalServiceListener listener) { - if (listener != null) { - listeners.add(listener); - - // If service is already available, notify immediately - if (currentService != null) { - listener.onServiceAvailable(currentService); - } - - // Notify with cached missing dependencies if available - if (cachedMissingDependencies != null && !cachedMissingDependencies.isEmpty()) { - listener.onMissingDependencies(isModernTerminal ? MODERN_TERMINAL_TYPE : TM_TERMINAL_TYPE, - cachedMissingDependencies); - } - } - } - - /** - * Remove a listener for terminal service events. - */ - public void removeListener(TerminalServiceListener listener) { - listeners.remove(listener); - } - - /** - * Get the current terminal service if available. - */ - public IRunInTerminalTool getCurrentService() { - return currentService; - } - - /** - * Start tracking terminal services. - */ - private void start() { - ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer<>() { - @Override - public IRunInTerminalTool addingService(ServiceReference reference) { - IRunInTerminalTool service = bundleContext.getService(reference); - if (service != null) { - currentService = service; - notifyServiceAvailable(service); - } - return service; - } - - @Override - public void modifiedService(ServiceReference reference, IRunInTerminalTool service) { - if (service != null) { - currentService = service; - notifyServiceAvailable(service); - } - } - - @Override - public void removedService(ServiceReference reference, IRunInTerminalTool service) { - } - }; - - serviceTracker = new ServiceTracker<>(bundleContext, IRunInTerminalTool.class, customizer); - serviceTracker.open(); - - IRunInTerminalTool[] services = serviceTracker.getServices(new IRunInTerminalTool[0]); - if (services != null && services.length > 0) { - currentService = services[0]; - } - // Check if bundle needs to be installed or updated - attemptTerminalBundleInstallation(); - } - - /** - * Stop the service manager. - */ - public void stop() { - if (serviceTracker != null) { - serviceTracker.close(); - serviceTracker = null; - } - currentService = null; - listeners.clear(); - } - - private void notifyServiceAvailable(IRunInTerminalTool service) { - for (TerminalServiceListener listener : listeners) { - listener.onServiceAvailable(service); - } - } - - private void notifyMissingDependencies(String terminalType, List missingDependencies) { - for (TerminalServiceListener listener : listeners) { - listener.onMissingDependencies(terminalType, missingDependencies); - } - } - - /** - * Attempt to install or update terminal bundle. Skips if bundle is already installed with sufficient version. - */ - private void attemptTerminalBundleInstallation() { - if (!installationAttempted.compareAndSet(false, true)) { - return; - } - - Job installationJob = new Job("Installing Terminal Bundle") { - @Override - protected IStatus run(IProgressMonitor monitor) { - monitor.beginTask("Installing terminal bundle", 100); - try { - // Step 1: Check if installation/update is needed - monitor.subTask("Checking existing installation"); - String symbolicName = isModernTerminal ? MODERN_TERMINAL_BUNDLE_ID : TM_TERMINAL_BUNDLE_ID; - Bundle existingBundle = getInstalledBundle(symbolicName); - Version requiredVersion = getEmbeddedBundleVersion(); - - if (existingBundle != null) { - Version installedVersion = existingBundle.getVersion(); - boolean needsUpdate = requiredVersion != null && installedVersion.compareTo(requiredVersion) < 0; - - if (!needsUpdate) { - // Already up-to-date, just ensure it's started - ensureStarted(existingBundle); - monitor.done(); - return Status.OK_STATUS; - } - } - monitor.worked(20); - - // Step 2: Check if required dependencies are available - monitor.subTask("Checking dependencies"); - List missingDependencies = getMissingDependencies(); - monitor.worked(20); - - if (missingDependencies.isEmpty()) { - // Dependencies available, install or update from embedded JAR - return installFromEmbeddedJar(existingBundle, monitor); - } else { - // Dependencies missing, cache and notify listeners - cachedMissingDependencies = missingDependencies; - notifyMissingDependencies(isModernTerminal ? MODERN_TERMINAL_TYPE : TM_TERMINAL_TYPE, missingDependencies); - return new Status(IStatus.WARNING, bundleContext.getBundle().getSymbolicName(), - "Terminal dependencies not available. User needs to install them manually."); - } - - } catch (BundleException e) { - monitor.done(); - CopilotCore.LOGGER.error("Failed to install terminal bundle", e); - return new Status(IStatus.ERROR, bundleContext.getBundle().getSymbolicName(), - "Failed to install terminal bundle", e); - } - } - }; - installationJob.setSystem(true); - installationJob.schedule(); - } - - /** - * Install terminal bundle from embedded JAR file (bundled with the plugin). - * - * @param existingBundle the existing bundle to update, or null if installing new - * @param monitor progress monitor - */ - private IStatus installFromEmbeddedJar(Bundle existingBundle, IProgressMonitor monitor) { - try { - monitor.subTask("Locating embedded bundle resource"); - String jarName = isModernTerminal ? MODERN_TERMINAL_BUNDLE_JAR : TM_TERMINAL_BUNDLE_JAR; - URL bundleUrl = getEmbeddedBundleUrl(jarName); - if (bundleUrl == null) { - return new Status(IStatus.ERROR, bundleContext.getBundle().getSymbolicName(), - "Failed to locate terminal bundle JAR: " + jarName); - } - monitor.worked(20); - - monitor.subTask(existingBundle != null ? "Updating bundle" : "Installing bundle"); - return installOrUpdateBundle(bundleUrl, existingBundle, monitor); - } catch (InterruptedException | BundleException e) { - CopilotCore.LOGGER.error("Failed to install from embedded JAR", e); - return new Status(IStatus.ERROR, bundleContext.getBundle().getSymbolicName(), - "Failed to install from embedded JAR", e); - } - } - - /** - * Get the version of the terminal bundle. All Copilot bundles share the same version. - * - * @return the terminal bundle version, or null if not available - */ - private Version getEmbeddedBundleVersion() { - String versionStr = PlatformUtils.getBundleVersion(); - if (versionStr == null || "unknown".equals(versionStr)) { - return null; - } - try { - return Version.parseVersion(versionStr); - } catch (IllegalArgumentException e) { - CopilotCore.LOGGER.error("Failed to parse Copilot bundle version: " + versionStr, e); - return null; - } - } - - /** - * Get URL to the embedded terminal bundle JAR from the UI plugin. - */ - private URL getEmbeddedBundleUrl(String bundleJarName) { - try { - Bundle[] bundles = bundleContext.getBundles(); - for (Bundle bundle : bundles) { - if ("com.microsoft.copilot.eclipse.ui".equals(bundle.getSymbolicName())) { - URL bundleUrl = FileLocator.find(bundle, new Path(TERMINAL_BUNDLES_PATH + bundleJarName)); - if (bundleUrl != null) { - return FileLocator.toFileURL(bundleUrl); - } - } - } - return null; - - } catch (IOException e) { - CopilotCore.LOGGER.error("Failed to locate embedded bundle resource: " + bundleJarName, e); - return null; - } - } - - /** - * Install or update bundle from embedded JAR URL. - * - * @param bundleUrl URL to the bundle JAR - * @param existingBundle existing bundle to update, or null to install new - * @param monitor progress monitor - */ - private IStatus installOrUpdateBundle(URL bundleUrl, Bundle existingBundle, IProgressMonitor monitor) - throws InterruptedException, BundleException { - Bundle targetBundle; - - if (existingBundle != null) { - // Update existing bundle - try (var in = bundleUrl.openStream()) { - existingBundle.update(in); - targetBundle = existingBundle; - } catch (BundleException | IOException e) { - CopilotCore.LOGGER.error("Failed to update terminal bundle", e); - return new Status(IStatus.ERROR, bundleContext.getBundle().getSymbolicName(), - "Failed to update terminal bundle: " + e.getMessage(), e); - } - } else { - // Install new bundle - try { - targetBundle = bundleContext.installBundle(bundleUrl.toString()); - } catch (BundleException e) { - CopilotCore.LOGGER.error("Failed to install terminal bundle", e); - return new Status(IStatus.ERROR, bundleContext.getBundle().getSymbolicName(), - "Failed to install terminal bundle: " + e.getMessage(), e); - } - } - monitor.worked(20); - - // Refresh and start the bundle - monitor.subTask("Refreshing bundles"); - refreshBundles(Set.of(targetBundle)); - monitor.worked(20); - - monitor.subTask("Starting bundle"); - ensureStarted(targetBundle); - monitor.worked(20); - - return Status.OK_STATUS; - } - - /** - * Get missing dependencies by reading Require-Bundle from the embedded JAR's MANIFEST.MF and checking which ones are - * not available in the runtime. - * - * @return list of missing bundle symbolic names, empty if all dependencies are available - */ - private List getMissingDependencies() { - List missing = new ArrayList<>(); - - try { - String jarName = isModernTerminal ? MODERN_TERMINAL_BUNDLE_JAR : TM_TERMINAL_BUNDLE_JAR; - URL bundleUrl = getEmbeddedBundleUrl(jarName); - if (bundleUrl == null) { - return missing; - } - - try (JarInputStream jarStream = new JarInputStream(bundleUrl.openStream())) { - Manifest manifest = jarStream.getManifest(); - if (manifest != null) { - String requireBundle = manifest.getMainAttributes().getValue("Require-Bundle"); - if (requireBundle != null) { - for (String bundleName : parseRequireBundle(requireBundle)) { - if (Platform.getBundle(bundleName) == null) { - missing.add(bundleName); - } - } - } - } - } - } catch (IOException e) { - CopilotCore.LOGGER.error("Failed to check dependencies from embedded JAR", e); - } - - return missing; - } - - /** - * Parse the Require-Bundle manifest header to extract bundle symbolic names. Uses Eclipse's ManifestElement parser - * for accurate OSGi header parsing. - * - * @param requireBundle the Require-Bundle header value - * @return array of bundle symbolic names - */ - private String[] parseRequireBundle(String requireBundle) { - List dependencies = new ArrayList<>(); - - try { - ManifestElement[] elements = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, requireBundle); - if (elements != null) { - for (ManifestElement element : elements) { - String bundleName = element.getValue(); - if (bundleName != null && !bundleName.isEmpty()) { - dependencies.add(bundleName); - } - } - } - } catch (BundleException e) { - CopilotCore.LOGGER.error("Failed to parse Require-Bundle header", e); - } - - return dependencies.toArray(new String[0]); - } - - /** - * Detect if the current Eclipse platform supports modern terminal (Eclipse 4.37+). - */ - private static boolean detectModernTerminal() { - Version currentVersion = PlatformUtils.getEclipseVersion(); - if (currentVersion == null) { - // Default to modern terminal if version check fails - return true; - } - return currentVersion.compareTo(TARGET_PLATFORM_VERSION) >= 0; - } - - /** - * Get an installed bundle by symbolic name. - */ - private Bundle getInstalledBundle(String symbolicName) { - for (Bundle bundle : bundleContext.getBundles()) { - if (symbolicName.equals(bundle.getSymbolicName())) { - return bundle; - } - } - return null; - } - - /** - * Refresh bundles to apply wiring changes. - */ - private void refreshBundles(Set toRefresh) throws InterruptedException { - if (!toRefresh.isEmpty()) { - final CountDownLatch latch = new CountDownLatch(1); - FrameworkWiring frameworkWiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class); - frameworkWiring.refreshBundles(toRefresh, new FrameworkListener() { - @Override - public void frameworkEvent(FrameworkEvent event) { - if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) { - latch.countDown(); - } else if (event.getType() == FrameworkEvent.ERROR) { - latch.countDown(); - } - } - }); - latch.await(10, TimeUnit.SECONDS); - } - } - - /** - * Ensure a bundle is started. - */ - private void ensureStarted(Bundle bundle) throws BundleException { - if (bundle.getState() != Bundle.ACTIVE && bundle.getState() != Bundle.STARTING) { - bundle.start(Bundle.START_TRANSIENT | Bundle.START_ACTIVATION_POLICY); - } - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +package com.microsoft.copilot.eclipse.terminal.api; + +import java.util.concurrent.CopyOnWriteArrayList; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * Central manager for terminal services. Tracks the {@link IRunInTerminalTool} OSGi service provided by the terminal + * implementation bundle and notifies listeners when it becomes available. + */ +public class TerminalServiceManager { + + /** + * Static inner class for lazy initialization of singleton instance. + */ + private static class InstanceHolder { + private static final TerminalServiceManager INSTANCE = createInstance(); + + private static TerminalServiceManager createInstance() { + Bundle apiBundle = FrameworkUtil.getBundle(TerminalServiceManager.class); + if (apiBundle != null) { + BundleContext context = apiBundle.getBundleContext(); + if (context != null) { + TerminalServiceManager instance = new TerminalServiceManager(context); + instance.start(); + return instance; + } + } + return null; + } + } + + private final BundleContext bundleContext; + private ServiceTracker serviceTracker; + private final CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>(); + private volatile IRunInTerminalTool currentService = null; + + /** + * Interface for listening to terminal service availability changes. + */ + public interface TerminalServiceListener { + /** + * Called when a terminal service becomes available. + * + * @param service the available terminal service + */ + void onServiceAvailable(IRunInTerminalTool service); + } + + private TerminalServiceManager(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + /** + * Get the singleton instance of TerminalServiceManager. + */ + public static TerminalServiceManager getInstance() { + return InstanceHolder.INSTANCE; + } + + /** + * Add a listener for terminal service events. + */ + public void addListener(TerminalServiceListener listener) { + if (listener != null) { + listeners.add(listener); + + // If service is already available, notify immediately + if (currentService != null) { + listener.onServiceAvailable(currentService); + } + } + } + + /** + * Remove a listener for terminal service events. + */ + public void removeListener(TerminalServiceListener listener) { + listeners.remove(listener); + } + + /** + * Get the current terminal service if available. + */ + public IRunInTerminalTool getCurrentService() { + return currentService; + } + + /** + * Start tracking terminal services. + */ + private void start() { + ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer<>() { + @Override + public IRunInTerminalTool addingService(ServiceReference reference) { + IRunInTerminalTool service = bundleContext.getService(reference); + if (service != null) { + currentService = service; + notifyServiceAvailable(service); + } + return service; + } + + @Override + public void modifiedService(ServiceReference reference, IRunInTerminalTool service) { + if (service != null) { + currentService = service; + notifyServiceAvailable(service); + } + } + + @Override + public void removedService(ServiceReference reference, IRunInTerminalTool service) { + } + }; + + serviceTracker = new ServiceTracker<>(bundleContext, IRunInTerminalTool.class, customizer); + serviceTracker.open(); + + IRunInTerminalTool[] services = serviceTracker.getServices(new IRunInTerminalTool[0]); + if (services != null && services.length > 0) { + currentService = services[0]; + } + } + + /** + * Stop the service manager. + */ + public void stop() { + if (serviceTracker != null) { + serviceTracker.close(); + serviceTracker = null; + } + currentService = null; + listeners.clear(); + } + + private void notifyServiceAvailable(IRunInTerminalTool service) { + for (TerminalServiceListener listener : listeners) { + listener.onServiceAvailable(service); + } + } +} diff --git a/com.microsoft.copilot.eclipse.ui.jobs.test/.classpath b/com.microsoft.copilot.eclipse.ui.jobs.test/.classpath index 38f401ad4..2167a547d 100644 --- a/com.microsoft.copilot.eclipse.ui.jobs.test/.classpath +++ b/com.microsoft.copilot.eclipse.ui.jobs.test/.classpath @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.copilot.eclipse.ui.jobs.test/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.ui.jobs.test/META-INF/MANIFEST.MF index 7acdbcaf6..4be973136 100644 --- a/com.microsoft.copilot.eclipse.ui.jobs.test/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.ui.jobs.test/META-INF/MANIFEST.MF @@ -4,10 +4,11 @@ Bundle-Name: com.microsoft.copilot.eclipse.ui.jobs.test Bundle-SymbolicName: com.microsoft.copilot.eclipse.ui.jobs.test;singleton:=true Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Automatic-Module-Name: com.microsoft.copilot.eclipse.ui.jobs.test -Require-Bundle: junit-jupiter-api;bundle-version="5.10.1", - junit-jupiter-params;bundle-version="5.10.1", +Require-Bundle: junit-jupiter-api;bundle-version="[5.10.1,6.0.0)", + junit-jupiter-engine;bundle-version="[5.10.1,6.0.0)", + junit-jupiter-params;bundle-version="[5.10.1,6.0.0)", org.eclipse.core.runtime;bundle-version="[3.30.0,4.0.0)", com.microsoft.copilot.eclipse.ui.jobs;bundle-version="0.21.0" Import-Package: org.osgi.framework;version="[1.10.0,2.0.0)" diff --git a/com.microsoft.copilot.eclipse.ui.jobs/.classpath b/com.microsoft.copilot.eclipse.ui.jobs/.classpath index 5508535a4..b1415d56b 100644 --- a/com.microsoft.copilot.eclipse.ui.jobs/.classpath +++ b/com.microsoft.copilot.eclipse.ui.jobs/.classpath @@ -1,7 +1,11 @@ - - - - - - - + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.jdt.core.prefs index 20cc7b588..f7d4b5bfd 100644 --- a/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.ui.jobs/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,10 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 diff --git a/com.microsoft.copilot.eclipse.ui.jobs/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.ui.jobs/META-INF/MANIFEST.MF index 0fee3467d..e76c9cd27 100644 --- a/com.microsoft.copilot.eclipse.ui.jobs/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.ui.jobs/META-INF/MANIFEST.MF @@ -5,7 +5,7 @@ Bundle-SymbolicName: com.microsoft.copilot.eclipse.ui.jobs;singleton:=true Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot Bundle-Activator: com.microsoft.copilot.eclipse.ui.jobs.CopilotJobs -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Bundle-Localization: plugin Automatic-Module-Name: com.microsoft.copilot.eclipse.ui.jobs Bundle-ActivationPolicy: lazy diff --git a/com.microsoft.copilot.eclipse.ui.jobs/build.properties b/com.microsoft.copilot.eclipse.ui.jobs/build.properties index 18012dbed..2257d7129 100644 --- a/com.microsoft.copilot.eclipse.ui.jobs/build.properties +++ b/com.microsoft.copilot.eclipse.ui.jobs/build.properties @@ -1,5 +1,5 @@ source.. = src/ -output.. = bin/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/.checkstyle b/com.microsoft.copilot.eclipse.ui.terminal.tm/.checkstyle deleted file mode 100644 index 357a84774..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/.checkstyle +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/.classpath b/com.microsoft.copilot.eclipse.ui.terminal.tm/.classpath deleted file mode 100644 index 8d8612144..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/.project b/com.microsoft.copilot.eclipse.ui.terminal.tm/.project deleted file mode 100644 index cac3b0de6..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/.project +++ /dev/null @@ -1,45 +0,0 @@ - - - com.microsoft.copilot.eclipse.ui.terminal.tm - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - net.sf.eclipsecs.core.CheckstyleBuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - org.eclipse.pde.ds.core.builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - net.sf.eclipsecs.core.CheckstyleNature - - diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.ui.terminal.tm/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 62ef3488c..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,9 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning -org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/.settings/org.eclipse.m2e.core.prefs b/com.microsoft.copilot.eclipse.ui.terminal.tm/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f1c..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.ui.terminal.tm/META-INF/MANIFEST.MF deleted file mode 100644 index c4a5f14bc..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/META-INF/MANIFEST.MF +++ /dev/null @@ -1,21 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: com.microsoft.copilot.eclipse.ui.terminal.tm -Bundle-SymbolicName: com.microsoft.copilot.eclipse.ui.terminal.tm;singleton:=true -Bundle-Version: 0.21.0.qualifier -Bundle-Vendor: GitHub Copilot -Bundle-RequiredExecutionEnvironment: JavaSE-17 -Automatic-Module-Name: com.microsoft.copilot.eclipse.ui.terminal.tm -Bundle-ActivationPolicy: lazy -Service-Component: OSGI-INF/component.xml -Import-Package: org.osgi.framework;version="[1.10.0,2.0.0)", - org.osgi.service.component -Require-Bundle: com.microsoft.copilot.eclipse.terminal.api;bundle-version="0.21.0", - org.eclipse.tm.terminal.view.core, - org.eclipse.tm.terminal.view.ui, - org.eclipse.tm.terminal.control, - org.eclipse.tm.terminal.connector.local, - org.eclipse.tm.terminal.connector.process, - org.eclipse.ui;bundle-version="3.205.0", - org.apache.commons.lang3;bundle-version="3.13.0", - org.eclipse.core.runtime;bundle-version="[3.30.0,4.0.0)" diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/OSGI-INF/component.xml b/com.microsoft.copilot.eclipse.ui.terminal.tm/OSGI-INF/component.xml deleted file mode 100644 index c21fca9cb..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/OSGI-INF/component.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/build.properties b/com.microsoft.copilot.eclipse.ui.terminal.tm/build.properties deleted file mode 100644 index 4aee9b7ab..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - .,\ - OSGI-INF/component.xml \ No newline at end of file diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/pom.xml b/com.microsoft.copilot.eclipse.ui.terminal.tm/pom.xml deleted file mode 100644 index 1d4b39049..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - 4.0.0 - - com.microsoft.copilot.eclipse - github-copilot-for-eclipse - ${copilot-plugin-version} - - com.microsoft.copilot.eclipse.ui.terminal.tm - eclipse-plugin - ${base.name} :: TM Terminal - - - - org.eclipse.tycho - target-platform-configuration - ${tycho-version} - - - ../target-tm-terminal.target - - - - - org.eclipse.tycho - tycho-maven-plugin - ${tycho-version} - true - - - org.eclipse.tycho - tycho-packaging-plugin - - - - \ No newline at end of file diff --git a/com.microsoft.copilot.eclipse.ui.terminal.tm/src/com/microsoft/copilot/eclipse/ui/terminal/tm/RunInTerminalTool.java b/com.microsoft.copilot.eclipse.ui.terminal.tm/src/com/microsoft/copilot/eclipse/ui/terminal/tm/RunInTerminalTool.java deleted file mode 100644 index 4e27a0d30..000000000 --- a/com.microsoft.copilot.eclipse.ui.terminal.tm/src/com/microsoft/copilot/eclipse/ui/terminal/tm/RunInTerminalTool.java +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package com.microsoft.copilot.eclipse.ui.terminal.tm; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - -import org.apache.commons.lang3.StringUtils; -import org.eclipse.core.runtime.Platform; -import org.eclipse.swt.custom.CTabFolder; -import org.eclipse.swt.custom.CTabItem; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Display; -import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; -import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; -import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; -import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; -import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; -import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; -import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; -import org.eclipse.tm.terminal.view.ui.interfaces.IPreferenceKeys; -import org.eclipse.tm.terminal.view.ui.interfaces.IUIConstants; -import org.eclipse.ui.IViewPart; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.osgi.service.component.annotations.Component; - -import com.microsoft.copilot.eclipse.terminal.api.IRunInTerminalTool; -import com.microsoft.copilot.eclipse.terminal.api.ShellIntegrationScripts; -import com.microsoft.copilot.eclipse.terminal.api.TerminalCommandProcessor; -import com.microsoft.copilot.eclipse.terminal.api.TerminalCommandProcessor.CompletionCheckResult; -import com.microsoft.copilot.eclipse.terminal.api.TerminalCommandProcessor.CompletionCheckState; - -/** - * terminal tool implementation for older Eclipse versions. - */ -@Component(service = IRunInTerminalTool.class, immediate = true) -public class RunInTerminalTool implements IRunInTerminalTool { - // Shared constants and static fields - private static final Object lock = new Object(); - private static final Map backgroundCommandOutputs = new HashMap<>(); - private static final String BACKGROUND_TERMINAL_PREFIX = "Copilot-"; - private static final String POWERSHELL_SCRIPT_ENV = "COPILOT_POWERSHELL_INTEGRATION_SCRIPT"; - private static final String COMMAND_CANCELLED_MESSAGE = "Terminal command cancelled."; - private static final String COMMAND_INTERRUPTED_MESSAGE = "Terminal command interrupted by a new command."; - - // Non-background terminal field - private ITerminalViewControl persistentTerminalViewControl; - - // Terminal UI-related fields - private ITerminalControl terminalControl; - private CTabFolder tabFolder; - private CTabItem copilotTabItem; - private Supplier terminalIconSupplier; - - // Output and command state - private StringBuilder sb; - private volatile ForegroundCommand foregroundCommand; - - /** - * Constructor for RunInTerminalTool. - */ - public RunInTerminalTool() { - this.sb = new StringBuilder(); - } - - @Override - public CompletableFuture executeCommand(String command, boolean isBackground, String workingDirectory) { - if (StringUtils.isBlank(command)) { - return CompletableFuture.completedFuture("The command is null or empty."); - } - - if (!isBackground) { - closeRunningForegroundTerminal(COMMAND_INTERRUPTED_MESSAGE); - } - - CompletableFuture commandFuture = new CompletableFuture<>(); - ForegroundCommand commandState = isBackground ? null - : new ForegroundCommand(commandFuture, hasShellIntegrationMarker()); - - if (commandState != null) { - foregroundCommand = commandState; - if (!commandState.useMarker()) { - // Retain only the last line (prompt) in the output buffer - if (!sb.isEmpty()) { - int lastLineStart = sb.lastIndexOf(StringUtils.LF); - if (lastLineStart > 0) { - sb.delete(0, lastLineStart); - } - } - } else { - // For marker-based detection, clear the buffer - sb.setLength(0); - } - } - - String executionId = UUID.randomUUID().toString(); - final String finalCommand = TerminalCommandProcessor.formatForExecution(command, useBracketedPaste()); - - synchronized (lock) { - if (!isBackground && this.persistentTerminalViewControl != null) { - revealTerminal(); - sendCommand(this.persistentTerminalViewControl, finalCommand); - return commandFuture; - } - - ITerminalService service = TerminalServiceFactory.getService(); - if (service == null) { - clearForegroundCommand(commandState); - return CompletableFuture.completedFuture("Failed to open terminal console due to terminal service is null."); - } - - service.openConsole(prepareTerminalProperties(isBackground, executionId, workingDirectory), status -> { - if (status.isOK()) { - if (commandFuture.isDone()) { - return; - } - ITerminalViewControl terminalViewControl = finalizeTerminalSetup(executionId, isBackground); - if (terminalViewControl == null) { - clearForegroundCommand(commandState); - commandFuture.complete("Terminal view control cannot be setup for RunInTerminalTool."); - return; - } - - if (!isBackground) { - this.persistentTerminalViewControl = terminalViewControl; - revealTerminal(); - } - sendCommand(terminalViewControl, finalCommand); - } else { - clearForegroundCommand(commandState); - commandFuture.complete("Failed to open terminal console: " + status.getException()); - } - }); - } - - if (isBackground) { - return CompletableFuture.completedFuture("Command is running in terminal with ID=" + executionId); - } - - return commandFuture; - } - - @Override - public Map prepareTerminalProperties(boolean runInBackground, String executionId, - String workingDirectory) { - Map properties = new HashMap<>(); - - properties.put(ITerminalsConnectorConstants.PROP_ENCODING, "UTF-8"); - properties.put(ITerminalsConnectorConstants.PROP_TITLE_DISABLE_ANSI_TITLE, true); - if (StringUtils.isNotBlank(workingDirectory)) { - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, workingDirectory); - } - - if (Platform.getOS().equals(Platform.OS_WIN32)) { - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_PATH, "powershell.exe"); - String scriptPath = ShellIntegrationScripts.getPowerShellScriptPath(); - if (scriptPath != null) { - String[] environment = new String[] { POWERSHELL_SCRIPT_ENV + "=" + scriptPath }; - String args = "-NoExit -ExecutionPolicy Bypass -Command \". $env:" + POWERSHELL_SCRIPT_ENV + "\""; - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT, environment); - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT, true); - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, args); - } - } else if (Platform.getOS().equals(Platform.OS_LINUX)) { - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_PATH, "/bin/bash"); - String scriptPath = ShellIntegrationScripts.getBashScriptPath(); - if (scriptPath != null) { - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, "--init-file \"" + scriptPath + "\" -i"); - } - } else { - // macOS or other Unix-like: keep existing behavior, only set args if empty - String args = UIPlugin.getScopedPreferences() - .getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX_ARGS); - if (StringUtils.isBlank(args)) { - properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, "-l"); - } - } - - properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, true); - properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, - "org.eclipse.tm.terminal.connector.local.launcher.local"); - - if (runInBackground) { - properties.put(ITerminalsConnectorConstants.PROP_TITLE, buildBackgroundTerminalTitle(executionId)); - properties.put(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS, - new ITerminalServiceOutputStreamMonitorListener[] { buildOutputStreamMonitorListener(true, executionId) }); - } else { - properties.put(ITerminalsConnectorConstants.PROP_TITLE, "Copilot"); - properties.put(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS, - new ITerminalServiceOutputStreamMonitorListener[] { buildOutputStreamMonitorListener(false, null) }); - } - - return properties; - } - - @Override - public StringBuilder getBackgroundCommandOutput(String executionId) { - StringBuilder output = backgroundCommandOutputs.get(executionId); - return output; - } - - @Override - public void cancelCurrentCommand() { - closeRunningForegroundTerminal(COMMAND_CANCELLED_MESSAGE); - } - - private void closeRunningForegroundTerminal(String completionMessage) { - ForegroundCommand commandState = foregroundCommand; - if (commandState != null && !commandState.future().isDone()) { - closeCurrentForegroundTerminal(completionMessage); - } - } - - private void closeCurrentForegroundTerminal(String completionMessage) { - ForegroundCommand commandState = null; - CTabItem tabItem = null; - synchronized (lock) { - commandState = foregroundCommand; - foregroundCommand = null; - persistentTerminalViewControl = null; - tabItem = copilotTabItem; - copilotTabItem = null; - sb.setLength(0); - } - - if (tabItem != null) { - final CTabItem tabItemToDispose = tabItem; - // Keep this synchronous so a new foreground command cannot open before the old terminal tab is disposed. - Display.getDefault().syncExec(() -> { - if (!tabItemToDispose.isDisposed()) { - tabItemToDispose.dispose(); - } - }); - } - if (commandState != null && !commandState.future().isDone()) { - commandState.future().complete(completionMessage); - } - } - - private void clearForegroundCommand(ForegroundCommand commandState) { - if (commandState != null && foregroundCommand == commandState) { - foregroundCommand = null; - } - } - - private void sendCommand(ITerminalViewControl terminalViewControl, String command) { - terminalViewControl.pasteString(command); - } - - private boolean hasShellIntegrationMarker() { - if (Platform.getOS().equals(Platform.OS_WIN32)) { - return ShellIntegrationScripts.getPowerShellScriptPath() != null; - } - if (Platform.getOS().equals(Platform.OS_LINUX)) { - return ShellIntegrationScripts.getBashScriptPath() != null; - } - return false; - } - - private boolean useBracketedPaste() { - // macOS terminal multiline handling differs from PowerShell/Bash integration, so keep its existing plain input. - return Platform.getOS().equals(Platform.OS_WIN32) || Platform.getOS().equals(Platform.OS_LINUX); - } - - private ITerminalViewControl finalizeTerminalSetup(String executionId, boolean isBackground) { - String title = isBackground ? buildBackgroundTerminalTitle(executionId) : "Copilot"; - synchronized (lock) { - terminalControl = getTerminalControl(title, isBackground); - if (terminalControl != null && terminalControl instanceof ITerminalViewControl iterminalviewcontrol) { - return iterminalviewcontrol; - } - } - return null; - } - - private ITerminalControl getTerminalControl(String terminalTitle, boolean isBackground) { - AtomicReference ref = new AtomicReference<>(); - - Display.getDefault().syncExec(() -> { - try { - IWorkbenchPage page = getActivePage(); - if (page != null) { - IViewPart view = page.showView(IUIConstants.ID, null, IWorkbenchPage.VIEW_VISIBLE); - if (view != null) { - tabFolder = view.getAdapter(CTabFolder.class); - if (tabFolder != null) { - for (CTabItem item : tabFolder.getItems()) { - if (terminalTitle.equals(item.getText())) { - Image terminalIcon = resolveTerminalIcon(); - if (terminalIcon != null && !terminalIcon.isDisposed()) { - item.setImage(terminalIcon); - } - item.addDisposeListener( - buildDisposeListener(terminalTitle.replace(BACKGROUND_TERMINAL_PREFIX, ""), isBackground)); - if (!isBackground) { - // Foreground terminal command will reuse the tab item, so keep a reference to the tab item - copilotTabItem = item; - } - ref.set((ITerminalControl) item.getData()); - break; - } - } - } - } - } - } catch (PartInitException e) { - // Skip exception - } - }); - - return ref.get(); - } - - private ITerminalServiceOutputStreamMonitorListener buildOutputStreamMonitorListener(boolean isBackground, - String executionId) { - StringBuilder output = isBackground ? new StringBuilder() : sb; - if (isBackground) { - backgroundCommandOutputs.put(executionId, output); - } - - return (byteBuffer, bytesRead) -> { - String content = new String(byteBuffer, 0, bytesRead, StandardCharsets.UTF_8); - // Remove ANSI escape sequences while preserving only real line breaks from the terminal output. - content = content.replaceAll("\u001B\\[(\\?)?[\\d;]*[a-zA-Z]", ""); - - // Handle Windows terminal title sequences - using Platform instead of - // PlatformUtils - if (Platform.getOS().equals(Platform.OS_WIN32)) { - // Remove terminal title sequences in Windows - // It sometimes appears at the last line, which will also destroy the validation - // of the last prompt line. - content = content.replaceAll("\u001B\\][0-9];.*?(\u0007|\u001B\\\\)", ""); - } - - output.append(content); - - // Detect completion based on platform strategy - ForegroundCommand commandState = foregroundCommand; - if (!isBackground && commandState != null && !commandState.future().isDone()) { - CompletionCheckResult completionResult = commandState.useMarker() - ? TerminalCommandProcessor.tryCompleteWithMarker(output) - : TerminalCommandProcessor.tryCompleteWithPrompt(output); - handleCompletionResult(commandState, completionResult); - } - }; - } - - private void handleCompletionResult(ForegroundCommand commandState, CompletionCheckResult completionResult) { - if (completionResult.state() == CompletionCheckState.INCOMPLETE) { - return; - } - if (foregroundCommand == commandState) { - foregroundCommand = null; - } - if (!commandState.future().isDone()) { - commandState.future().complete(completionResult.output()); - } - } - - private DisposeListener buildDisposeListener(String executionId, boolean isBackground) { - return e -> { - if (isBackground) { - backgroundCommandOutputs.remove(executionId); - } else { - persistentTerminalViewControl = null; - } - - if (backgroundCommandOutputs.isEmpty() && persistentTerminalViewControl == null) { - terminalControl = null; - } - }; - } - - private void revealTerminal() { - if (tabFolder != null && copilotTabItem != null) { - Display.getDefault().syncExec(() -> { - try { - IWorkbenchPage page = getActivePage(); - if (page != null) { - IViewPart view = page.showView(IUIConstants.ID, null, IWorkbenchPage.VIEW_VISIBLE); - if (tabFolder.isDisposed() && view != null) { - tabFolder = view.getAdapter(CTabFolder.class); - } - } - if (tabFolder != null && !tabFolder.isDisposed()) { - tabFolder.setSelection(copilotTabItem); - } - } catch (PartInitException e) { - // Skip exception - } - }); - } - } - - private String buildBackgroundTerminalTitle(String executionId) { - return BACKGROUND_TERMINAL_PREFIX + executionId; - } - - private record ForegroundCommand(CompletableFuture future, boolean useMarker) { - } - - /** - * Get active workbench page without UiUtils dependency. - */ - private IWorkbenchPage getActivePage() { - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - if (window != null) { - return window.getActivePage(); - } - return null; - } - - @Override - public void setTerminalIconSupplier(Supplier terminalIconSupplier) { - this.terminalIconSupplier = terminalIconSupplier; - } - - /** Call this method from UI thread only. */ - private Image resolveTerminalIcon() { - if (terminalIconSupplier == null) { - return null; - } - return terminalIconSupplier.get(); - } -} diff --git a/com.microsoft.copilot.eclipse.ui.terminal/.classpath b/com.microsoft.copilot.eclipse.ui.terminal/.classpath index e0ce1f7ec..b1415d56b 100644 --- a/com.microsoft.copilot.eclipse.ui.terminal/.classpath +++ b/com.microsoft.copilot.eclipse.ui.terminal/.classpath @@ -1,8 +1,11 @@ - - - - - - - - + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.jdt.core.prefs index 62ef3488c..23fa13b17 100644 --- a/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.ui.terminal/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 diff --git a/com.microsoft.copilot.eclipse.ui.terminal/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.ui.terminal/META-INF/MANIFEST.MF index 4aa767cfc..bb646a7e7 100644 --- a/com.microsoft.copilot.eclipse.ui.terminal/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.ui.terminal/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-Name: com.microsoft.copilot.eclipse.ui.terminal Bundle-SymbolicName: com.microsoft.copilot.eclipse.ui.terminal;singleton:=true Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Automatic-Module-Name: com.microsoft.copilot.eclipse.ui.terminal Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/component.xml diff --git a/com.microsoft.copilot.eclipse.ui.terminal/build.properties b/com.microsoft.copilot.eclipse.ui.terminal/build.properties index 4aee9b7ab..367dd831e 100644 --- a/com.microsoft.copilot.eclipse.ui.terminal/build.properties +++ b/com.microsoft.copilot.eclipse.ui.terminal/build.properties @@ -1,5 +1,5 @@ source.. = src/ -output.. = bin/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/component.xml \ No newline at end of file diff --git a/com.microsoft.copilot.eclipse.ui.terminal/pom.xml b/com.microsoft.copilot.eclipse.ui.terminal/pom.xml index f70016ec1..830edfbf6 100644 --- a/com.microsoft.copilot.eclipse.ui.terminal/pom.xml +++ b/com.microsoft.copilot.eclipse.ui.terminal/pom.xml @@ -18,7 +18,7 @@ ${tycho-version} - ../target-terminal.target + ../target-platforms/2025-12.target diff --git a/com.microsoft.copilot.eclipse.ui.test/.classpath b/com.microsoft.copilot.eclipse.ui.test/.classpath index 38f401ad4..766df48f2 100644 --- a/com.microsoft.copilot.eclipse.ui.test/.classpath +++ b/com.microsoft.copilot.eclipse.ui.test/.classpath @@ -1,11 +1,15 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.jdt.core.prefs index 62ef3488c..23fa13b17 100644 --- a/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.ui.test/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 diff --git a/com.microsoft.copilot.eclipse.ui.test/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.ui.test/META-INF/MANIFEST.MF index ab85b21d7..cba4993d7 100644 --- a/com.microsoft.copilot.eclipse.ui.test/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.ui.test/META-INF/MANIFEST.MF @@ -4,7 +4,7 @@ Bundle-Name: com.microsoft.copilot.eclipse.ui.test Bundle-SymbolicName: com.microsoft.copilot.eclipse.ui.test;singleton:=true Bundle-Version: 0.21.0.qualifier Bundle-Vendor: GitHub Copilot -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Fragment-Host: com.microsoft.copilot.eclipse.ui Automatic-Module-Name: com.microsoft.copilot.eclipse.ui.test Import-Package: org.objenesis;version="[3.4.0,4.0.0)" diff --git a/com.microsoft.copilot.eclipse.ui.test/build.properties b/com.microsoft.copilot.eclipse.ui.test/build.properties index 07c97efed..8ffd63634 100644 --- a/com.microsoft.copilot.eclipse.ui.test/build.properties +++ b/com.microsoft.copilot.eclipse.ui.test/build.properties @@ -1,5 +1,5 @@ -source.. = src -output.. = target/classes +source.. = src/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ fragment.xml diff --git a/com.microsoft.copilot.eclipse.ui/.classpath b/com.microsoft.copilot.eclipse.ui/.classpath index 8d8612144..b1415d56b 100644 --- a/com.microsoft.copilot.eclipse.ui/.classpath +++ b/com.microsoft.copilot.eclipse.ui/.classpath @@ -1,7 +1,11 @@ - - - - - - - + + + + + + + + + + + diff --git a/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.core.resources.prefs b/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..4824b8026 --- /dev/null +++ b/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.jdt.core.prefs b/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.jdt.core.prefs index 21eccc094..a98206bc4 100644 --- a/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.jdt.core.prefs +++ b/com.microsoft.copilot.eclipse.ui/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns=false org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 diff --git a/com.microsoft.copilot.eclipse.ui/META-INF/MANIFEST.MF b/com.microsoft.copilot.eclipse.ui/META-INF/MANIFEST.MF index a7cc5c25d..73b4f6120 100644 --- a/com.microsoft.copilot.eclipse.ui/META-INF/MANIFEST.MF +++ b/com.microsoft.copilot.eclipse.ui/META-INF/MANIFEST.MF @@ -21,7 +21,7 @@ Export-Package: com.microsoft.copilot.eclipse.ui, com.microsoft.copilot.eclipse.ui.extensions, com.microsoft.copilot.eclipse.ui.nes;x-friends:="com.microsoft.copilot.eclipse.ui.test" Bundle-Activator: com.microsoft.copilot.eclipse.ui.CopilotUi -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Automatic-Module-Name: com.microsoft.copilot.eclipse.ui Bundle-ActivationPolicy: lazy Import-Package: org.osgi.framework;version="[1.10.0,2.0.0)" diff --git a/com.microsoft.copilot.eclipse.ui/build.properties b/com.microsoft.copilot.eclipse.ui/build.properties index 5ba08abef..495210f7a 100644 --- a/com.microsoft.copilot.eclipse.ui/build.properties +++ b/com.microsoft.copilot.eclipse.ui/build.properties @@ -1,5 +1,5 @@ -source.. = src -output.. = target/classes +source.. = src/ +output.. = target/classes/ bin.includes = META-INF/,\ .,\ plugin.xml,\ @@ -7,5 +7,4 @@ bin.includes = META-INF/,\ plugin.properties,\ css/,\ intro/,\ - terminal-bundles/*.jar,\ contexts.xml diff --git a/com.microsoft.copilot.eclipse.ui/pom.xml b/com.microsoft.copilot.eclipse.ui/pom.xml index ebe39c403..5bbe2df3f 100644 --- a/com.microsoft.copilot.eclipse.ui/pom.xml +++ b/com.microsoft.copilot.eclipse.ui/pom.xml @@ -23,30 +23,6 @@ ${tycho-version} true - - org.apache.maven.plugins - maven-antrun-plugin - 3.1.0 - - - copy-terminal-jars - process-resources - - run - - - - - - - - - - org.eclipse.tycho tycho-packaging-plugin diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/UiConstants.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/UiConstants.java index 6cfbb8371..2d163907b 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/UiConstants.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/UiConstants.java @@ -36,6 +36,5 @@ private UiConstants() { public static final String GITHUB_COPILOT_CODING_AGENT_SLUG = "github-copilot-coding-agent"; public static final String GITHUB_COPILOT_CODING_AGENT_LEARN_MORE_URL = "https://aka.ms/learn-copilot-coding-agent"; - public static final String TERMINAL_DEPENDENCY_GUIDE_URL = "https://aka.ms/terminal-dependency-guide"; public static final String COPILOT_RATE_LIMIT_INFO_URL = "https://aka.ms/github-copilot-rate-limit-error"; } diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/services/AgentToolService.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/services/AgentToolService.java index c7a013c2a..2ce55d56b 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/services/AgentToolService.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/services/AgentToolService.java @@ -49,7 +49,6 @@ import com.microsoft.copilot.eclipse.ui.chat.tools.JavaDebuggerToolAdapter; import com.microsoft.copilot.eclipse.ui.chat.tools.RunInTerminalToolAdapter; import com.microsoft.copilot.eclipse.ui.chat.tools.RunInTerminalToolAdapter.GetTerminalOutputTool; -import com.microsoft.copilot.eclipse.ui.dialogs.MissingTerminalDependenciesDialog; import com.microsoft.copilot.eclipse.ui.utils.SwtUtils; /** @@ -95,11 +94,6 @@ public void onServiceAvailable(IRunInTerminalTool service) { } } - @Override - public void onMissingDependencies(String terminalType, List missingDependencies) { - MissingTerminalDependenciesDialog.showIfNotSuppressed(terminalType, missingDependencies); - } - /** * Register default tools. */ diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/Messages.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/Messages.java index 29fee450d..3c0ed05c1 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/Messages.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/Messages.java @@ -21,15 +21,6 @@ public final class Messages extends NLS { public static String projectSelectionDialog_button_continue; public static String githubCodingAgent_link_learnMore; - // Terminal dependency dialog - public static String terminalDependencyDialog_shellTitle; - public static String terminalDependencyDialog_title; - public static String terminalDependencyDialog_message; - public static String terminalDependencyDialog_missingDependencies; - public static String terminalDependencyDialog_instruction; - public static String terminalDependencyDialog_helpLink; - public static String terminalDependencyDialog_dontShowAgain; - static { // initialize resource bundle NLS.initializeMessages("com.microsoft.copilot.eclipse.ui.dialogs.messages", Messages.class); diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/MissingTerminalDependenciesDialog.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/MissingTerminalDependenciesDialog.java deleted file mode 100644 index 1e87cdfcc..000000000 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/MissingTerminalDependenciesDialog.java +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package com.microsoft.copilot.eclipse.ui.dialogs; - -import java.util.List; - -import org.eclipse.core.runtime.preferences.ConfigurationScope; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.program.Program; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Link; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.PlatformUI; -import org.osgi.service.prefs.BackingStoreException; - -import com.microsoft.copilot.eclipse.core.Constants; -import com.microsoft.copilot.eclipse.core.CopilotCore; -import com.microsoft.copilot.eclipse.ui.CopilotImages; -import com.microsoft.copilot.eclipse.ui.CopilotUi; -import com.microsoft.copilot.eclipse.ui.UiConstants; -import com.microsoft.copilot.eclipse.ui.utils.SwtUtils; - -/** - * Dialog to inform users about missing terminal dependencies. Provides information about what needs to be installed and - * a link to documentation. - */ -public class MissingTerminalDependenciesDialog extends TitleAreaDialog { - - private final String terminalType; - private final List missingDependencies; - private Button dontShowAgainCheckbox; - - /** - * Creates the dialog. - * - * @param parentShell the parent shell - * @param terminalType the type of terminal (e.g., "Eclipse Terminal" or "TM Terminal") - * @param missingDependencies list of missing bundle symbolic names - */ - public MissingTerminalDependenciesDialog(Shell parentShell, String terminalType, List missingDependencies) { - super(parentShell); - this.terminalType = terminalType; - this.missingDependencies = missingDependencies; - setShellStyle(getShellStyle() | SWT.RESIZE); - } - - @Override - protected void configureShell(Shell shell) { - super.configureShell(shell); - shell.setText(Messages.terminalDependencyDialog_shellTitle); - loadIcon(shell); - } - - private void loadIcon(Shell shell) { - Image icon = CopilotImages.getImage(CopilotImages.IMG_GITHUB_COPILOT); - if (icon != null) { - shell.setImage(icon); - } - } - - @Override - protected Control createDialogArea(Composite parent) { - setTitle(Messages.terminalDependencyDialog_title); - setMessage(NLS.bind(Messages.terminalDependencyDialog_message, terminalType)); - - Composite area = (Composite) super.createDialogArea(parent); - - Composite container = new Composite(area, SWT.NONE); - container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - GridLayout layout = new GridLayout(1, false); - layout.marginWidth = 15; - layout.marginHeight = 15; - layout.verticalSpacing = 10; - container.setLayout(layout); - - // Missing dependencies section - Label depsLabel = new Label(container, SWT.NONE); - depsLabel.setText(Messages.terminalDependencyDialog_missingDependencies); - depsLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)); - for (String dep : missingDependencies) { - Label depItem = new Label(container, SWT.NONE); - depItem.setText(" - " + dep); - depItem.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - } - - Label instructionLabel = new Label(container, SWT.WRAP); - instructionLabel.setText(NLS.bind(Messages.terminalDependencyDialog_instruction, terminalType)); - GridData instructionData = new GridData(SWT.FILL, SWT.CENTER, true, false); - instructionData.widthHint = 400; - instructionData.verticalIndent = 10; - instructionLabel.setLayoutData(instructionData); - - // Help link - Link link = new Link(container, SWT.NONE); - link.setText(NLS.bind(Messages.terminalDependencyDialog_helpLink, UiConstants.TERMINAL_DEPENDENCY_GUIDE_URL)); - link.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - Program.launch(e.text); - } - }); - GridData linkData = new GridData(SWT.FILL, SWT.CENTER, true, false); - linkData.verticalIndent = 5; - link.setLayoutData(linkData); - - // Don't show again checkbox - dontShowAgainCheckbox = new Button(container, SWT.CHECK); - dontShowAgainCheckbox.setText(Messages.terminalDependencyDialog_dontShowAgain); - GridData checkboxData = new GridData(SWT.FILL, SWT.CENTER, true, false); - checkboxData.verticalIndent = 15; - dontShowAgainCheckbox.setLayoutData(checkboxData); - - return area; - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); - } - - @Override - protected void okPressed() { - if (dontShowAgainCheckbox != null && dontShowAgainCheckbox.getSelection()) { - setSuppressDialog(true); - } - super.okPressed(); - } - - /** - * Check if the dialog has been suppressed by user preference. - * - * @return true if the dialog should not be shown - */ - public static boolean isDialogSuppressed() { - IEclipsePreferences prefs = ConfigurationScope.INSTANCE - .getNode(CopilotUi.getPlugin().getBundle().getSymbolicName()); - return prefs.getBoolean(Constants.SUPPRESS_TERMINAL_DEPENDENCY_DIALOG, false); - } - - /** - * Set whether to suppress the dialog. - * - * @param suppress true to suppress future dialogs - */ - private static void setSuppressDialog(boolean suppress) { - try { - IEclipsePreferences prefs = ConfigurationScope.INSTANCE - .getNode(CopilotUi.getPlugin().getBundle().getSymbolicName()); - prefs.putBoolean(Constants.SUPPRESS_TERMINAL_DEPENDENCY_DIALOG, suppress); - prefs.flush(); - } catch (BackingStoreException e) { - CopilotCore.LOGGER.error("Failed to persist terminal dialog preference", e); - } - } - - /** - * Shows the dialog if not suppressed by user preference. - * - * @param terminalType the type of terminal required - * @param missingDependencies list of missing dependencies - */ - public static void showIfNotSuppressed(String terminalType, List missingDependencies) { - if (isDialogSuppressed()) { - return; - } - - SwtUtils.invokeOnDisplayThreadAsync(() -> { - if (!PlatformUI.isWorkbenchRunning()) { - return; - } - var window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (window == null) { - return; - } - Shell shell = window.getShell(); - MissingTerminalDependenciesDialog dialog = new MissingTerminalDependenciesDialog(shell, terminalType, - missingDependencies); - dialog.open(); - }); - } -} diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/messages.properties b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/messages.properties index 69e7eadd1..62dd88314 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/messages.properties +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/dialogs/messages.properties @@ -9,12 +9,3 @@ projectSelectionDialog_label_selectProject=Select Project: projectSelectionDialog_button_cancel=Cancel projectSelectionDialog_button_continue=Continue githubCodingAgent_link_learnMore=Learn about coding agent - -# Terminal dependency dialog -terminalDependencyDialog_shellTitle=GitHub Copilot -terminalDependencyDialog_title=Terminal Support Unavailable -terminalDependencyDialog_message=GitHub Copilot's terminal functionality requires the {0}, which is not installed in your Eclipse. -terminalDependencyDialog_missingDependencies=Missing dependencies: -terminalDependencyDialog_instruction=To enable terminal support, please install the {0} from your Eclipse update site. -terminalDependencyDialog_helpLink=Learn how to install terminal support -terminalDependencyDialog_dontShowAgain=Don''t show this message again diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/perspectives/CopilotPerspectiveFactory.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/perspectives/CopilotPerspectiveFactory.java index 2015a0630..7ca15104a 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/perspectives/CopilotPerspectiveFactory.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/perspectives/CopilotPerspectiveFactory.java @@ -40,7 +40,7 @@ public void createInitialLayout(IPageLayout layout) { IFolderLayout consoleLayout = layout.createFolder("bottom", IPageLayout.BOTTOM, 0.8f, editorArea); consoleLayout.addView(IPageLayout.ID_PROBLEM_VIEW); consoleLayout.addView(IConsoleConstants.ID_CONSOLE_VIEW); - consoleLayout.addView("org.eclipse.tm.terminal.view.ui.TerminalsView"); + consoleLayout.addView("org.eclipse.terminal.view.ui.TerminalsView"); consoleLayout.addPlaceholder(IPageLayout.ID_BOOKMARKS); consoleLayout.addPlaceholder(IProgressConstants.PROGRESS_VIEW_ID); @@ -55,7 +55,7 @@ public void createInitialLayout(IPageLayout layout) { layout.addShowViewShortcut(IProgressConstants.PROGRESS_VIEW_ID); layout.addShowViewShortcut(IPageLayout.ID_PROJECT_EXPLORER); layout.addShowViewShortcut(TemplatesView.ID); - layout.addShowViewShortcut("org.eclipse.tm.terminal.view.ui.TerminalsView"); + layout.addShowViewShortcut("org.eclipse.terminal.view.ui.TerminalsView"); layout.addShowViewShortcut("org.eclipse.pde.runtime.LogView"); layout.addShowViewShortcut("org.eclipse.search.ui.views.SearchView"); layout.addShowViewShortcut(Constants.GITHUB_JOBS_VIEW_ID); diff --git a/com.microsoft.copilot.eclipse.ui/terminal-bundles/.gitkeep b/com.microsoft.copilot.eclipse.ui/terminal-bundles/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/launch/Verify Copilot for Eclipse.launch b/launch/Verify Copilot for Eclipse.launch new file mode 100644 index 000000000..e2537bd26 --- /dev/null +++ b/launch/Verify Copilot for Eclipse.launch @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/launch/plugin_debug_configuration.launch b/launch/plugin_debug_configuration.launch index 8c8419e65..eedd1787c 100644 --- a/launch/plugin_debug_configuration.launch +++ b/launch/plugin_debug_configuration.launch @@ -19,7 +19,7 @@ - + diff --git a/pom.xml b/pom.xml index ba917990f..d66246443 100644 --- a/pom.xml +++ b/pom.xml @@ -21,10 +21,9 @@ - + com.microsoft.copilot.eclipse.terminal.api com.microsoft.copilot.eclipse.ui.terminal - com.microsoft.copilot.eclipse.ui.terminal.tm com.microsoft.copilot.eclipse.core com.microsoft.copilot.eclipse.ui @@ -96,7 +95,7 @@ ${tycho-version} - ../base.target + ../target-platforms/2025-12.target JavaSE-21 diff --git a/target-platforms/2025-12.target b/target-platforms/2025-12.target new file mode 100644 index 000000000..d5ba85bde --- /dev/null +++ b/target-platforms/2025-12.target @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/target-terminal.target b/target-terminal.target deleted file mode 100644 index ad2e7c962..000000000 --- a/target-terminal.target +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/target-tm-terminal.target b/target-tm-terminal.target deleted file mode 100644 index ff989f093..000000000 --- a/target-tm-terminal.target +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file