diff --git a/.github/workflows/build-terminal.yml b/.github/workflows/build-terminal.yml
index a9273e5..f58de8f 100644
--- a/.github/workflows/build-terminal.yml
+++ b/.github/workflows/build-terminal.yml
@@ -155,13 +155,32 @@ jobs:
dotnet-version: 10.0.x
- name: Restore
- run: dotnet restore Devolutions.Terminal.slnx -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ run: dotnet restore Devolutions.Terminal.slnx -p:Configuration=Release -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
- name: Build
- run: dotnet build Devolutions.Terminal.slnx -c Release --no-restore -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ run: dotnet build Devolutions.Terminal.slnx -c Release --no-restore -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
- name: Test
- run: dotnet test Devolutions.Terminal.slnx -c Release --no-build -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ # Engine tests resolve the separately installed runtime; it is not a DT package payload.
+ run: pwsh -NoLogo -NoProfile -File scripts/Install-IsebergTestPowerShell.ps1
+
+ - name: Run tests
+ timeout-minutes: 60
+ run: >-
+ dotnet test Devolutions.Terminal.slnx -c Release --no-build -m:1
+ -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ --logger "console;verbosity=normal" --logger trx
+ --results-directory artifacts/test-results/windows
+ --blame-hang --blame-hang-timeout 5min --blame-hang-dump-type none
+
+ - name: Upload Windows test diagnostics
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: windows-test-diagnostics
+ path: artifacts/test-results/windows
+ if-no-files-found: ignore
+ retention-days: 7
- name: Test macOS legal notice layout
run: pwsh -NoLogo -NoProfile -File scripts/Test-MacOsLegalNotices.ps1
@@ -212,7 +231,7 @@ jobs:
if-no-files-found: error
native-aot:
- name: NativeAOT ${{ matrix.rid }}
+ name: NativeAOT desktop ${{ matrix.rid }}
runs-on: windows-latest
needs: release-metadata
strategy:
@@ -241,16 +260,28 @@ jobs:
with:
dotnet-version: 10.0.x
- - name: Publish
+ - name: Publish NativeAOT desktop
run: >
dotnet publish src/Devolutions.Terminal/Devolutions.Terminal.csproj
-c Release
-r ${{ matrix.rid }}
--self-contained
+ -p:EnablePowerShellIse=false
+ -p:PublishAot=true
-p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
-o artifacts/${{ matrix.rid }}
- - name: Upload native executable
+ - name: Check opt-in managed Iseberg desktop
+ run: >
+ dotnet publish src/Devolutions.Terminal/Devolutions.Terminal.csproj
+ -c Release
+ -r ${{ matrix.rid }}
+ --self-contained
+ -p:EnablePowerShellIse=true
+ -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ -o artifacts/iseberg-validation/${{ matrix.rid }}
+
+ - name: Upload NativeAOT desktop
uses: actions/upload-artifact@v4
with:
name: DevolutionsTerminal-${{ matrix.rid }}
@@ -282,10 +313,13 @@ jobs:
dotnet-version: 10.0.x
- name: Restore
- run: dotnet restore Devolutions.Terminal.slnx -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ run: dotnet restore Devolutions.Terminal.slnx -p:Configuration=Release -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
- name: Run managed tests
- run: dotnet test Devolutions.Terminal.slnx -c Release --no-restore -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ run: pwsh -NoLogo -NoProfile -File scripts/Install-IsebergTestPowerShell.ps1
+
+ - name: Test managed projects
+ run: dotnet test Devolutions.Terminal.slnx -c Release --no-restore -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
- name: Validate Linux scripts and metadata
run: bash scripts/Test-LinuxPackagingMetadata.sh
@@ -315,10 +349,13 @@ jobs:
dotnet-version: 10.0.x
- name: Restore
- run: dotnet restore Devolutions.Terminal.slnx -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ run: dotnet restore Devolutions.Terminal.slnx -p:Configuration=Release -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
- name: Run managed tests
- run: dotnet test Devolutions.Terminal.slnx -c Release --no-restore -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
+ run: pwsh -NoLogo -NoProfile -File scripts/Install-IsebergTestPowerShell.ps1
+
+ - name: Test managed projects
+ run: dotnet test Devolutions.Terminal.slnx -c Release --no-restore -p:EnablePowerShellIse=true -p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
- name: Validate macOS scripts and metadata
run: pwsh -NoLogo -NoProfile -File scripts/Test-MacOsPackagingMetadata.ps1
@@ -333,7 +370,7 @@ jobs:
run: pwsh -NoLogo -NoProfile -File scripts/Test-MacOsNuGetSigning.ps1
macos-native-aot:
- name: macOS NativeAOT ${{ matrix.rid }}
+ name: macOS NativeAOT desktop ${{ matrix.rid }}
runs-on: macos-26
needs:
- macos-managed
@@ -364,19 +401,21 @@ jobs:
with:
dotnet-version: 10.0.x
- - name: NativeAOT publish
+ - name: NativeAOT desktop publish
run: >
dotnet publish src/Devolutions.Terminal/Devolutions.Terminal.csproj
-c Release
-r ${{ matrix.rid }}
--self-contained true
+ -p:EnablePowerShellIse=false
+ -p:PublishAot=true
-p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}
-p:DebugSymbols=false
-p:DebugType=None
-p:NativeDebugSymbols=false
-o artifacts/publish/${{ matrix.rid }}
- - name: Upload macOS NativeAOT publish
+ - name: Upload macOS desktop publish
uses: actions/upload-artifact@v4
with:
name: DevolutionsTerminal-${{ matrix.rid }}
@@ -649,7 +688,7 @@ jobs:
throw "Runtime hash mismatch: expected ${{ matrix.runtime_sha256 }}, got $actualHash."
}
- - name: NativeAOT publish
+ - name: NativeAOT desktop publish
shell: pwsh
run: |
$publishArgs = @(
@@ -657,6 +696,8 @@ jobs:
"-c", "Release",
"-r", "${{ matrix.rid }}",
"--self-contained", "true",
+ "-p:EnablePowerShellIse=false",
+ "-p:PublishAot=true",
"-p:VersionPrefix=${{ needs.release-metadata.outputs.release_version }}",
"-p:DebugSymbols=false",
"-p:DebugType=None",
@@ -668,7 +709,7 @@ jobs:
}
dotnet publish @publishArgs
- - name: Upload Linux NativeAOT publish
+ - name: Upload Linux desktop publish
uses: actions/upload-artifact@v4
with:
name: DevolutionsTerminal-${{ matrix.rid }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8817cd5..05fbabe 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,14 +22,22 @@ as a tab on `/pty/{id}` (`ws` on this HTTP host, `wss` when the page is HTTPS).
The browser never supplies a command line, and the host does not send one back.
Elevated profiles are listed and refused.
-Warnings are errors. Prefer small, reviewable changes that keep NativeAOT publish green.
+Warnings are errors. Keep the default NativeAOT desktop publish green.
+Iseberg is disabled by default; its managed developer build and regression suite
+require `-p:EnablePowerShellIse=true`. See [Iseberg](docs/iseberg.md) for the
+installed-engine boundary.
-## NativeAOT
+## Desktop publish
```powershell
dotnet publish src/Devolutions.Terminal -c Release -r win-x64 --self-contained
```
+The default desktop and release packages use NativeAOT and exclude Iseberg.
+Add `-p:EnablePowerShellIse=true` only for an optional managed, untrimmed
+Iseberg developer build. Use the same flag for restore/build/test/run commands
+when working on Iseberg. The CLI remains NativeAOT in both variants.
+
Linux packages:
```bash
diff --git a/Devolutions.Terminal.slnx b/Devolutions.Terminal.slnx
index 502486a..1faefa3 100644
--- a/Devolutions.Terminal.slnx
+++ b/Devolutions.Terminal.slnx
@@ -16,6 +16,11 @@
+
+
+
+
+
diff --git a/Directory.Build.props b/Directory.Build.props
index aa65286..d020f39 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -18,6 +18,7 @@
false
true
direct
+ false
$(MSBuildThisFileDirectory)assets\icons\terminal.ico
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 2911b07..cb7b136 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -11,6 +11,8 @@
+
+
diff --git a/README.md b/README.md
index 99ecfd1..6e2835d 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,14 @@
# Devolutions Terminal
A cross-platform terminal emulator implemented in C# on **.NET 10**, published
-with **NativeAOT**, and rendered with **Avalonia 12** / Skia:
+as a self-contained **NativeAOT** desktop app, and rendered with **Avalonia 12** / Skia:
- **ConPTY** on Windows and a real **forkpty** transport on Linux and macOS
- Azure Cloud Shell for remote Azure sessions
- selectable built-in or **Ghostty** VT engine
- Windows Terminal-compatible `settings.json`, actions, keybindings, and `dt` CLI
+- optional source-integrated **Iseberg** PowerShell ISE profiles in managed
+ developer builds only (disabled in default NativeAOT builds and release packages)
This is the [Devolutions Terminal](https://github.com/Devolutions/devolutions-terminal)
source tree. Projects, namespaces, and the GUI host use `Devolutions.Terminal.*`.
@@ -29,23 +31,29 @@ Install [gsudo](https://gerardog.github.io/gsudo/) and ensure `gsudo.exe` is on
Elevation is only available for local Windows sessions; UAC approval is still
required, and cancelling it does not launch an unelevated shell.
-## NativeAOT publish
+## Desktop publish
```powershell
dotnet publish src/Devolutions.Terminal -c Release -r win-x64 --self-contained
```
-The native executable is written to
+The executable is written to
`src/Devolutions.Terminal/bin/Release/net10.0/win-x64/publish/Devolutions.Terminal.exe`.
-macOS NativeAOT app bundles (Darwin only):
+The default desktop and `dt` CLI are NativeAOT. Release packages exclude Iseberg.
+An explicitly opted-in `-p:EnablePowerShellIse=true` developer build uses a
+managed, untrimmed desktop and separately installed compatible PowerShell; see
+[docs/iseberg.md](docs/iseberg.md). Saved Iseberg profiles remain intact, but
+cannot launch in the default build.
+
+macOS app bundles (Darwin only):
```bash
pwsh scripts/Build-MacOsPackage.ps1 osx-arm64 2026.3.0 artifacts/packages
pwsh scripts/Test-MacOsPackage.ps1 osx-arm64 artifacts/packages/*.zip
```
-Linux x64 and ARM64 NativeAOT packages are built on Linux with:
+Linux x64 and ARM64 packages are built on Linux with:
```bash
scripts/Build-LinuxPackage.sh linux-x64 2026.3.0 artifacts/packages all
@@ -113,7 +121,8 @@ Devolutions.Terminal.Connection ConPTY + Linux PTY + Azure Cloud Shell + brows
Devolutions.Terminal.Settings Layered Windows Terminal-compatible JSON settings
Devolutions.Terminal.Control Avalonia TermControl renderer
Devolutions.Terminal.App Tabs, title bar, panes, actions, window behavior
-Devolutions.Terminal NativeAOT executable and composition root
+Devolutions.Terminal.Ise Imported Iseberg engine, editor and embedded workbench
+Devolutions.Terminal Desktop executable and composition root
Devolutions.Terminal.Browser Avalonia WebAssembly host (in-process dt-wasm shell)
Devolutions.Terminal.Browser.Host Loopback server for profile tabs and a real PTY
```
diff --git a/assets/profile-icons/iseberg.scale-100.png b/assets/profile-icons/iseberg.scale-100.png
new file mode 100644
index 0000000..ca923ff
Binary files /dev/null and b/assets/profile-icons/iseberg.scale-100.png differ
diff --git a/assets/profile-icons/iseberg.svg b/assets/profile-icons/iseberg.svg
new file mode 100644
index 0000000..1a5dd61
--- /dev/null
+++ b/assets/profile-icons/iseberg.svg
@@ -0,0 +1,12 @@
+
diff --git a/docs/iseberg-parity.md b/docs/iseberg-parity.md
new file mode 100644
index 0000000..f5c1b8e
--- /dev/null
+++ b/docs/iseberg-parity.md
@@ -0,0 +1,270 @@
+# Original Windows PowerShell ISE feature comparison
+
+DT's source-integrated Iseberg in an explicitly enabled managed developer build
+already covers the main edit/run/debug workflow. Default NativeAOT builds and
+release packages disable Iseberg; saved profile settings are preserved.
+The integration now matches additional portable ISE features, but this is **not a
+drop-in replacement for the original `$psISE` object model, WPF add-ons, or
+Windows PowerShell 5.1**. Several features exist in the imported workbench but
+are deliberately disabled by DT; exact interaction and advanced endpoint
+combinations still require comparison.
+
+This report compares the installed original ISE implementation, its documented
+contracts, and the actual DT integration, not the standalone Iseberg application.
+The initial audit identified the gaps below; subsequent licensed-source
+adaptations implemented the portable subset recorded in this report. See
+[integration and deployment](iseberg.md) for ownership and deployment details.
+
+## Scope, provenance, and evidence
+
+ILSpy CLI **11.1.0.9782** successfully exported the original managed launcher and
+four UI assemblies as local projects: **1,213 C# files and 44 XAML files**.
+The editor assembly contains substantial Visual Studio text infrastructure;
+these counts are not counts of user features. The decompiled projects were not
+built or imported into DT. The Windows PowerShell engine itself was not
+decompiled.
+
+| Original component | File version | C# files | XAML files | Responsibility |
+| --- | --- | --- | --- | --- |
+| `powershell_ise.exe` | 10.0.26100.8875 | 7 | 0 | STA launcher, argument parsing handoff, existing-instance file routing |
+| `Microsoft.PowerShell.GPowerShell` | 10.0.26100.8875 | 139 | 20 | ISE workbench, host, execution, debugging, object model, recovery |
+| `Microsoft.PowerShell.Editor` | 10.0.26100.7309 | 899 | 8 | Text model, WPF editing, classification, IntelliSense infrastructure |
+| `Microsoft.PowerShell.GraphicalHost` | 10.0.26100.1591 | 159 | 16 | Graphical command/help and related Windows UI |
+| `Microsoft.PowerShell.ISECommon` | 10.0.26100.1 | 9 | 0 | Shared ISE command-line and instance communication support |
+
+The launcher is under
+`C:\Windows\System32\WindowsPowerShell\v1.0`. The four DLLs are under
+`C:\Windows\Microsoft.NET\assembly\GAC_MSIL`, with assembly identity
+`3.0.0.0`, public key token `31bf3856ad364e35`.
+The GUI reference engine reports **Windows PowerShell 5.1.26100.9444**;
+assembly file versions are not the engine version. DT uses installed
+**PowerShell 7.6.6**, Avalonia **12.1.1**, and AvaloniaEdit **12.0.0**.
+
+Local evidence lives in ignored
+`artifacts\iseberg\original-ise-analysis`. Its `manifest.json` records exact
+input paths, sizes, SHA-256 digests, tool version, and output counts.
+Decompilation used `ilspycmd -p -o