Showing preview only (385K chars total). Download the full file or copy to clipboard to get everything.
Repository: eclipse-theia/theia-ide
Branch: master
Commit: c5ce2e7120a1
Files: 136
Total size: 351.1 KB
Directory structure:
gitextract_jxq8o1lq/
├── .eslintrc.js
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ ├── build-next-release.yml
│ ├── build-next.yml
│ ├── build.yml
│ ├── license-check-workflow.yml
│ ├── publish-builder-img.yml
│ └── publish-theia-ide-img.yml
├── .gitignore
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── theia.code-snippets
├── ADOPTER.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── NOTICE.md
├── PUBLISHING.md
├── README.md
├── TheiaIDE logo/
│ └── TheiaIDE.eps
├── applications/
│ ├── browser/
│ │ ├── package.json
│ │ ├── resources/
│ │ │ └── preload.html
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ ├── electron/
│ │ ├── .eslintrc.js
│ │ ├── electron-builder.yml
│ │ ├── entitlements.plist
│ │ ├── package.json
│ │ ├── resources/
│ │ │ ├── LICENSE
│ │ │ ├── icon.icns
│ │ │ ├── icons/
│ │ │ │ └── MacLauncherIcons/
│ │ │ │ ├── 512-512-2.icns
│ │ │ │ ├── Theia-16bp-alfa ignored.icns
│ │ │ │ ├── icns-1bit/
│ │ │ │ │ ├── 128-128.icns
│ │ │ │ │ ├── 16-16-1.icns
│ │ │ │ │ ├── 256-256.icns
│ │ │ │ │ ├── 32-32.icns
│ │ │ │ │ ├── 48-48.icns
│ │ │ │ │ └── 512-512-2 copy.icns
│ │ │ │ ├── icns-8bit/
│ │ │ │ │ ├── 128-128.icns
│ │ │ │ │ ├── 16-16.icns
│ │ │ │ │ ├── 256-256.icns
│ │ │ │ │ ├── 32-32.icns
│ │ │ │ │ ├── 48-48.icns
│ │ │ │ │ └── 512-512.icns
│ │ │ │ ├── icon.icns
│ │ │ │ └── icon.icon/
│ │ │ │ └── icon.json
│ │ │ └── preload.html
│ │ ├── scripts/
│ │ │ ├── after-pack.js
│ │ │ ├── appimage-helpers.js
│ │ │ ├── generate-app-update-yml.js
│ │ │ ├── notarize.sh
│ │ │ ├── sign-directory-windows.ts
│ │ │ ├── sign-directory.ts
│ │ │ ├── sign-utils.ts
│ │ │ ├── sign.sh
│ │ │ ├── theia-electron-main.js
│ │ │ ├── update-blockmap.ts
│ │ │ └── update-checksum.ts
│ │ ├── test/
│ │ │ ├── app.spec.js
│ │ │ └── workspace/
│ │ │ └── README.md
│ │ ├── tsconfig.eslint.json
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ └── electron-next/
│ ├── .eslintrc.js
│ ├── electron-builder.yml
│ ├── package.json
│ ├── resources/
│ │ ├── LICENSE
│ │ └── preload.html
│ ├── scripts/
│ │ ├── after-pack.js
│ │ ├── appimage-helpers.js
│ │ └── theia-electron-main.js
│ ├── test/
│ │ └── workspace/
│ │ └── README.md
│ ├── tsconfig.eslint.json
│ ├── tsconfig.json
│ └── webpack.config.js
├── browser.Dockerfile
├── cleanup/
│ └── Jenkinsfile
├── configs/
│ ├── base.eslintrc.json
│ ├── base.tsconfig.json
│ ├── build.eslintrc.json
│ ├── errors.eslintrc.json
│ ├── license-check-config.json
│ ├── tsconfig.eslint.json
│ ├── warnings.eslintrc.json
│ └── xss.eslintrc.json
├── docs/
│ └── developing-with-local-theia.md
├── lerna.json
├── next/
│ ├── Jenkinsfile
│ └── NEXT_INTEGRATION_BUILD.md
├── package.json
├── patches/
│ └── @theia+terminal+1.72.0-next.20.patch
├── releng/
│ ├── preview/
│ │ ├── Jenkinsfile.build
│ │ ├── Jenkinsfile.sign
│ │ └── Jenkinsfile.upload
│ └── promote/
│ └── Jenkinsfile
├── scripts/
│ ├── build-with-local-theia.js
│ ├── generate-next-icons.js
│ ├── make-files-writeable.ts
│ └── update-theia-version.ts
├── theia-extensions/
│ ├── launcher/
│ │ ├── .eslintrc.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── browser/
│ │ │ │ ├── create-launcher-contribution.ts
│ │ │ │ ├── create-launcher-frontend-module.ts
│ │ │ │ ├── desktopfile-service.ts
│ │ │ │ └── launcher-service.ts
│ │ │ └── node/
│ │ │ ├── desktopfile-endpoint.ts
│ │ │ ├── launcher-backend-module.ts
│ │ │ ├── launcher-endpoint.ts
│ │ │ └── launcher-util.ts
│ │ └── tsconfig.json
│ ├── product/
│ │ ├── .eslintrc.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── browser/
│ │ │ │ ├── branding-util.tsx
│ │ │ │ ├── style/
│ │ │ │ │ └── index.css
│ │ │ │ ├── theia-ide-about-dialog.tsx
│ │ │ │ ├── theia-ide-config.ts
│ │ │ │ ├── theia-ide-contribution.tsx
│ │ │ │ ├── theia-ide-frontend-module.ts
│ │ │ │ └── theia-ide-getting-started-widget.tsx
│ │ │ └── electron-main/
│ │ │ ├── icon-contribution.ts
│ │ │ └── theia-ide-main-module.ts
│ │ └── tsconfig.json
│ └── updater/
│ ├── .eslintrc.js
│ ├── package.json
│ ├── src/
│ │ ├── common/
│ │ │ └── updater/
│ │ │ └── theia-updater.ts
│ │ ├── electron-browser/
│ │ │ ├── theia-updater-frontend-module.ts
│ │ │ └── updater/
│ │ │ ├── theia-updater-frontend-contribution.ts
│ │ │ └── theia-updater-preferences.ts
│ │ └── electron-main/
│ │ └── update/
│ │ ├── theia-updater-impl.ts
│ │ └── theia-updater-main-module.ts
│ └── tsconfig.json
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.js
================================================
/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
extends: [
'./configs/base.eslintrc.json',
'./configs/warnings.eslintrc.json',
'./configs/errors.eslintrc.json',
'./configs/xss.eslintrc.json'
],
ignorePatterns: [
'**/{node_modules,lib}',
'plugins'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./configs/tsconfig.eslint.json', './theia-extensions/*/tsconfig.json', 'applications/electron/tsconfig.eslint.json']
}
};
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug Report
about: Create a report to help us improve
---
<!-- Please provide a detailed description of the bug. -->
### Bug Description:
<!-- Please provide clear steps to reproduce the bug. -->
### Steps to Reproduce:
1.
2.
3.
<!-- Please provide any additional information available. -->
<!-- Additional information can be in the form of logs, screenshots, screencasts. -->
### Additional Information
- Operating System:
- Theia Version:
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Question
url: https://github.com/eclipse-theia/theia/discussions
about: Please ask questions here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature Request
about: Propose an idea for the project
---
<!-- Please fill out the following content for a feature request. -->
<!-- Please provide a clear description of the feature and any relevant information. -->
### Feature Description:
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
Thank you for your Pull Request. Please provide a description and review
the requirements below.
Contributors guide: https://github.com/theia-ide/theia/blob/master/CONTRIBUTING.md
-->
#### What it does
<!-- Include relevant issues and describe how they are addressed. -->
#### How to test
<!-- Explain how a reviewer can reproduce a bug, test new functionality or verify performance improvements. -->
#### Review checklist
- [ ] as an author, I have thoroughly tested my changes and carefully followed [the review guidelines](https://github.com/theia-ide/theia/blob/master/doc/pull-requests.md#requesting-a-review)
#### Reminder for reviewers
- as a reviewer, I agree to behave in accordance with [the review guidelines](https://github.com/theia-ide/theia/blob/master/doc/pull-requests.md#reviewing)
================================================
FILE: .github/workflows/build-next-release.yml
================================================
name: Build Theia IDE Next Release (Linux)
on:
workflow_dispatch:
schedule:
- cron: "0 2 * * 1-5" # Runs every weekday at 2am UTC
jobs:
build:
name: Build Next Release (Linux only)
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Use Node.js 24
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 24.x
registry-url: "https://registry.npmjs.org"
- name: Use Python 3.13
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Export build variables
shell: bash
run: |
THEIA_VERSION=next
echo "THEIA_VERSION=${THEIA_VERSION}" >> $GITHUB_ENV
yarn version --minor --no-git-tag-version
IDE_VERSION=$(jq -r .version package.json)
echo "THEIA_IDE_VERSION=${IDE_VERSION}-next-$(date +%Y-%m-%d)" >> $GITHUB_ENV
- name: Build next package
shell: bash
run: |
yarn --skip-integrity-check --network-timeout 100000
yarn version --new-version $THEIA_IDE_VERSION --no-git-tag-version
yarn lerna version $THEIA_IDE_VERSION --no-push --no-git-tag-version --yes
yarn update:theia $THEIA_VERSION && yarn update:theia:children $THEIA_VERSION
yarn --skip-integrity-check --network-timeout 100000
yarn build:extensions
yarn build:applications:next
yarn download:plugins
yarn package:applications:next
env:
NODE_OPTIONS: --max_old_space_size=4096
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Test (Linux)
run: xvfb-run -a yarn --cwd applications/electron-next test
- name: Upload Linux Dist Files
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: theia-ide-next-linux
path: |
applications/electron-next/dist/TheiaIDENext.AppImage
retention-days: 7
- name: Publish to rolling next release
shell: bash
run: |
# Delete existing next release if present
gh release delete next --yes --cleanup-tag 2>/dev/null || true
# Create a new pre-release with the next tag
gh release create next \
--title "Next Build - Ubuntu AppImage (${{ env.THEIA_IDE_VERSION }})" \
--notes "Automated next build of the Ubuntu AppImage from \`master\` ($(date -u '+%Y-%m-%d %H:%M UTC'))." \
--prerelease \
--target ${{ github.sha }} \
applications/electron-next/dist/TheiaIDENext.AppImage \
applications/electron-next/dist/latest-linux.yml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/build-next.yml
================================================
name: Build Theia IDE next version
on:
workflow_dispatch:
schedule:
- cron: "0 3 * * 1" # Runs every monday at 3am
jobs:
build:
name: Build ${{ matrix.os }} next
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-15, macos-15-intel, windows-2022] # macos-15-intel is for x64, macOS-15 is for arm64
runs-on: ${{ matrix.os }}
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # To fetch all history for all branches and tags. (Will be required for caching with lerna: https://github.com/markuplint/markuplint/pull/111)
- name: Use Node.js 24
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 24.x
registry-url: "https://registry.npmjs.org"
- name: Use Python 3.11
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Export build variables
shell: bash
run: |
THEIA_VERSION=next
echo "THEIA_VERSION=${THEIA_VERSION}" >> $GITHUB_ENV
yarn version --minor --no-git-tag-version
echo "THEIA_IDE_VERSION=$(jq -r .version package.json)-${THEIA_VERSION}-$(date +%d-%m-%y)" >> $GITHUB_ENV
- name: Update electron-builder.yml for macos-15
if: matrix.os == 'macos-15'
run: |
sed -i '' 's|https://download.eclipse.org/theia/ide/latest/macos|https://download.eclipse.org/theia/ide/latest/macos-arm|g' applications/electron/electron-builder.yml
- name: Build prod package
shell: bash
run: |
yarn --skip-integrity-check --network-timeout 100000
yarn version --new-version $THEIA_IDE_VERSION --no-git-tag-version
yarn lerna version $THEIA_IDE_VERSION --no-push --no-git-tag-version --yes
yarn update:theia $THEIA_VERSION && yarn update:theia:children $THEIA_VERSION
yarn --skip-integrity-check --network-timeout 100000
yarn build
yarn download:plugins
yarn package:applications
env:
NODE_OPTIONS: --max_old_space_size=4096
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9
- name: Rename AppImage with version
if: runner.os == 'Linux'
run: |
mv applications/electron/dist/TheiaIDE.AppImage applications/electron/dist/TheiaIDE-$THEIA_IDE_VERSION.AppImage
- name: Upload Linux Dist Files
if: runner.os == 'Linux'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: theia-ide-next-linux
path: |
applications/electron/dist/TheiaIDE-${{ env.THEIA_IDE_VERSION }}.AppImage
retention-days: 7
- name: Upload Mac Dist Files
if: runner.os == 'macOS'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: ${{ matrix.os == 'macos-15-intel' && 'theia-ide-next-mac-x64' || matrix.os == 'macos-15' && 'theia-ide-next-mac-arm64'}}
path: applications/electron/dist/*.dmg
retention-days: 7
- name: Upload Windows Dist Files
if: runner.os == 'Windows'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: theia-ide-next-windows
path: applications/electron/dist/*.exe
retention-days: 7
================================================
FILE: .github/workflows/build.yml
================================================
name: Build, package and test
on:
push:
branches:
- master
paths-ignore:
- '**/*.md'
- 'TheiaIDE logo/**'
workflow_dispatch:
pull_request:
branches:
- master
paths-ignore:
- '**/*.md'
- 'TheiaIDE logo/**'
schedule:
- cron: "0 4 * * *" # Runs every day at 4am: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule
jobs:
build:
name: ${{ matrix.os }}, Node.js v${{ matrix.node }}
strategy:
fail-fast: false
matrix:
os: [windows-2022, ubuntu-22.04, macos-15, macos-15-intel] # macos-15-intel is for x64, macOS-15 is for arm64
node: ["24.x"]
runs-on: ${{ matrix.os }}
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # To fetch all history for all branches and tags. (Will be required for caching with lerna: https://github.com/markuplint/markuplint/pull/111)
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ matrix.node }}
registry-url: "https://registry.npmjs.org"
- name: Use Python 3.13
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Install dependencies
shell: bash
run: yarn --skip-integrity-check --network-timeout 100000
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Lint
shell: bash
run: yarn lint
- name: Build dev package (Windows, Linux)
if: (runner.os == 'Windows' || runner.os == 'Linux') && github.event_name == 'pull_request'
shell: bash
run: |
yarn build:dev
yarn download:plugins
yarn package:applications:preview
env:
NODE_OPTIONS: --max_old_space_size=4096
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9
- name: Build prod package (Windows, Linux)
if: (runner.os == 'Windows' || runner.os == 'Linux') && github.event_name != 'pull_request'
shell: bash
run: |
yarn build
yarn download:plugins
yarn package:applications
env:
NODE_OPTIONS: --max_old_space_size=4096
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9
- name: Update electron-builder.yml for macos-15
if: matrix.os == 'macos-15'
run: |
sed -i '' 's|https://download.eclipse.org/theia/ide/latest/macos|https://download.eclipse.org/theia/ide/latest/macos-arm|g' applications/electron/electron-builder.yml
- name: Build prod package (Mac)
if: runner.os == 'macOS'
shell: bash
run: |
yarn build
yarn download:plugins
yarn package:applications
env:
NODE_OPTIONS: --max_old_space_size=4096
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9
- name: Upload Mac Dist Files
if: runner.os == 'macOS'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: ${{ matrix.os == 'macos-15-intel' && 'mac-x64' || matrix.os == 'macos-15' && 'mac-arm64'}}
path: |
applications/electron/dist/**
!applications/electron/dist/mac/**
!applications/electron/dist/mac-arm64/**
retention-days: 1
- name: Upload Windows Dist Files
if: runner.os == 'Windows' && github.event_name != 'pull_request'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: windows
path: |
applications/electron/dist/**
retention-days: 1
- name: Upload Linux Dist Files
if: runner.os == 'Linux' && github.event_name != 'pull_request'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: linux
path: |
applications/electron/dist/**
retention-days: 1
- name: Test (Linux)
if: runner.os == 'Linux'
run: |
xvfb-run -a yarn electron test
- name: Test (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
yarn electron test
- name: Test (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
yarn electron test
- name: Upload test screenshots
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: test-screenshots-${{ matrix.os }}
path: applications/electron/test-screenshots/
if-no-files-found: ignore
retention-days: 5
================================================
FILE: .github/workflows/license-check-workflow.yml
================================================
name: 3PP License Check
on:
push:
branches:
- master
paths:
- 'yarn.lock'
workflow_dispatch:
pull_request:
branches:
- master
paths:
- 'yarn.lock'
schedule:
- cron: '0 4 * * *' # Runs every day at 4am: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule
jobs:
License-check:
name: 3PP License Check using dash-licenses
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
node: [24]
java: [17]
runs-on: ${{ matrix.os }}
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 2
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ matrix.node }}
- name: Use Java ${{ matrix.java }}
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'adopt'
java-version: ${{ matrix.java }}
- name: Run daily dash-licenses check (non-review mode)
if: ${{ github.event_name == 'schedule' }}
shell: bash
run: |
yarn --frozen-lockfile --ignore-scripts
# Workaround: pre-download dash-licenses JAR (see comments in step below)
DASH_JAR="node_modules/@eclipse-dash/nodejs-wrapper/download/dash-licenses.jar"
mkdir -p "$(dirname "$DASH_JAR")"
SNAP_BASE="https://repo.eclipse.org/repository/dash-maven2-snapshots/org/eclipse/dash/org.eclipse.dash.licenses/1.1.1-SNAPSHOT"
SNAP_JAR=$(curl -s "$SNAP_BASE/maven-metadata.xml" | grep -oP '(?<=<value>)1\.1\.1-[^<]+' | tail -1)
curl -L "$SNAP_BASE/org.eclipse.dash.licenses-$SNAP_JAR.jar" -o "$DASH_JAR"
yarn license:check
- name: Run dash-licenses check in review mode
if: ${{ github.event_name != 'schedule' }}
shell: bash
run: |
yarn --frozen-lockfile --ignore-scripts
# Workaround: pre-download dash-licenses JAR since the @eclipse-dash/nodejs-wrapper
# uses a broken Nexus 2 URL after the repo.eclipse.org upgrade to Nexus 3.
# We use 1.1.1-SNAPSHOT because 1.0.2 and 1.1.0 incorrectly flag internal
# workspace packages (link:true with no version) as restricted.
# See: https://github.com/eclipse-dash/nodejs-wrapper/issues/7
# See: https://github.com/eclipse-dash/dash-licenses/issues/534
# TODO: remove this workaround once the nodejs-wrapper is updated (GH-17168)
DASH_JAR="node_modules/@eclipse-dash/nodejs-wrapper/download/dash-licenses.jar"
mkdir -p "$(dirname "$DASH_JAR")"
SNAP_BASE="https://repo.eclipse.org/repository/dash-maven2-snapshots/org/eclipse/dash/org.eclipse.dash.licenses/1.1.1-SNAPSHOT"
SNAP_JAR=$(curl -s "$SNAP_BASE/maven-metadata.xml" | grep -oP '(?<=<value>)1\.1\.1-[^<]+' | tail -1)
curl -L "$SNAP_BASE/org.eclipse.dash.licenses-$SNAP_JAR.jar" -o "$DASH_JAR"
yarn license:check:review
env:
DASH_TOKEN: ${{ secrets.DASH_LICENSES_PAT }}
================================================
FILE: .github/workflows/publish-builder-img.yml
================================================
name: Publish builder image
on:
schedule:
- cron: "0 0 1 * *" # runs 1st day of every month
workflow_dispatch:
jobs:
build:
name: Build and push builder image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Login to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # 4.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
push: true
tags: eclipsetheia/theia-blueprint:builder
================================================
FILE: .github/workflows/publish-theia-ide-img.yml
================================================
name: Publish Theia IDE Docker Image
on:
workflow_dispatch:
inputs:
tag:
description: The image's tag
required: true
default: next
jobs:
build:
name: Build and push Theia IDE image to Github Packages
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
install: true
driver: docker-container
driver-opts: |
image=moby/buildkit:latest
network=host
- name: Login to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # 4.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to the Github Container registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # 4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: List docker buildx available platforms
shell: bash
run: |
docker buildx inspect --bootstrap
- name: Build and push Docker image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
file: browser.Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}/theia-ide:${{ github.event.inputs.tag }}
ghcr.io/${{ github.repository }}/theia-ide:latest
platforms: linux/amd64,linux/arm64
================================================
FILE: .gitignore
================================================
.DS_Store
**/node_modules
**/.browser_modules
**/dist
**/lib
**/src-gen
**/gen-webpack.config.js
**/gen-webpack.node.config.js
**/plugins
**/tsconfig.tsbuildinfo
*.log
license-check-summary.txt*
.theia-ide/chatSessions
.prompts
**/test-screenshots
================================================
FILE: .vscode/launch.json
================================================
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach by Process ID",
"processId": "${command:PickProcess}"
},
{
"type": "node",
"request": "launch",
"name": "Launch with Node.js",
"program": "${file}"
},
{
"type": "node",
"request": "launch",
"name": "Launch Electron Backend",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"cwd": "${workspaceFolder}/applications/electron",
"protocol": "inspector",
"args": [
"scripts/theia-electron-main.js",
"--log-level=debug",
"--hostname=localhost",
"--no-cluster",
"--app-project-path=${workspaceFolder}/applications/electron",
"--remote-debugging-port=9222",
"--no-app-auto-install",
"--plugins=local-dir:../../plugins"
],
"env": {
"NODE_ENV": "development"
},
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/applications/electron/src-gen/**/*.js",
"${workspaceFolder}/applications/electron/lib/**/*.js",
"${workspaceFolder}/theia-extensions/*/lib/**/*.js",
"${workspaceFolder}/node_modules/@theia/*/lib/**/*.js"
],
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outputCapture": "std"
},
{
"type": "node",
"request": "launch",
"name": "Launch Browser Backend",
"program": "${workspaceFolder}/applications/browser/lib/backend/main.js",
"cwd": "${workspaceFolder}/applications/browser",
"args": [
"--hostname=0.0.0.0",
"--port=3000",
"--no-cluster",
"--app-project-path=${workspaceFolder}/applications/browser",
"--plugins=local-dir:../../plugins",
"--log-level=debug"
],
"env": {
"NODE_ENV": "development"
},
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/applications/browser/src-gen/**/*.js",
"${workspaceFolder}/applications/browser/lib/**/*.js",
"${workspaceFolder}/theia-extensions/**/lib/**/*.js",
"${workspaceFolder}/node_modules/@theia/*/lib/**/*.js"
],
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outputCapture": "std"
},
{
"type": "node",
"request": "attach",
"name": "Attach to Plugin Host",
"port": 9339,
"timeout": 60000,
"stopOnEntry": false,
"smartStep": true,
"sourceMaps": true,
"internalConsoleOptions": "openOnSessionStart",
"outFiles": [
"${workspaceFolder}/plugins/**/*.js"
]
},
{
"type": "node",
"request": "launch",
"name": "Launch Browser Backend (eclipse.jdt.ls)",
"program": "${workspaceFolder}/applications/browser/lib/backend/main.js",
"cwd": "${workspaceFolder}/applications/browser",
"args": [
"--hostname=0.0.0.0",
"--port=3000",
"--no-cluster",
"--root-dir=${workspaceFolder}/../eclipse.jdt.ls/org.eclipse.jdt.ls.core",
"--app-project-path=${workspaceFolder}/applications/browser",
"--plugins=local-dir:../../plugins",
"--log-level=debug",
"--no-app-auto-install"
],
"env": {
"NODE_ENV": "development"
},
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/applications/browser/src-gen/**/*.js",
"${workspaceFolder}/applications/browser/lib/**/*.js",
"${workspaceFolder}/theia-extensions/**/lib/**/*.js",
"${workspaceFolder}/node_modules/@theia/*/lib/**/*.js"
],
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outputCapture": "std"
},
{
"type": "node",
"request": "launch",
"protocol": "inspector",
"name": "Run Mocha Tests",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": [
"--no-timeouts",
"--colors",
"--opts",
"${workspaceFolder}/configs/mocha.opts",
"**/${fileBasenameNoExtension}.js"
],
"env": {
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
},
"sourceMaps": true,
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outputCapture": "std"
},
{
"name": "Launch Browser Frontend",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000/",
"webRoot": "${workspaceFolder}/applications/browser"
},
{
"type": "chrome",
"request": "attach",
"name": "Attach to Electron Frontend",
"port": 9222,
"webRoot": "${workspaceFolder}/applications/electron"
},
{
"name": "Launch VS Code Tests",
"type": "node",
"request": "launch",
"args": [
"${workspaceFolder}/applications/browser/lib/backend/main.js",
"${workspaceFolder}/plugins/vscode-api-tests/testWorkspace",
"--port",
"3030",
"--hostname",
"0.0.0.0",
"--extensionTestsPath=${workspaceFolder}/plugins/vscode-api-tests/out/singlefolder-tests",
"--hosted-plugin-inspect=9339"
],
"env": {
"THEIA_DEFAULT_PLUGINS": "local-dir:${workspaceFolder}/plugins"
},
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/../.js"
]
}
],
"compounds": [
{
"name": "Launch Electron Backend & Frontend",
"configurations": [
"Launch Electron Backend",
"Attach to Plugin Host",
"Attach to Electron Frontend"
],
"stopAll": true
},
{
"name": "Launch Browser Backend & Frontend",
"configurations": [
"Launch Browser Backend",
"Attach to Plugin Host",
"Launch Browser Frontend"
],
"stopAll": true
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"[markdown]": {
"editor.defaultFormatter": "davidanson.vscode-markdownlint"
}
}
================================================
FILE: .vscode/theia.code-snippets
================================================
{
"Copyright-JS/JSX/TS/TSX/CSS": {
"prefix": [
"header",
"copyright"
],
"body": "/********************************************************************************\n * Copyright (C) $CURRENT_YEAR ${YourCompany} and others.\n *\n * This program and the accompanying materials are made available under the\n * terms of the MIT License, which is available in the project root.\n *\n * SPDX-License-Identifier: MIT\n ********************************************************************************/\n\n$0",
"description": "Adds the copyright...",
"scope": "javascript,javascriptreact,typescript,typescriptreact,css"
}
}
================================================
FILE: ADOPTER.md
================================================
# Adopter Guide
This repository serves as a template for building desktop products on the [Eclipse Theia platform](https://theia-ide.org). This guide documents packaging considerations when building your own Theia based applications.
## Electron Packaging and Asar
Electron applications may use [asar archives](https://github.com/electron/asar) to package application source files into a single read only archive. This improves startup performance and avoids path length issues on Windows.
In this repository, asar packaging is enabled via `asar: true` in `applications/electron/electron-builder.yml`. When the application is packaged with `electron-builder`, the contents of the app directory are bundled into an `app.asar` file inside the packaged application's `resources/` folder.
Code that uses `__dirname` to access files, or executes scripts from the filesystem, will fail because asar archives are not real directories. At runtime, `__dirname` resolves to a path inside `app.asar`, but Node's `fs` module and the OS cannot access files inside the archive as regular filesystem entries.
Two categories of files are typically affected:
1. **Native binaries**, `.node` files or prebuilt binaries
2. **Scripts and resources** that must be accessible on the real filesystem
### Mitigation Strategies
#### 1. asarUnpack (electron-builder.yml)
Files matching `asarUnpack` glob patterns are automatically extracted alongside the asar archive during packaging. At runtime, these files live under `app.asar.unpacked/` instead of `app.asar/`.
For example:
```yaml
asarUnpack:
- "**/lib/backend/native/**"
- "**/lib/backend/shell-integrations/**"
- "**/lib/build/Release/**"
- "**/lib/prebuilds/**"
```
`asarUnpack` only extracts the files to the real filesystem. Code that resolves paths using `__dirname` will still get a path containing `app.asar`, so it must also handle the `.asar.unpacked` path segment for the files to be found.
#### 2. patch-package
When upstream code in `node_modules` needs modification, for example to adjust paths, [patch-package](https://github.com/ds300/patch-package) can apply source level patches after `yarn install`.
* Patches live in the `patches` directory at the repository root
* Patches are applied automatically via the `postinstall` script in `package.json`
#### 3. Webpack Post Processing
Another option is to adjust the bundled code in Webpack.
As an example, the `PatchRipgrepPlugin` in `applications/electron/webpack.config.js` patches the bundled `main.js` after webpack emit to rewrite ripgrep's path resolution from `.asar` to `.asar.unpacked`:
```js
class PatchRipgrepPlugin {
apply(compiler) {
compiler.hooks.afterEmit.tapAsync('PatchRipgrepPlugin', (compilation, callback) => {
// Reads main.js, finds the ripgrep path assignment, and rewrites
// .asar + path.sep → .asar.unpacked + path.sep
// ...
});
}
}
```
================================================
FILE: CODE_OF_CONDUCT.md
================================================
<div id="theia-logo" align="left">
<br />
<img src="https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/EF_GRY-OR_svg.svg?sanitize=true" alt="Eclipse Logo" width="300"/>
</div>
# Community Code of Conduct
Version 1.1
October 21, 2019
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at codeofconduct@eclipse.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
<div id="theia-logo" align="left">
<br />
<img src="https://www.eclipse.org/images/Eclipse_Code_of_Conduct.png" alt="Eclipse Logo" width="150"/>
</div>
----
Note: Please see [here](https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php) for the latest version of this document, hosted at the Eclipse Foundation
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Eclipse Theia
Theia is a young open-source project with a modular architecture. One of the
goals is to make sure that we can customize and enhance any Theia application
through extensions. So while the main Theia repository contains some common
functionality for IDE-like applications, like a file system or a navigator
view, most functionality doesn't necessarily need to be put into the core
repository but can be developed separately.
## How Can I Contribute?
In the following some of the typical ways of contribution are described.
### Asking Questions
It's totally fine to ask questions by opening an issue in the Theia GitHub
repository. We will close it once it's answered and tag it with the 'question'
label. Please check if the question has been asked before there or on [Stack
Overflow](https://stackoverflow.com).
### Reporting Bugs
If you have found a bug, you should first check if it has already been filed
and maybe even fixed. If you find an existing unresolved issue, please add your
case. If you could not find an existing bug report, please file a new one. In
any case, please add all information you can share and that will help to
reproduce and solve the problem.
### Reporting Feature Requests
You may want to see a feature or have an idea. You can file a request and we
can discuss it. If such a feature request already exists, please add a comment
or some other form of feedback to indicate you are interested too. Also in this
case any concrete use case scenario is appreciated to understand the motivation
behind it.
### Pull Requests
Before you get started investing significant time in something you want to get
merged and maintained as part of Theia, you should talk with the team through
an issue. Simply choose the issue you would want to work on, and tell everyone
that you are willing to do so and how you would approach it. The team will be
happy to guide you and give feedback.
We follow the contributing and reviewing pull request guidelines described
[here](https://github.com/eclipse-theia/theia/blob/master/doc/pull-requests.md).
## Coding Guidelines
We follow the coding guidelines described
[here](https://github.com/eclipse-theia/theia/wiki/Coding-Guidelines).
## Eclipse Contributor Agreement
Before your contribution can be accepted by the project team contributors must
electronically sign the Eclipse Contributor Agreement (ECA).
* https://www.eclipse.org/legal/ECA.php
Commits that are provided by non-committers must have a Signed-off-by field in
the footer indicating that the author is aware of the terms by which the
contribution has been provided to the project. The non-committer must
additionally have an Eclipse Foundation account and must have a signed Eclipse
Contributor Agreement (ECA) on file.
For more information, please see the Eclipse Committer Handbook:
https://www.eclipse.org/projects/handbook/#resources-commit
## Sign your work
The sign-off is a simple line at the end of the explanation for the patch. Your
signature certifies that you wrote the patch or otherwise have the right to
pass it on as an open-source patch. The rules are pretty simple: if you can
certify the below (from
[developercertificate.org](https://developercertificate.org/)):
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
Then you just add a line to every git commit message:
Signed-off-by: Joe Smith <joe.smith@email.com>
Use your real name (sorry, no pseudonyms or anonymous contributions.)
If you set your `user.name` and `user.email` git configs, you can sign your
commit automatically with `git commit -s`.
================================================
FILE: Dockerfile
================================================
# See the associated GitHub workflow, that builds and publishes
# this docker image to Docker Hub:
# .github/workflows/publish-builder-img.yml
# It can be triggered manually from the GitHub project page.
# We want to support as many Debian versions as possible.
# Therefore, use the oldest Debian release that still provides the desired Node.js version.
FROM node:24-bookworm
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
libxkbfile-dev libsecret-1-dev python3 \
wine wine32 wine64 \
&& rm -rf /var/lib/apt/lists/*
# UID-agnostic wine tuning. WINEPREFIX is intentionally NOT set here; callers
# must provide a writable path owned by the runtime user.
ENV WINEDLLOVERRIDES="mscoree=;mshtml=" \
WINEDEBUG=-all
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Eclipse Theia IDE Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: NOTICE.md
================================================
# Notices for Eclipse Theia
This content is produced and maintained by the Eclipse Theia project.
* Project home: https://projects.eclipse.org/projects/ecd.theia
## Trademarks
Eclipse Theia is a trademark of the Eclipse Foundation.
## Copyright
All content is the property of the respective authors or their employers. For
more information regarding authorship of content, please consult the listed
source code repository logs.
## Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the MIT License which is available at https://opensource.org/license/mit/.
SPDX-License-Identifier: MIT
## Source Code
The project maintains the following source code repositories:
* https://github.com/eclipse/theia-generator-plugin
* https://github.com/eclipse/theia-yeoman-plugin
* https://github.com/eclipse/theia-plugin-packager
* https://github.com/eclipse/theia-cpp-extension
* https://github.com/eclipse/theia-python-extension
* https://github.com/eclipse/theia-java-extension
## Third-party Content
This project leverages the following third party content.
chalk (2.4.1)
* License: MIT
* Project: https://github.com/chalk/chalk
* Source: https://github.com/chalk/chalk
code copied from project cortex-debug (0.1.21)
* License: MIT
Code copied from project Microsoft/vscode (1.31.0)
* License: MIT
Code copied from project Microsoft/vscode (1.32.3)
* License: MIT
* Project: https://code.visualstudio.com/
* Source: https://github.com/Microsoft/vscode
Code copied from project Microsoft/vscode (1.33.1)
* License: MIT
code copied from project microsoft/vscode (1.33.1)
* License: MIT
Code copied from VSCode (n/a)
* License: MIT
Copied code from project VSCode (n/a)
* License: MIT
CSS copied from VS Code (n/a)
* License: MIT
dugite (1.52.0)
* License: MIT
Electron (3.1.7)
* License: BSD-2-Clause AND BSD-3-Clause AND (MIT OR GPL-2.0) AND Apache-2.0
AND (BSD-2-Clause OR MIT OR Apache-2.0) AND ISC AND MIT AND X11 AND
BSD-2-Clause-FreeBSD AND Public-Domain AND Unlicense AND MPL-2.0 AND
(BSD-3-Clause OR MPL-2.0) AND CC-BY-3.0 AND (AFL-2.0
* Project: https://electronjs.org/
* Source: https://github.com/electron/electron
electron@2.0.14 (2.0.14)
* License: MIT AND BSD-2-Clause AND Apache-2.0 AND (AFL-2.1 OR BSD-3-Clause)
AND BSD-3-Clause AND ISC AND X11 AND Public-Domain AND (GPL-2.0 OR MIT) AND
Unlicense AND IJG AND ICU AND UNICODE-TOU AND NTP AND (MIT OR BSD-3-Clause)
AND Libpng AND MPL-2.0 AND LGPL-2.1+
* Project: https://github.com/electron/electron
* Source: https://github.com/electron/electron/releases/tag/v2.0.14
getmac (1.4.6)
* License: MIT
* Project: https://github.com/bevry/getmac
* Source: https://github.com/bevry/getmac
GH-3397: Implemented the HTTP-based authentication for Git in Electron. (n/a)
* License: MIT
glob promise (3.4.0)
* License: ISC
* Project: https://github.com/ahmadnassri/glob-promise
* Source: https://github.com/ahmadnassri/glob-promise
Icon configure-inverse.svg (n/a)
* License: MIT
* Project: https://github.com/Microsoft/vscode
* Source:
https://github.com/Microsoft/vscode/blob/master/src/vs/workbench/contrib/tasks/common/media/configure-inverse.svg#L1
libffmpeg (FFmpeg) Delivered with Electron (3.1.7)
* License: LGPL-2.1+
long.js (3.2.0)
* License: Apache-2.0
micromatch (3.1.10)
* License: MIT
* Project: https://github.com/micromatch/micromatch
* Source: https://github.com/micromatch/micromatch
monaco-typescript (2.3.0)
* License: MIT
* Project: https://github.com/Microsoft/monaco-typescript
* Source: https://github.com/Microsoft/monaco-typescript.git
native-keymap (1.2.5)
* License: Pending
* Project: https://github.com/Microsoft/node-native-keymap
* Source: https://github.com/Microsoft/node-native-keymap
node-oniguruma (n/a)
* License: BSD-2-Clause AND GPL-2.0 WITH Autoconf-exception-2.0 AND
GPL-2.0-or-later WITH libtool-exception AND X11 AND MIT AND Public-Domain
node.js dependencies for Theia (n/a)
* License: MIT AND BSD-3-Clause AND ISC AND Apache-2.0 AND BSD-2-Clause AND
Zlib AND X11 AND (BSD-3-Clause OR AFL-2.1) AND CC-By-4.0 AND CC-by-2.5-SA AND
CC0-1.0 AND (BSD-3-Clause OR MPL-2.0) AND Unlicense AND (MIT OR GPL-3.0) AND
(MIT OR GPL-2.0) AND (Apache-2.0 OR
ps-list (5.0.1)
* License: MIT
* Project: https://github.com/sindresorhus/ps-list
* Source: https://github.com/sindresorhus/ps-list
read-pkg (4.0.1)
* License: MIT
* Project: https://github.com/sindresorhus/read-pkg
* Source: https://github.com/sindresorhus/read-pkg
regular expressions and helper function copied from microsoft/vscode (1.33.1)
* License: MIT
requestretry (3.1.0)
* License: MIT
* Project: https://github.com/FGRibreau/node-request-retry
* Source: https://github.com/FGRibreau/node-request-retry
rimraf (2.6.2)
* License: ISC
textmate/tcl.tmbundle (n/a)
* License: LicenseRef-Php_Tmbundle
theia npm node (n/a)
* License: BSD-2-Clause OR (MIT OR Apache-2.0) AND (AFL-2.1 OR BSD-3-Clause)
AND Apache-2.0 AND Artistic-2.0 AND BSD-3-Clause AND (BSD-3-Clause OR MIT)
AND MPL-2.0 AND CC0-1.0 AND CC-BY-3.0 AND CC-BY-4.0 AND CC-BY-SA-2.5 AND
GPL-2.0 WITH Autoconf-ex
theia-cpp-extension npm node (n/a)
* License: BSD-2-Clause OR (MIT OR Apache-2.0) AND MIT AND BSD-3-Clause AND
Zlib AND (MIT OR GPL-3.0) AND OFL-1.1 AND Apache-2.0 AND CC0-1.0 AND
CC-BY-3.0 AND ISC AND MPL-2.0 AND License-Ref-Public-Domain AND BSL-1.0 AND
(AFL-2.1 OR BSD-3.0) AND Unlicense AND Artist
tslint (5.10.0)
* License: Apache-2.0 AND MIT
* Project: http://palantir.github.io/tslint/
* Source: https://github.com/palantir/tslint
typefox/monaco-language-client (0.5.0)
* License: MIT
typescript-formatter (7.2.2)
* License: MIT
* Project: https://github.com/vvakame/typescript-formatter
* Source: https://github.com/vvakame/typescript-formatter
VS Code (1.33.0)
* License: MIT
vscode (1.26.0)
* License: MIT AND LicenseRef-Php_Tmbundle
vscode (1.26.0)
* License: MIT
vscode (1.31.0)
* License: MIT
vscode-debugadapter-node (n/a)
* License: MIT
vscode-java (0.36.0)
* License: EPL-1.0
vscode-java (0.44.0)
* License: EPL-1.0
vscode-java-debug (0.15.0)
* License: MIT
when (3.7.8)
* License: MIT
* Project: https://github.com/cujojs/when
* Source: https://github.com/cujojs/when
wjordan/browser-path SHA6719d19077b1454bff8b802f9be79cb1b69ebe7e (n/a)
* License: MIT
xterm.js (3.9.1)
* License: MIT
* Project: https://xtermjs.org/
* Source: https://github.com/xtermjs/xterm.js
yargs (12.0.1)
* License: MIT
* Project: http://yargs.js.org/
* Source: https://github.com/yargs/yargs
yeoman environment (2.3.0)
* License: BSD-2-Clause AND BSD-3-Clause
* Project: https://github.com/yeoman/environment
* Source: https://github.com/yeoman/environment
yeoman generator (3.0.0)
* License: BSD-2-Clause AND BSD-3-Clause
* Project: http://yeoman.io
* Source: https://github.com/yeoman/generator
yeoman-generator (2.0)
* License: BSD-2-Clause
* Project: http://yeoman.io/
* Source: https://github.com/yeoman/generator
yosay (2.0.2)
* License: BSD-2-Clause
* Project: https://github.com/yeoman/yosay
* Source: https://github.com/yeoman/yosay
## Cryptography
Content may contain encryption software. The country in which you are currently
may have restrictions on the import, possession, and use, and/or re-export to
another country, of encryption software. BEFORE using any encryption software,
please check the country's laws, regulations and policies concerning the import,
possession, or use, and re-export of encryption software, to see if this is
permitted.
## Electron
NOTICE:
Please note Electron combines Chromium and Node.js into a single runtime.
While Electron, Chromium and Node.js are generally licensed under very
permissive MIT and BSD-3-Clause licenses, both Electron and Chromium distribute
FFmpeg. While FFmpeg is under the LGPL-2.1-or-later license it incorporates
several optional parts and optimizations that are covered by the
GPL-2.0-or-later. We understand both Electron and Chromium do not distribute
versions of FFmpeg with GPL content enabled; however, FFmpeg may be configured
enabled to work with proprietary codecs. It is our understanding these
proprietary codecs may be patented; and as a result, may be subject to
licensing fees.
We strongly recommend downstream consumers verify the type of FFmpeg support
configured and modify as required. More information on instructions to verify
can be found here
https://electronjs.org/docs/development/upgrading-chromium#verify-ffmpeg-support
================================================
FILE: PUBLISHING.md
================================================
# Publishing Guide for the Eclipse Theia IDE
This document provides a unified, structured guide for publishing a new version of the Theia IDE. It covers everything from updating package versions, preview testing, releasing, promoting to stable, and other post-release activities.
## Table of Contents
1. [Overview](#1-overview)
2. [Update Package Versions and Theia](#2-update-package-versions-and-theia)
- [2.1 Install build dependencies](#21-install-build-dependencies)
- [2.2 Update versions](#22-update-versions)
- [2.3 Check for mandatory code changes](#23-check-for-mandatory-code-changes)
- [2.4 Prepare Release PR](#24-prepare-release-pr)
- [2.5 Mac Artifacts](#25-mac-artifacts)
- [2.6 Merge Release PR & Trigger Jenkins Build](#26-merge-release-pr--trigger-jenkins-build)
3. [Preview, Testing, and Release Process](#3-preview-testing-and-release-process)
- [3.1 Confirm the new preview version is published](#31-confirm-the-new-preview-version-is-published-do-not-promote-as-stable-yet)
- [3.2 Announce Preview Test Phase](#32-announce-preview-test-phase)
- [3.3 Patch Releases](#33-patch-releases)
4. [Promote IDE from Preview to Stable Channel](#4-promote-ide-from-preview-to-stable-channel)
5. [Tag the Release Commit](#5-tag-the-release-commit)
6. [Publish Docker Image](#6-publish-docker-image)
7. [Snap Update](#7-snap-update)
8. [Upgrade Dependencies](#8-upgrade-dependencies)
## 1. Overview
<!-- release: both -->
Every commit to the master branch is automatically published as a preview version. Official updates require a version change.
This guide differentiates between two version numbers:
- **THEIA_VERSION**: (used variable: {{version}}) The version of Theia used in this release.
- **THEIA_IDE_VERSION**: (used variable: {{ideVersion}}) The Theia IDE release version. Depending on the context:
- If there was **no** Theia release, increment the patch version by 1 (e.g., 1.47.0 -> 1.47.1 or 1.47.100 -> 1.47.101).
- For a new Theia *minor* release (e.g., 1.48.0), use the same version as Theia.
- For a new Theia *patch* release (e.g., 1.48.1), use Theia's patch version multiplied by 100 (e.g., 1.48.100).
## 2. Update Package Versions and Theia
<!-- release: both -->
Follow these steps to update dependencies and package versions:
### 2.1. Install build dependencies
<!-- release: both -->
```sh
yarn
```
### 2.2. Update versions
<!-- release: both -->
1. Update the monorepo version to **THEIA_IDE_VERSION** (without creating a Git tag):
```sh
yarn version --no-git-tag-version --new-version {{ideVersion}}
```
2. Optional: If there is a new Theia release to consume, update Theia dependencies to **THEIA_VERSION** :
```sh
yarn update:theia {{version}} && yarn update:theia:children {{version}}
```
3. Update all package versions to **THEIA_IDE_VERSION** (select in input prompt):
```sh
yarn lerna version --exact --no-push --no-git-tag-version
```
4. Update the yarn lock file:
```sh
yarn
```
### 2.3. Check for mandatory code changes
<!-- release: both -->
Update the code to include everything that should be part of the release:
- Implement all tickets that are located in: <https://github.com/eclipse-theia/theia-ide/labels/toDoWithRelease>
- If there was a Theia release:
- Review breaking changes
- Check for new built-ins
- Check sample applications changes
- Update code as necessary
- Check for new theia packages to be consumed in the example applications (in case there are no tickets)
### 2.4. Prepare Release PR
<!-- release: both -->
After completing step 2.3, open a PR with your changes <https://github.com/eclipse-theia/theia-ide/compare>
PR Title:
```md
Update to Theia v{{version}}
```
OR (if it is a pure Theia IDE version update):
```md
Publish Theia IDE {{ideVersion}}
```
### 2.5. Mac Artifacts
<!-- release: both -->
- The PR will trigger a verification build that generates two zip files with mac artifacts.
- Download these two zips and replace them in this pre-release: <https://github.com/eclipse-theia/theia-ide/releases/tag/pre-release>.
- These unsigned dmgs will be used as input for the Jenkins build.
### 2.6. Merge Release PR & Trigger Jenkins Build
<!-- release: both -->
1. Merge PR
2. ==> Steps 2.4 and 2.5 need to be complete to proceed!
3. Once [CI checks after merge to master are complete](https://github.com/eclipse-theia/theia-ide/actions), trigger the Jenkins Release Preview <https://ci.eclipse.org/theia/job/theia-ide-release/> job without parameters.
4. Once 3. is successful the notarize job <https://ci.eclipse.org/theia/job/theia-ide-sign-notarize/> is started automatically.
5. Once 4. is successful it starts the upload job <https://ci.eclipse.org/theia/job/theia-ide-upload/>
*Note*: Please report if upload fails more than 5 times, we need to investigate!
## 3. Preview, Testing, and Release Process
<!-- release: both -->
Once the PR is merged and the preview build is created, follow these steps for testing and eventual release:
### 3.1 Confirm the new preview version is published (do not promote as stable yet)
<!-- release: both -->
- Check if uploaded versions are complete in in download folder <https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/>
- e.g. check if the latest files are correct and the artifacts are there (in doubt, compare to previous versions)
### 3.2 Announce Preview Test Phase
<!-- release: minor -->
### 3.2.1 GH Discussions
<!-- release: minor -->
- Use GitHub Discussions for the announcement in the [Category Release Announcements](https://github.com/eclipse-theia/theia/discussions/new?category=release-announcements).
Title:
```md
Theia IDE {{majorMinor}}.x Preview Testing
```
Body:
```md
The new version {{ideVersion}} of the Theia IDE is available on the preview channel now. Please join the preview testing!
You can download it here:
- [Linux](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/linux/TheiaIDE.AppImage)
- [Mac x86](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/macos/TheiaIDE.dmg)
- [Mac ARM](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/macos-arm/TheiaIDE.dmg)
- [Windows](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/windows/TheiaIDESetup.exe)
Update your existing installation by setting the preference `updates.channel` to `preview`.
Please respond here when you can test the preview without finding blockers, by commenting with a ✔️.
If you find any issues, please mention them in this thread and report them as an issue once confirmed by other testers.
| Phase | Target | Status |
|:---|:---|:---|
| {{ideVersion}} preview available | {{releaseDate}} | :white_check_mark: |
| {{ideVersion}} community preview window | {{previewStart}} → {{previewEnd}} | :hourglass_flowing_sand: |
| Theia IDE {{majorMinor}}.x Promoted to Stable | {{previewEnd}} + 1 business day | |
| Docker image Publish | {{previewEnd}} + 1 business day | |
| Snap updated | {{previewEnd}} + 1 business day | |
```
- Pin discussion to the Release Announcement Category
### 3.2.2 theia-dev mailing list
<!-- release: minor -->
- Announce the preview release via email to [the `theia-dev` mailing List](mailto:theia-dev@eclipse.org) with the following template:
Subject:
```md
Theia IDE {{majorMinor}}.x preview phase
```
Body:
```md
Hi everyone,
Version {{ideVersion}} of the Theia IDE is now available on the preview channel. Please join the preview test and help us stabilize the release.
Visit the preview discussion for more information and coordination: https://github.com/eclipse-theia/theia/discussions/{{discussionNumber}}
```
### 3.2.3 Eclipse Theia Release discussion
<!-- release: minor -->
- Announce the start of the Theia IDE Preview Test phase in the Theia Release announcement (`Eclipse Theia v{{version}}`) discussion (see <https://github.com/eclipse-theia/theia/discussions/categories/release-announcements>):
```md
The preview test phase for the Theia IDE {{ideVersion}} has started. You can find the details here:
- https://github.com/eclipse-theia/theia/discussions/{{discussionNumber}}
```
### 3.2.4 Optional: Announcement to Theia IDE Preview Testers
<!-- release: minor -->
- Optional: Announce the start of the Theia IDE Preview Test phase to your testers (e.g., via Slack, Teams, E-Mail):
```md
:theia: The Theia IDE preview {{ideVersion}} for Theia version {{version}} is now available!
Please take a moment to test it and provide feedback - whether you've run into issues or everything works as expected. {{linkToNewPreviewComment}}
To help us get a quick overview, please react with the emoji for your OS (:ubuntu:, :windows:, :mac_arm:, :mac_x64:) once you updated to the new version.
Thanks!
```
### 3.3 Patch Releases
<!-- release: patch -->
- Address reported blockers and issue patch releases (this process may take 1–2 weeks).
**Note:** If issues are persistent, or resources are insufficient, the release may be postponed to the next version.
- If a blocker was found add this status to the respective preview window:
```md
:no_entry: blocker was found
```
### 3.3.1 Update Preview Discussion with new preview
<!-- release: patch -->
- For Patch Releases, use the [Preview discussion](#32-announce-preview-test-phase) and post a comment to announce the patch release of the Theia IDE: <https://github.com/eclipse-theia/theia/discussions/{{discussionNumber}}>
```md
The new version {{ideVersion}} of the Theia IDE is available on the preview channel now. Please join the preview testing!
You can download it here:
- [Linux](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/linux/TheiaIDE.AppImage)
- [Mac x86](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/macos/TheiaIDE.dmg)
- [Mac ARM](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/macos-arm/TheiaIDE.dmg)
- [Windows](https://download.eclipse.org/theia/ide-preview/{{ideVersion}}/windows/TheiaIDESetup.exe)
Update your existing installation by setting the preference `updates.channel` to `preview`.
Please respond here when you can test the preview without finding blockers, by commenting with a ✔️.
If you find any issues, please mention them in this thread and report them as an issue once confirmed by other testers.
```
### 3.3.2 Update Preview Discussion Table
<!-- release: patch -->
- Adapt the target dates to the planned new preview window and final release dates
- Add comments in the status if necessary
- See example announcements here: <https://github.com/eclipse-theia/theia/discussions/16109>
- Update the discussion's status table with two rows for the current patch release:
```md
| [{{ideVersion}} preview available]({{linkToNewPreviewComment}}) | {{previewStart}} | :white_check_mark: |
| {{ideVersion}} community preview window | {{previewStart}} → {{previewEnd}} | :hourglass_flowing_sand: |
```
- Also adapt the target dates of the remaining entries in table (if not yet promoted)
### 3.3.3 Optional: Internal Slack announcement
<!-- release: patch -->
- Optional: Announce the start of the Theia IDE Preview Test phase in your internal Slack channel:
```md
:theia: The Theia IDE preview {{ideVersion}} for Theia version {{version}} is now available!
Please take a moment to test it and provide feedback - whether you've run into issues or everything works as expected. {{linkToNewPreviewComment}}
To help us get a quick overview, please react with the emoji for your OS (:ubuntu:, :windows:, :mac_arm:, :mac_x64:) once you updated to the new version.
Thanks!
```
## 3.4 Optional: Internal Slack - feedback reminder
<!-- release: both -->
- Optional: Schedule a slack reminder close to the preview end:
```md
Quick reminder: We're planning to promote the new IDE version (e.g., tomorrow/on Monday), please share your feedback for the preview {{ideVersion}}!
:point_right: https://github.com/eclipse-theia/theia/discussions/{{discussionNumber}}
Thanks! :thx:
```
## 4. Promote IDE from Preview to Stable Channel
<!-- release: both -->
Promote the IDE using the [Build Job](https://ci.eclipse.org/theia/job/Theia%20-%20Promote%20IDE/).
- Specify the release version in the `VERSION` parameter (e.g., 1.48.0), corresponding to the **THEIA_IDE_VERSION** copied from <https://download.eclipse.org/theia/ide-preview/>.
- Post a comment to announce the official release of the Theia IDE:
```md
{{ideVersion}} has been promoted to stable
```
- Update the [Base Preview discussion](#32-announce-preview-test-phase) status table with a checkmark and the version that has been published.
```md
| [Theia IDE {{majorMinor}}.x Promoted to Stable](https://download.eclipse.org/theia/ide/1.67.100/) | {{today}} | :white_check_mark: |
```
- Mark the message as the answer.
- Unpin discussion from the Release Announcement Category.
## 5. Tag the Release Commit
<!-- release: both -->
After promoting the release, tag the release commit as follows:
1. Create the tag:
```bash
git tag v{{ideVersion}} ${SHA of release commit}
```
2. Push the tag to the repository:
```bash
git push origin v{{ideVersion}}
```
## 6. Publish Docker Image
<!-- release: both -->
Publish the Docker image by running the [workflow](https://github.com/eclipse-theia/theia-ide/actions/workflows/publish-theia-ide-img.yml) from the `master` branch. Use **${THEIA_IDE_VERSION}** as the version.
(We do NOT use the v prefix here in this case currently).
- Check the GH package page if the image was published correctly: <https://github.com/eclipse-theia/theia-ide/pkgs/container/theia-ide%2Ftheia-ide>
- Update the [Preview discussion](#32-announce-preview-test-phase) status table
```md
| [Docker image Publish](https://github.com/eclipse-theia/theia-ide/pkgs/container/theia-ide%2Ftheia-ide) | {{today}} | :white_check_mark: |
```
## 7. Snap Update
<!-- release: both -->
Can be parallel to step 6.
After the IDE is promoted to stable, perform these steps for the snap update:
1. Run [this workflow](https://github.com/eclipse-theia/theia-ide-snap/actions/workflows/update.yml) from the `master` branch.
2. After the build succeeded, visit <https://github.com/eclipse-theia/theia-ide-snap/pulls> to find the PR that updates to **${THEIA_IDE_VERSION}**.
3. Check out the corresponding branch.
4. Amend the latest commit with your author details:
```bash
git commit --amend --author="Your Name <name@example.com>"
```
5. Force push the branch.
6. Verify that all checks pass, and then `rebase and merge`.
7. Confirm the master branch build (Store Publishing) is successful.
8. Check if snap is available <https://snapcraft.io/theia-ide>
9. Update the [Preview discussion](#32-announce-preview-test-phase) status table
```md
| [Snap updated](https://snapcraft.io/theia-ide) | {{today}} | :white_check_mark: |
```
## 8. Upgrade Dependencies
<!-- release: both -->
After each release, run the following command to upgrade dependencies:
Keep this upgrade process in a separate PR, as it might require IP Reviews from the Eclipse Foundation and additional time. Also, verify the `electron` version in `yarn.lock` and adjust `electronVersion` in `applications/electron/electron-builder.yml` if it has changed.
To perform the upgrade:
- Run `yarn upgrade` at the root of the repository.
- Fix any compilation errors, typing errors, and failing tests.
- Open a PR with the changes ([example](https://github.com/eclipse-theia/theia-ide/pull/568)).
- The license check review is done via the CI.
- Wait for the "IP Check" to complete ([example](https://gitlab.eclipse.org/eclipsefdn/emo-team/iplab/-/issues/22828)).
Performing this after the release helps us to find issues with the new dependencies and gives time to perform a license check on the dependencies.
================================================
FILE: README.md
================================================
<br/>
<div id="theia-logo" align="center">
<br />
<img src="https://raw.githubusercontent.com/eclipse-theia/theia-ide/master/theia-extensions/product/src/browser/icons/TheiaIDE.png" alt="Theia Logo" width="300"/>
<h3>Eclipse Theia IDE</h3>
</div>
<div id="badges" align="center">
The Eclipse Theia IDE is built with this project.\
Eclipse Theia IDE also serves as a template for building desktop-based products based on the Eclipse Theia platform.
</div>
[](https://theia-ide.org//#theiaidedownload)
[](https://ci.eclipse.org/theia/job/Theia2/job/master/)
<!-- currently we have no working next job because next builds are not published -->
<!-- [](https://ci.eclipse.org/theia/job/theia-next/job/master/) -->
[Main Theia Repository](https://github.com/eclipse-theia/theia)
[Visit the Theia website](http://www.theia-ide.org) for more documentation: [Using the Theia IDE](https://theia-ide.org/docs/user_getting_started/), [Packaging Theia as a Desktop Product](https://theia-ide.org/docs/blueprint_documentation/).
## License
- [MIT](LICENSE)
## Trademark
"Theia" is a trademark of the Eclipse Foundation
<https://www.eclipse.org/theia>
## What is this?
The Eclipse IDE is a modern and open IDE for cloud and desktop. The Theia IDE is based on the [Theia platform](https://theia-ide.org).
The Theia IDE is available as a [downloadable desktop application](https://theia-ide.org//#theiaidedownload). You can also try the latest version of the Theia IDE online. The online test version is limited to 30 minutes per session and hosted via Theia.cloud. Finally, we provide an [experimental Docker image](#docker) for hosting the Theia IDE online.
The Eclipse Theia IDE also serves as a **template** for building desktop-based products based on the Eclipse Theia platform, as well as to showcase Eclipse Theia capabilities. It is made up of a subset of existing Eclipse Theia features and extensions. [Documentation is available](https://theia-ide.org/docs/composing_applications/) to help you customize and build your own Eclipse Theia-based product.
## Theia IDE vs Theia Blueprint
The Theia IDE has been rebranded from its original name “Theia Blueprint”. You can therefore assume the terms “Theia IDE” and “Theia Blueprint” to be synonymous.
## Development
### Requirements
Please check Theia's [prerequisites](https://github.com/eclipse-theia/theia/blob/master/doc/Developing.md#prerequisites), and keep node versions aligned between Theia IDE and that of the referenced Theia version.
### Documentation
Documentation on how to package Theia as a Desktop Product may be found [here](https://theia-ide.org/docs/blueprint_documentation/)
For adopters building their own products based on this template, see the [Adopter Guide](ADOPTER.md) for additional considerations.
### Repository Structure
- Root level configures mono-repo build with lerna
- `applications` groups the different app targets
- `browser` contains a browser based version of Eclipse Theia IDE that may be packaged as a Docker image
- `electron` contains the electron app to package, packaging configuration, and E2E tests for the electron target.
- `theia-extensions` groups the various custom theia extensions for the Eclipse Theia IDE
- `product` contains a Theia extension contributing the product branding (about dialogue and welcome page).
- `updater` contains a Theia extension contributing the update mechanism and corresponding UI elements (based on the electron updater).
- `launcher` contains a Theia extension contributing, for AppImage applications, the option to create a script that allows to start the Eclipse Theia IDE from the command line by calling the 'theia' command.
- `patches` contains patches applied to upstream packages
### Build
For development and casual testing of the Eclipse Theia IDE, one can build it in "dev" mode. This permits building the IDE on systems with less resources, like a Raspberry Pi 4B with 4GB of RAM.
NOTE: If manually building after updating dependencies or pulling to a newer commit, run `git clean -xfd` to help avoid runtime conflicts.
```sh
# Build "dev" version of the app. Its quicker, uses less resources,
# but the front end app is not "minified"
yarn && yarn build:dev && yarn download:plugins
```
Production applications:
```sh
# Build production version of the Eclipse Theia IDE app
yarn && yarn build && yarn download:plugins
```
### Package the Applications
ATM we only produce packages for the Electron application.
_If you are trying to compile for arm on an arm machine, you may want to follow [these steps](https://github.com/eclipse-theia/theia-ide/issues/690#issuecomment-4157768849) before_
```sh
yarn package:applications
# or
yarn electron package
```
The packaged application is located in `applications/electron/dist`.
### Create a Preview Electron Electron Application (without packaging it)
```sh
yarn electron package:preview
```
The packaged application is located in `applications/electron/dist`.
### Running E2E Tests on Electron
The E2E tests basic UI tests of the actual application.
This is done based on the preview of the packaged application.
```sh
yarn electron package:preview
yarn electron test
```
### Running Browser app
The browser app may be started with
```sh
yarn browser start
```
and connect to <http://localhost:3000/>
### Developing with Local Theia Framework
To build and test the Theia IDE against a local development version of the Theia framework, see [docs/developing-with-local-theia.md](docs/developing-with-local-theia.md).
### Troubleshooting
- [_"Don't expect that you can build app for all platforms on one platform."_](https://www.electron.build/multi-platform-build)
### Reporting Feature Requests and Bugs
The features in the Eclipse Theia IDE are based on Theia and the included extensions/plugins. For bugs in Theia please consider opening an issue in the [Theia project on Github](https://github.com/eclipse-theia/theia/issues/new/choose).
The Eclipse Theia IDE only packages existing functionality into a product and installers for the product. If you believe there is a mistake in packaging, something needs to be added to the packaging or the installers do not work properly, please [open an issue on Github](https://github.com/eclipse-theia/theia-ide/issues/new/choose) to let us know.
### Docker
The Docker image of the Theia IDE is currently in _experimental state_. It is built from the same sources and packages as the desktop version, but it is not part of the [preview test](https://github.com/eclipse-theia/theia-ide/blob/master/PUBLISHING.md#preview-testing-and-release-process-for-the-theia-ide).
You can find a prebuilt Docker image of the IDE [here](https://github.com/eclipse-theia/theia-ide/pkgs/container/theia-ide%2Ftheia-ide).
You can also create the Docker image for the Eclipse Theia IDE based on the browser app with the following build command:
```sh
docker build -t theia-ide -f browser.Dockerfile .
```
You may then run this with
```sh
docker run -p=3000:3000 --rm theia-ide
```
and connect to <http://localhost:3000/>
================================================
FILE: applications/browser/package.json
================================================
{
"private": true,
"name": "theia-ide-browser-app",
"description": "Eclipse Theia IDE browser product",
"productName": "Theia IDE",
"version": "1.71.100",
"license": "MIT",
"author": "Eclipse Theia <theia-dev@eclipse.org>",
"homepage": "https://github.com/eclipse-theia/theia-ide#readme",
"bugs": {
"url": "https://github.com/eclipse-theia/theia/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/eclipse-theia/theia-ide.git"
},
"engines": {
"yarn": ">=1.7.0 <2",
"node": ">=22"
},
"theia": {
"frontend": {
"config": {
"applicationName": "Theia IDE",
"warnOnPotentiallyInsecureHostPattern": false,
"preferences": {
"toolbar.showToolbar": true,
"files.enableTrash": false,
"security.workspace.trust.enabled": false
},
"reloadOnReconnect": true
}
},
"backend": {
"config": {
"warnOnPotentiallyInsecureHostPattern": false,
"startupTimeout": -1,
"resolveSystemPlugins": false,
"configurationFolder": ".theia-ide",
"frontendConnectionTimeout": 3000
}
},
"generator": {
"config": {
"preloadTemplate": "./resources/preload.html"
}
}
},
"dependencies": {
"@theia/ai-anthropic": "1.72.0-next.20",
"@theia/ai-chat": "1.72.0-next.20",
"@theia/ai-chat-ui": "1.72.0-next.20",
"@theia/ai-claude-code": "1.72.0-next.20",
"@theia/ai-code-completion": "1.72.0-next.20",
"@theia/ai-codex": "1.72.0-next.20",
"@theia/ai-copilot": "1.72.0-next.20",
"@theia/ai-core": "1.72.0-next.20",
"@theia/ai-core-ui": "1.72.0-next.20",
"@theia/ai-editor": "1.72.0-next.20",
"@theia/ai-google": "1.72.0-next.20",
"@theia/ai-history": "1.72.0-next.20",
"@theia/ai-huggingface": "1.72.0-next.20",
"@theia/ai-ide": "1.72.0-next.20",
"@theia/ai-llamafile": "1.72.0-next.20",
"@theia/ai-mcp": "1.72.0-next.20",
"@theia/ai-mcp-server": "1.72.0-next.20",
"@theia/ai-mcp-ui": "1.72.0-next.20",
"@theia/ai-ollama": "1.72.0-next.20",
"@theia/ai-openai": "1.72.0-next.20",
"@theia/ai-scanoss": "1.72.0-next.20",
"@theia/ai-terminal": "1.72.0-next.20",
"@theia/ai-vercel-ai": "1.72.0-next.20",
"@theia/bulk-edit": "1.72.0-next.20",
"@theia/callhierarchy": "1.72.0-next.20",
"@theia/collaboration": "1.72.0-next.20",
"@theia/console": "1.72.0-next.20",
"@theia/core": "1.72.0-next.20",
"@theia/debug": "1.72.0-next.20",
"@theia/dev-container": "1.72.0-next.20",
"@theia/editor": "1.72.0-next.20",
"@theia/editor-preview": "1.72.0-next.20",
"@theia/external-terminal": "1.72.0-next.20",
"@theia/file-search": "1.72.0-next.20",
"@theia/filesystem": "1.72.0-next.20",
"@theia/getting-started": "1.72.0-next.20",
"@theia/keymaps": "1.72.0-next.20",
"@theia/markers": "1.72.0-next.20",
"@theia/memory-inspector": "1.72.0-next.20",
"@theia/messages": "1.72.0-next.20",
"@theia/metrics": "1.72.0-next.20",
"@theia/mini-browser": "1.72.0-next.20",
"@theia/monaco": "1.72.0-next.20",
"@theia/navigator": "1.72.0-next.20",
"@theia/notebook": "1.72.0-next.20",
"@theia/outline-view": "1.72.0-next.20",
"@theia/output": "1.72.0-next.20",
"@theia/plugin-dev": "1.72.0-next.20",
"@theia/plugin-ext": "1.72.0-next.20",
"@theia/plugin-ext-vscode": "1.72.0-next.20",
"@theia/preferences": "1.72.0-next.20",
"@theia/preview": "1.72.0-next.20",
"@theia/process": "1.72.0-next.20",
"@theia/property-view": "1.72.0-next.20",
"@theia/remote": "1.72.0-next.20",
"@theia/scanoss": "1.72.0-next.20",
"@theia/scm": "1.72.0-next.20",
"@theia/search-in-workspace": "1.72.0-next.20",
"@theia/secondary-window": "1.72.0-next.20",
"@theia/task": "1.72.0-next.20",
"@theia/terminal": "1.72.0-next.20",
"@theia/terminal-manager": "1.72.0-next.20",
"@theia/test": "1.72.0-next.20",
"@theia/timeline": "1.72.0-next.20",
"@theia/toolbar": "1.72.0-next.20",
"@theia/typehierarchy": "1.72.0-next.20",
"@theia/userstorage": "1.72.0-next.20",
"@theia/variable-resolver": "1.72.0-next.20",
"@theia/vsx-registry": "1.72.0-next.20",
"@theia/workspace": "1.72.0-next.20",
"fs-extra": "^9.1.0",
"theia-ide-product-ext": "1.71.100"
},
"devDependencies": {
"@theia/cli": "1.72.0-next.20",
"@theia/bundle-plugin": "1.72.0-next.20"
},
"scripts": {
"clean": "theia clean && rimraf node_modules",
"build": "yarn -s rebuild && theia build --app-target=\"browser\" --mode development",
"build:prod": "yarn -s rebuild && theia build --app-target=\"browser\"",
"rebuild": "theia rebuild:browser --cacheRoot ../..",
"start": "theia start --plugins=local-dir:../../plugins",
"watch": "concurrently --kill-others -n tsc,build -c red,yellow \"tsc -b -w --preserveWatchOutput\" \"yarn -s watch:bundle\"",
"update:theia": "ts-node ../../scripts/update-theia-version.ts",
"update:next": "ts-node ../../scripts/update-theia-version.ts next"
}
}
================================================
FILE: applications/browser/resources/preload.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<style>
html,
body {
background-color: black;
}
.theia-preload {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* Above styles copied from https://github.com/eclipse-theia/theia/blob/5aeef6c0c683b4e91713ab736957e6655b486adc/packages/core/src/browser/style/index.css#L147-L151 */
/* Otherwise, there is a flickering when Theia's CSS loads. */
background-image: none;
}
.theia-preload::after {
/* remove default loading animation */
content: none;
}
.spinner-container {
display: flex;
flex-direction: center;
align-self: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.custom-spinner {
align-self: center;
}
.custom-spinner svg {
width: 16vw;
height: 16vh;
animation-delay: 0;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-name: theia-ide-spinner;
animation-timing-function: ease;
}
@keyframes theia-ide-spinner {
0% {
filter: invert(49%) sepia(71%) saturate(5980%) hue-rotate(199deg) brightness(103%) contrast(101%);
transform: scale(1.0);
}
50% {
filter: invert(57%) sepia(52%) saturate(1900%) hue-rotate(160deg) brightness(100%) contrast(102%);
transform: scale(0.8);
}
100% {
filter: invert(49%) sepia(71%) saturate(5980%) hue-rotate(199deg) brightness(103%) contrast(101%);
transform: scale(1.0);
}
}
</style>
</head>
<body>
<div class='spinner-container'>
<div class='custom-spinner'>
<svg id="spinner" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" preserveAspectRatio="xMinYMin meet"
viewBox="0, 0, 1150, 540.6">
<g id="Layer_1" fill="#FFFFFF">
<path
d="M880.199,2.8 C1028.1,2.8 1147.9,122.6 1147.9,270.5 C1147.9,418.3 1028.1,538.2 880.2,538.2 L290.1,538.2 C269,538.2 251.9,521.1 251.9,500 C251.9,478.9 269,461.8 290.1,461.8 L427.6,461.8 C448.6,461.8 465.7,444.7 465.7,423.6 C465.7,402.5 448.6,385.4 427.6,385.4 L396.999,385.4 C375.9,385.4 358.8,368.3 358.8,347.2 C358.8,326.1 375.9,309 397,309 L488.703,309 C509.918,308.941 526.373,291.65 526.9,270.8 C526.9,249.7 509.8,232.6 488.7,232.6 L167.8,232.6 C146.7,232.6 129.6,215.5 129.6,194.4 C129.6,173.3 146.7,156.2 167.8,156.2 L404.604,156.2 C425.818,156.141 442.273,138.85 442.8,118 C442.8,96.9 425.7,79.8 404.6,79.8 L351.2,79.8 C330.1,79.8 313,62.7 313,41.6 C313,20.5 330.1,2.4 351.2,2.4 L880.199,2.8 z M837.4,92 L837.4,92 C755.2,92 688.7,158.6 688.7,240.7 L688.7,300.2 C688.7,382.4 755.2,448.9 837.4,448.9 C919.5,448.9 986.1,382.4 986.1,300.2 L986.1,240.7 C986.1,158.6 919.5,92 837.4,92 L837.4,92 z M888.2,232.6 C908,232.6 924.1,248.7 924.1,268.5 L924.1,273.1 C924.1,292.9 908,309 888.2,309 L776.6,309 C756.8,309 740.7,292.9 740.7,273.1 L740.7,268.5 C740.7,248.7 756.8,232.6 776.6,232.6 L888.2,232.6 z" />
<path
d="M170.1,461.8 C190,461.8 206,477.8 206,497.7 L206,502.3 C206,522.1 190,538.2 170.1,538.2 L38,538.2 C18.2,538.2 2.1,522.1 2.1,502.3 L2.1,497.7 C2.1,477.8 18.2,461.8 38,461.8 L170.1,461.8 z" />
<path
d="M231.3,3.4 C251.1,3.4 267.1,19.5 267.1,39.3 L267.1,44 C267.1,63.8 251.1,79.8 231.3,79.8 L83.8,79.8 C64,79.8 47.9,63.8 47.9,44 L47.9,39.3 C47.9,19.5 64,3.4 83.8,3.4 L231.3,3.4 z" />
<path
d="M277.1,309 C296.9,309 313,325.1 313,344.9 L313,349.5 C313,369.3 296.9,385.4 277.1,385.4 L196.1,385.4 C176.3,385.4 160.2,369.3 160.2,349.5 L160.2,344.9 C160.2,325.1 176.3,309 196.1,309 L277.1,309 z" />
</g>
</svg>
</div>
</div>
<script>
if (document.head) {
let link = document.createElement('link');
link.rel = 'icon';
link.href = '/favicon.ico';
document.head.appendChild(link);
}
</script>
</body>
</html>
================================================
FILE: applications/browser/tsconfig.json
================================================
{
"extends": "../../configs/base.tsconfig",
"include": [],
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "../../theia-extensions/launcher"
},
{
"path": "../../theia-extensions/product"
}
]
}
================================================
FILE: applications/browser/webpack.config.js
================================================
/**
* This file can be edited to customize webpack configuration.
* To reset delete this file and rerun theia build again.
*/
// @ts-check
const configs = require('./gen-webpack.config.js');
const nodeConfig = require('./gen-webpack.node.config.js');
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
/**
* Expose bundled modules on window.theia.moduleName namespace, e.g.
* window['theia']['@theia/core/lib/common/uri'].
* Such syntax can be used by external code, for instance, for testing.
configs[0].module.rules.push({
test: /\.js$/,
loader: require.resolve('@theia/application-manager/lib/expose-loader')
}); */
// serve favico from root
// @ts-ignore
configs[0].plugins.push(
// @ts-ignore
new CopyWebpackPlugin({
patterns: [
{
context: path.resolve('.', '..', '..', 'applications', 'browser', 'ico'),
from: '**'
}
]
})
);
module.exports = [
...configs,
nodeConfig.config
];
================================================
FILE: applications/electron/.eslintrc.js
================================================
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: [
'../../configs/build.eslintrc.json'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.eslint.json'
}
};
================================================
FILE: applications/electron/electron-builder.yml
================================================
appId: eclipse.theia
productName: TheiaIDE
copyright: Copyright © 2020-2025 Eclipse Foundation, Inc
electronDist: ../../node_modules/electron/dist
electronVersion: 39.8.7
asar: true
asarUnpack:
- "**/lib/backend/native/**"
- "**/lib/backend/shell-integrations/**"
- "**/lib/build/Release/**"
- "**/lib/prebuilds/**"
nodeGypRebuild: false
npmRebuild: false
directories:
buildResources: resources
# node_modules and package.json are copied automatically
# Exclude node_modules manually because electron is copied by electron-builder and we are using a bundled backend
files:
- src-gen
- lib
- resources/icons/WindowIcon/512-512.png
- resources/TheiaIDESplash.svg
- scripts
- "!**node_modules/**"
extraResources:
- from: ../../plugins
to: app/plugins
win:
icon: resources/icons/WindowsLauncherIcons/TheiaIDE.ico
target:
- nsis
publish:
provider: generic
url: "https://download.eclipse.org/theia/ide/${version}/windows"
useMultipleRangeRequest: false
mac:
icon: resources/icons/MacLauncherIcons/icon.icns
category: public.app-category.developer-tools
protocols:
- name: theia
schemes:
- theia
darkModeSupport: true
target:
- dmg
- zip
publish:
provider: generic
url: "https://download.eclipse.org/theia/ide/latest/macos"
linux:
icon: resources/icons/LinuxLauncherIcons
category: Development
mimeTypes:
- inode/directory
vendor: Eclipse Foundation, Inc
target:
- deb
- AppImage
publish:
provider: generic
url: "https://download.eclipse.org/theia/ide/latest/linux"
nsis:
menuCategory: true
oneClick: false
perMachine: false
installerHeaderIcon: resources/icons/WindowsLauncherIcons/TheiaIDE.ico
installerIcon: resources/icons/WindowsLauncherIcons/TheiaIDE.ico
uninstallerIcon: resources/icons/WindowsLauncherIcons/TheiaIDE.ico
installerSidebar: resources/icons/InstallerSidebarImage/164-314Windows.bmp
uninstallerSidebar: resources/icons/InstallerSidebarImage/164-314Windows.bmp
allowToChangeInstallationDirectory: true
runAfterFinish: false
artifactName: ${productName}Setup.${ext}
license: LICENSE
dmg:
artifactName: ${productName}.${ext}
deb:
artifactName: ${productName}.${ext}
appImage:
artifactName: ${productName}.${ext}
afterPack: ./scripts/after-pack.js
================================================
FILE: applications/electron/entitlements.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
================================================
FILE: applications/electron/package.json
================================================
{
"private": true,
"name": "theia-ide-electron-app",
"description": "Eclipse Theia IDE product",
"productName": "Theia IDE",
"version": "1.71.100",
"main": "scripts/theia-electron-main.js",
"license": "MIT",
"author": "Eclipse Theia <theia-dev@eclipse.org>",
"homepage": "https://github.com/eclipse-theia/theia-ide#readme",
"bugs": {
"url": "https://github.com/eclipse-theia/theia/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/eclipse-theia/theia-ide.git"
},
"engines": {
"yarn": ">=1.7.0 <2",
"node": ">=22"
},
"theia": {
"target": "electron",
"frontend": {
"config": {
"applicationName": "Theia IDE",
"reloadOnReconnect": true,
"preferences": {
"toolbar.showToolbar": true
},
"electron": {
"showWindowEarly": false,
"splashScreenOptions": {
"content": "resources/TheiaIDESplash.svg",
"height": 276,
"width": 446
}
}
}
},
"backend": {
"config": {
"frontendConnectionTimeout": -1,
"startupTimeout": -1,
"resolveSystemPlugins": false,
"configurationFolder": ".theia-ide"
}
},
"generator": {
"config": {
"preloadTemplate": "./resources/preload.html"
}
}
},
"dependencies": {
"@theia/ai-anthropic": "1.72.0-next.20",
"@theia/ai-chat": "1.72.0-next.20",
"@theia/ai-chat-ui": "1.72.0-next.20",
"@theia/ai-claude-code": "1.72.0-next.20",
"@theia/ai-code-completion": "1.72.0-next.20",
"@theia/ai-codex": "1.72.0-next.20",
"@theia/ai-copilot": "1.72.0-next.20",
"@theia/ai-core": "1.72.0-next.20",
"@theia/ai-core-ui": "1.72.0-next.20",
"@theia/ai-editor": "1.72.0-next.20",
"@theia/ai-google": "1.72.0-next.20",
"@theia/ai-history": "1.72.0-next.20",
"@theia/ai-huggingface": "1.72.0-next.20",
"@theia/ai-ide": "1.72.0-next.20",
"@theia/ai-llamafile": "1.72.0-next.20",
"@theia/ai-mcp": "1.72.0-next.20",
"@theia/ai-mcp-server": "1.72.0-next.20",
"@theia/ai-mcp-ui": "1.72.0-next.20",
"@theia/ai-ollama": "1.72.0-next.20",
"@theia/ai-openai": "1.72.0-next.20",
"@theia/ai-scanoss": "1.72.0-next.20",
"@theia/ai-terminal": "1.72.0-next.20",
"@theia/ai-vercel-ai": "1.72.0-next.20",
"@theia/bulk-edit": "1.72.0-next.20",
"@theia/callhierarchy": "1.72.0-next.20",
"@theia/collaboration": "1.72.0-next.20",
"@theia/console": "1.72.0-next.20",
"@theia/core": "1.72.0-next.20",
"@theia/debug": "1.72.0-next.20",
"@theia/dev-container": "1.72.0-next.20",
"@theia/editor": "1.72.0-next.20",
"@theia/editor-preview": "1.72.0-next.20",
"@theia/electron": "1.72.0-next.20",
"@theia/external-terminal": "1.72.0-next.20",
"@theia/file-search": "1.72.0-next.20",
"@theia/filesystem": "1.72.0-next.20",
"@theia/getting-started": "1.72.0-next.20",
"@theia/keymaps": "1.72.0-next.20",
"@theia/markers": "1.72.0-next.20",
"@theia/memory-inspector": "1.72.0-next.20",
"@theia/messages": "1.72.0-next.20",
"@theia/metrics": "1.72.0-next.20",
"@theia/mini-browser": "1.72.0-next.20",
"@theia/monaco": "1.72.0-next.20",
"@theia/navigator": "1.72.0-next.20",
"@theia/notebook": "1.72.0-next.20",
"@theia/outline-view": "1.72.0-next.20",
"@theia/output": "1.72.0-next.20",
"@theia/plugin-dev": "1.72.0-next.20",
"@theia/plugin-ext": "1.72.0-next.20",
"@theia/plugin-ext-vscode": "1.72.0-next.20",
"@theia/preferences": "1.72.0-next.20",
"@theia/preview": "1.72.0-next.20",
"@theia/process": "1.72.0-next.20",
"@theia/property-view": "1.72.0-next.20",
"@theia/remote": "1.72.0-next.20",
"@theia/remote-wsl": "1.72.0-next.20",
"@theia/scanoss": "1.72.0-next.20",
"@theia/scm": "1.72.0-next.20",
"@theia/search-in-workspace": "1.72.0-next.20",
"@theia/secondary-window": "1.72.0-next.20",
"@theia/task": "1.72.0-next.20",
"@theia/terminal": "1.72.0-next.20",
"@theia/terminal-manager": "1.72.0-next.20",
"@theia/test": "1.72.0-next.20",
"@theia/timeline": "1.72.0-next.20",
"@theia/toolbar": "1.72.0-next.20",
"@theia/typehierarchy": "1.72.0-next.20",
"@theia/userstorage": "1.72.0-next.20",
"@theia/variable-resolver": "1.72.0-next.20",
"@theia/vsx-registry": "1.72.0-next.20",
"@theia/workspace": "1.72.0-next.20",
"fs-extra": "^9.1.0",
"theia-ide-launcher-ext": "1.71.100",
"theia-ide-product-ext": "1.71.100",
"theia-ide-updater-ext": "1.71.100"
},
"devDependencies": {
"@theia/cli": "1.72.0-next.20",
"@theia/bundle-plugin": "1.72.0-next.20",
"@types/js-yaml": "^3.12.10",
"@types/yargs": "17.0.7",
"@wdio/cli": "^6.12.1",
"@wdio/local-runner": "^6.12.1",
"@wdio/mocha-framework": "^6.11.0",
"@wdio/spec-reporter": "^6.11.0",
"app-builder-lib": "26.0.12",
"chai": "^4.5.0",
"concurrently": "^3.6.1",
"electron": "39.8.7",
"electron-builder": "26.0.12",
"electron-chromedriver": "^28.3.3",
"electron-mocha": "^12.3.1",
"electron-osx-sign": "^0.6.0",
"js-yaml": "^3.14.2",
"mocha": "^8.4.0",
"rimraf": "^2.7.1",
"ts-node": "^10.9.2",
"wdio-chromedriver-service": "^6.0.4",
"webdriverio": "^6.12.1",
"yargs": "17.2.1"
},
"scripts": {
"clean": "theia clean && rimraf node_modules",
"clean:dist": "rimraf dist",
"build": "yarn -s rebuild && theia build --app-target=\"electron\" --mode development",
"build:prod": "yarn -s rebuild && theia build --app-target=\"electron\"",
"rebuild": "theia rebuild:electron --cacheRoot ../..",
"watch": "concurrently -n compile,build \"theiaext watch --preserveWatchOutput\" \"theia build --watch --mode development\"",
"start": "electron scripts/theia-electron-main.js --plugins=local-dir:../../plugins",
"start:debug": "yarn start --log-level=debug",
"package": "yarn clean:dist && yarn rebuild && electron-builder -c.mac.identity=null --publish never",
"package:prod": "yarn deploy",
"deploy": "yarn clean:dist && yarn rebuild && electron-builder -c.mac.identity=null --publish always",
"package:preview": "yarn clean:dist && yarn rebuild && electron-builder -c.mac.identity=null --dir",
"update:checksum": "ts-node scripts/update-checksum.ts",
"update:blockmap": "ts-node scripts/update-blockmap.ts",
"update:theia": "ts-node ../../scripts/update-theia-version.ts",
"update:next": "ts-node ../../scripts/update-theia-version.ts next",
"sign:directory": "ts-node scripts/sign-directory.ts",
"sign:directory:windows": "ts-node scripts/sign-directory-windows.ts",
"test": "mocha --timeout 60000 \"./test/*.spec.js\"",
"lint": "eslint --ext js,jsx,ts,tsx scripts && eslint --ext js,jsx,ts,tsx test",
"lint:fix": "eslint --ext js,jsx,ts,tsx scripts --fix && eslint --ext js,jsx,ts,tsx test -fix"
}
}
================================================
FILE: applications/electron/resources/LICENSE
================================================
MIT License
Copyright (c) 2020 Eclipse Theia Blueprint Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: applications/electron/resources/icons/MacLauncherIcons/icon.icon/icon.json
================================================
{
"fill" : {
"automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
},
"groups" : [
{
"layers" : [
{
"image-name" : "icon.png",
"name" : "icon",
"position" : {
"scale" : 1.67,
"translation-in-points" : [
0,
0
]
}
}
],
"name" : "Icon",
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
},
{
"blur-material" : null,
"hidden" : false,
"layers" : [
{
"image-name" : "Theia Light BG.jpg",
"name" : "Theia Light BG"
}
],
"lighting" : "combined",
"name" : "Light Mode Content",
"opacity-specializations" : [
{
"appearance" : "dark",
"value" : 0
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
},
{
"hidden" : false,
"layers" : [
{
"image-name" : "Theia Dark BG.jpg",
"name" : "Theia Dark BG"
}
],
"lighting" : "combined",
"name" : "Dark Mode Content",
"opacity-specializations" : [
{
"value" : 0
},
{
"appearance" : "dark",
"value" : 1
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}
================================================
FILE: applications/electron/resources/preload.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<style>
html,
body {
background-color: black;
}
.theia-preload {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* Above styles copied from https://github.com/eclipse-theia/theia/blob/5aeef6c0c683b4e91713ab736957e6655b486adc/packages/core/src/browser/style/index.css#L147-L151 */
/* Otherwise, there is a flickering when Theia's CSS loads. */
background-image: none;
}
.theia-preload::after {
/* remove default loading animation */
content: none;
}
.spinner-container {
display: flex;
flex-direction: center;
align-self: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.custom-spinner {
align-self: center;
}
.custom-spinner svg {
width: 16vw;
height: 16vh;
animation-delay: 0;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-name: theia-ide-spinner;
animation-timing-function: ease;
}
@keyframes theia-ide-spinner {
0% {
filter: invert(49%) sepia(71%) saturate(5980%) hue-rotate(199deg) brightness(103%) contrast(101%);
transform: scale(1.0);
}
50% {
filter: invert(57%) sepia(52%) saturate(1900%) hue-rotate(160deg) brightness(100%) contrast(102%);
transform: scale(0.8);
}
100% {
filter: invert(49%) sepia(71%) saturate(5980%) hue-rotate(199deg) brightness(103%) contrast(101%);
transform: scale(1.0);
}
}
</style>
</head>
<body>
<div class='spinner-container'>
<div class='custom-spinner'>
<svg id="spinner" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" preserveAspectRatio="xMinYMin meet"
viewBox="0, 0, 1150, 540.6">
<g id="Layer_1" fill="#FFFFFF">
<path
d="M880.199,2.8 C1028.1,2.8 1147.9,122.6 1147.9,270.5 C1147.9,418.3 1028.1,538.2 880.2,538.2 L290.1,538.2 C269,538.2 251.9,521.1 251.9,500 C251.9,478.9 269,461.8 290.1,461.8 L427.6,461.8 C448.6,461.8 465.7,444.7 465.7,423.6 C465.7,402.5 448.6,385.4 427.6,385.4 L396.999,385.4 C375.9,385.4 358.8,368.3 358.8,347.2 C358.8,326.1 375.9,309 397,309 L488.703,309 C509.918,308.941 526.373,291.65 526.9,270.8 C526.9,249.7 509.8,232.6 488.7,232.6 L167.8,232.6 C146.7,232.6 129.6,215.5 129.6,194.4 C129.6,173.3 146.7,156.2 167.8,156.2 L404.604,156.2 C425.818,156.141 442.273,138.85 442.8,118 C442.8,96.9 425.7,79.8 404.6,79.8 L351.2,79.8 C330.1,79.8 313,62.7 313,41.6 C313,20.5 330.1,2.4 351.2,2.4 L880.199,2.8 z M837.4,92 L837.4,92 C755.2,92 688.7,158.6 688.7,240.7 L688.7,300.2 C688.7,382.4 755.2,448.9 837.4,448.9 C919.5,448.9 986.1,382.4 986.1,300.2 L986.1,240.7 C986.1,158.6 919.5,92 837.4,92 L837.4,92 z M888.2,232.6 C908,232.6 924.1,248.7 924.1,268.5 L924.1,273.1 C924.1,292.9 908,309 888.2,309 L776.6,309 C756.8,309 740.7,292.9 740.7,273.1 L740.7,268.5 C740.7,248.7 756.8,232.6 776.6,232.6 L888.2,232.6 z" />
<path
d="M170.1,461.8 C190,461.8 206,477.8 206,497.7 L206,502.3 C206,522.1 190,538.2 170.1,538.2 L38,538.2 C18.2,538.2 2.1,522.1 2.1,502.3 L2.1,497.7 C2.1,477.8 18.2,461.8 38,461.8 L170.1,461.8 z" />
<path
d="M231.3,3.4 C251.1,3.4 267.1,19.5 267.1,39.3 L267.1,44 C267.1,63.8 251.1,79.8 231.3,79.8 L83.8,79.8 C64,79.8 47.9,63.8 47.9,44 L47.9,39.3 C47.9,19.5 64,3.4 83.8,3.4 L231.3,3.4 z" />
<path
d="M277.1,309 C296.9,309 313,325.1 313,344.9 L313,349.5 C313,369.3 296.9,385.4 277.1,385.4 L196.1,385.4 C176.3,385.4 160.2,369.3 160.2,349.5 L160.2,344.9 C160.2,325.1 176.3,309 196.1,309 L277.1,309 z" />
</g>
</svg>
</div>
</div>
</body>
</html>
================================================
FILE: applications/electron/scripts/after-pack.js
================================================
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const util = require('util');
const child_process = require('child_process');
const rimraf = require('rimraf');
const sign_util = require('electron-osx-sign/util');
const asyncRimraf = util.promisify(rimraf);
const DELETE_PATHS = [
'Contents/Resources/app/node_modules/unzip-stream/aa.zip',
'Contents/Resources/app/node_modules/unzip-stream/testData*'
];
const signCommand = path.join(__dirname, 'sign.sh');
const notarizeCommand = path.join(__dirname, 'notarize.sh');
const entitlements = path.resolve(__dirname, '..', 'entitlements.plist');
const signFile = file => {
const stat = fs.lstatSync(file);
const mode = stat.isFile() ? stat.mode : undefined;
console.log(`Signing ${file}...`);
child_process.spawnSync(signCommand, [
path.basename(file),
entitlements
], {
cwd: path.dirname(file),
maxBuffer: 1024 * 10000,
env: process.env,
stdio: 'inherit',
encoding: 'utf-8'
});
if (mode) {
console.log(`Setting attributes of ${file}...`);
fs.chmodSync(file, mode);
}
};
exports.default = async function (context) {
await afterPackHook(context);
const running_ci = process.env.THEIA_IDE_JENKINS_CI === 'true';
const releaseDryRun = process.env.THEIA_IDE_JENKINS_RELEASE_DRYRUN === 'true';
const branch = process.env.BRANCH_NAME;
const running_on_mac = context.packager.platform.name === 'mac';
const appPath = path.resolve(context.appOutDir, `${context.packager.appInfo.productFilename}.app`);
// Remove anything we don't want in the final package
for (const deletePath of DELETE_PATHS) {
const resolvedPath = path.resolve(appPath, deletePath);
console.log(`Deleting ${resolvedPath}...`);
await asyncRimraf(resolvedPath);
}
// Only continue for macOS during CI
if ((( branch === 'master' || releaseDryRun) && running_ci && running_on_mac)) {
console.log('Detected Theia IDE Release on Mac ' + releaseDryRun ? ' (dry-run)' : ''
+ ' - proceeding with signing and notarizing');
} else {
if (running_on_mac) {
console.log('Not a release or dry-run requiring signing/notarizing - skipping');
}
return;
}
// Use app-builder-lib to find all binaries to sign, at this level it will include the final .app
let childPaths = await sign_util.walkAsync(context.appOutDir);
// Sign deepest first
// From https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/electron-osx-sign/sign.js#L120
childPaths = childPaths.sort((a, b) => {
const aDepth = a.split(path.sep).length;
const bDepth = b.split(path.sep).length;
return bDepth - aDepth;
});
// Sign binaries
childPaths.forEach(file => signFile(file, context.appOutDir));
// Notarize app
child_process.spawnSync(notarizeCommand, [
path.basename(appPath),
context.packager.appInfo.info._configuration.appId
], {
cwd: path.dirname(appPath),
maxBuffer: 1024 * 10000,
env: process.env,
stdio: 'inherit',
encoding: 'utf-8'
});
};
// taken and modified from: https://github.com/gergof/electron-builder-sandbox-fix/blob/a2251d7d8f22be807d2142da0cf768c78d4cfb0a/lib/index.js
const afterPackHook = async params => {
if (params.electronPlatformName !== 'linux') {
// this fix is only required on linux
return;
}
const executable = path.join(
params.appOutDir,
params.packager.executableName
);
const loaderScript = `#!/usr/bin/env bash
set -u
SCRIPT_DIR="$( cd "$( dirname "\${BASH_SOURCE[0]}" )" && pwd )"
exec "$SCRIPT_DIR/${params.packager.executableName}.bin" "--no-sandbox" "$@"
`;
try {
await fs.promises.rename(executable, executable + '.bin');
await fs.promises.writeFile(executable, loaderScript);
await fs.promises.chmod(executable, 0o755);
} catch (e) {
throw new Error('Failed to create loader for sandbox fix:\n' + e);
}
};
================================================
FILE: applications/electron/scripts/appimage-helpers.js
================================================
const fs = require('fs');
const path = require('path');
/**
* Reads the plugin copy metadata file and returns its content.
* @param metadataPath - Path to the metadata file
* @returns The metadata object or undefined if not found
*/
function readPluginCopyMetadata(metadataPath) {
if (!fs.existsSync(metadataPath)) {
return undefined;
}
try {
return JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
} catch (err) {
console.warn('Could not read built-in plugin copy metadata file:', err.message);
return undefined;
}
}
/**
* Writes the plugin copy metadata file with version and timestamp.
* @param metadataPath - Path to the metadata file
* @param version - Current version
*/
function writePluginCopyMetadata(metadataPath, version) {
const metadata = {
version: version,
copiedAt: new Date().toISOString()
};
fs.writeFileSync(metadataPath, JSON.stringify(metadata, undefined, 2));
}
/**
* Copies bundled plugins from AppImage to user directory if needed.
* @param bundledPluginsDir - Path to bundled plugins in AppImage
* @param userPluginsDir - Path to user built-in plugins directory
* @param currentVersion - Current Theia IDE version
* @returns true if the builtins were copied to the user dir, false if there was an error
*/
function copyBundledPlugins(bundledPluginsDir, userPluginsDir, currentVersion) {
const metadataFile = path.join(userPluginsDir, '.builtInPlugins-metadata');
// Ensure the user plugins directory exists
if (!fs.existsSync(userPluginsDir)) {
fs.mkdirSync(userPluginsDir, { recursive: true });
}
// Check if built-in plugins need to be copied
const metadata = readPluginCopyMetadata(metadataFile);
let shouldCopy = false;
if (!metadata) {
shouldCopy = true;
} else if (metadata.version !== currentVersion) {
console.log(`Theia IDE updated from ${metadata.version} to ${currentVersion}. Updating built-in plugins...`);
shouldCopy = true;
}
if (!shouldCopy) {
console.log('Built-in plugins were already copied.');
return true;
}
console.log(`Copying bundled plugins from AppImage to ${userPluginsDir}...`);
try {
// Clean existing plugins directory to remove old/obsolete plugins
fs.rmSync(userPluginsDir, { recursive: true, force: true });
fs.mkdirSync(userPluginsDir, { recursive: true });
const pluginEntries = fs.readdirSync(bundledPluginsDir, { withFileTypes: true });
for (const entry of pluginEntries) {
const srcPath = path.join(bundledPluginsDir, entry.name);
const destPath = path.join(userPluginsDir, entry.name);
fs.cpSync(srcPath, destPath, { recursive: true });
}
writePluginCopyMetadata(metadataFile, currentVersion);
console.log(`Bundled plugins copied successfully to ${userPluginsDir}.`);
} catch (err) {
console.error('Failed to copy bundled plugins:', err.message);
return false;
}
return true;
}
module.exports = {
copyBundledPlugins,
};
================================================
FILE: applications/electron/scripts/generate-app-update-yml.js
================================================
#!/usr/bin/env node
/********************************************************************************
* Copyright (C) 2026 STMicroelectronics and others.
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
*
* SPDX-License-Identifier: MIT
********************************************************************************/
// Generates app-update.yml for the Windows auto-updater.
//
// The normal electron-builder flow generates this file during afterPack, but
// only when the target is "nsis" or "appx". The Windows CI build splits
// packaging into two steps:
// 1. `electron-builder --dir` (target = "dir") → app-update.yml is skipped
// 2. `electron-builder --prepackaged` → afterPack does not run
//
// This script bridges that gap by writing the file before step 2.
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const electronDir = path.resolve(__dirname, '..');
const pkg = require(path.join(electronDir, 'package.json'));
const builderConfig = yaml.load(fs.readFileSync(path.join(electronDir, 'electron-builder.yml'), 'utf8'));
const winPublish = builderConfig.win.publish;
const version = pkg.version;
// Expand ${version} macro in the URL, matching electron-builder's macro expansion
const url = winPublish.url.replace('${version}', version);
const appUpdateYml = {
provider: winPublish.provider,
url,
...(winPublish.useMultipleRangeRequest !== undefined && { useMultipleRangeRequest: winPublish.useMultipleRangeRequest }),
updaterCacheDirName: `${pkg.name}-updater`
};
const outPath = path.join(electronDir, 'dist', 'win-unpacked', 'resources', 'app-update.yml');
fs.writeFileSync(outPath, yaml.dump(appUpdateYml, { lineWidth: -1 }));
console.log(`Generated ${outPath}`);
console.log(fs.readFileSync(outPath, 'utf8'));
================================================
FILE: applications/electron/scripts/notarize.sh
================================================
#!/bin/bash -x
INPUT=$1
APP_ID=$2
NEEDS_UNZIP=false
UUID_REGEX='"uuid"\s*:\s*"([^"]+)'
STATUS_REGEX='"status"\s*:\s*"([^"]+)'
# if folder, zip it
if [ -d "${INPUT}" ]; then
NEEDS_UNZIP=true
zip -r -q -y unsigned.zip "${INPUT}"
rm -rf "${INPUT}"
INPUT=unsigned.zip
fi
# copy file to storage server
scp -p "${INPUT}" genie.theia@projects-storage.eclipse.org:./
rm -f "${INPUT}"
# name to use on server
REMOTE_NAME=${INPUT##*/}
# notarize over ssh
RESPONSE=$(ssh -q genie.theia@projects-storage.eclipse.org curl -X POST -F file=@"\"${REMOTE_NAME}\"" -F "'options={\"primaryBundleId\": \"${APP_ID}\", \"staple\": true};type=application/json'" https://cbi.eclipse.org/macos/xcrun/notarize)
# fund uuid and status
[[ $RESPONSE =~ $UUID_REGEX ]]
UUID=${BASH_REMATCH[1]}
[[ $RESPONSE =~ $STATUS_REGEX ]]
STATUS=${BASH_REMATCH[1]}
# poll progress
echo " Progress: $RESPONSE"
while [[ $STATUS == 'IN_PROGRESS' ]]; do
sleep 120
RESPONSE=$(ssh -q genie.theia@projects-storage.eclipse.org curl -s https://cbi.eclipse.org/macos/xcrun/${UUID}/status)
[[ $RESPONSE =~ $STATUS_REGEX ]]
STATUS=${BASH_REMATCH[1]}
echo " Progress: $RESPONSE"
done
if [[ $STATUS != 'COMPLETE' ]]; then
echo "Notarization failed: $RESPONSE"
exit 1
fi
# download stapled result
ssh -q genie.theia@projects-storage.eclipse.org curl -o "\"stapled-${REMOTE_NAME}\"" https://cbi.eclipse.org/macos/xcrun/${UUID}/download
# copy stapled file back from server
scp -T -p genie.theia@projects-storage.eclipse.org:"\"./stapled-${REMOTE_NAME}\"" "${INPUT}"
# ensure storage server is clean
ssh -q genie.theia@projects-storage.eclipse.org rm -f "\"${REMOTE_NAME}\"" "\"stapled-${REMOTE_NAME}\"" entitlements.plist
# if unzip needed
if [ "$NEEDS_UNZIP" = true ]; then
unzip -qq "${INPUT}"
if [ $? -ne 0 ]; then
# echo contents if unzip failed
output=$(cat $INPUT)
echo "$output"
exit 1
fi
rm -f "${INPUT}"
fi
================================================
FILE: applications/electron/scripts/sign-directory-windows.ts
================================================
/********************************************************************************
* Copyright (C) 2026 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
*
* SPDX-License-Identifier: MIT
********************************************************************************/
import child_process from 'child_process';
import fs from 'fs';
import path from 'path';
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs/yargs';
import { formatBytes, replaceWithSigned, walkFiles } from './sign-utils';
/**
* Sign Windows binaries inside an electron-builder `--dir` output (`win-unpacked`) by uploading
* each `.exe` to the Eclipse Authenticode signing service and writing the signed result back in
* place. The traversal must mirror the roots that electron-builder's `winPackager.signApp()`
* would sign: the top level of the unpacked directory, `resources/app.asar.unpacked/` and
* `swiftshader/`. The filter (`.exe` only) matches electron-builder's default `shouldSignFile`
* when `win.signExts` is unset.
*/
const DEFAULT_SIGN_URL = 'https://cbi.eclipse.org/authenticode/sign';
const argv = yargs(hideBin(process.argv))
.option('directory', {
alias: 'd',
type: 'string',
demandOption: true,
description: 'The electron-builder `--dir` output directory (e.g. dist/win-unpacked) containing the unpacked Windows app'
})
.option('url', {
alias: 'u',
type: 'string',
default: DEFAULT_SIGN_URL,
description: 'The URL of the Authenticode signing service'
})
.version(false)
.wrap(120)
.parseSync();
function isExeFile(filePath: string): boolean {
return path.extname(filePath).toLowerCase() === '.exe';
}
/**
* Collect files to sign by reproducing electron-builder's `winPackager.signApp()` traversal:
* 1. Top-level files directly under `<dir>/` (no recursion)
* 2. Recursive walk of `<dir>/resources/app.asar.unpacked/`
* 3. Recursive walk of `<dir>/swiftshader/` (if present)
*/
function collectFilesToSign(unpackedDir: string): string[] {
const topLevel = walkFiles(unpackedDir, isExeFile, { shallow: true });
const asarUnpacked = walkFiles(path.join(unpackedDir, 'resources', 'app.asar.unpacked'), isExeFile);
const swiftshader = walkFiles(path.join(unpackedDir, 'swiftshader'), isExeFile);
return [...topLevel, ...asarUnpacked, ...swiftshader];
}
function signFile(file: string, url: string): void {
const signedPath = `${file}.signed`;
// Remove any stale signed file from a previous run
if (fs.existsSync(signedPath)) {
fs.unlinkSync(signedPath);
}
const before = fs.statSync(file);
console.log(`Signing ${file} (${formatBytes(before.size)})...`);
const started = Date.now();
const result = child_process.spawnSync(
'curl',
['-sSf', '-o', signedPath, '-F', `file=@${file}`, url],
{ stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf-8' }
);
const durationMs = Date.now() - started;
if (result.error) {
throw new Error(`Failed to invoke curl for ${file}: ${result.error.message}`);
}
if (result.status !== 0) {
// Dump whatever curl produced to help diagnose. If curl wrote a non-binary error payload to
// `signedPath` (e.g. an HTML/JSON error page from the signing service), log that too.
if (result.stdout) {
console.error(`curl stdout:\n${result.stdout}`);
}
if (result.stderr) {
console.error(`curl stderr:\n${result.stderr}`);
}
if (fs.existsSync(signedPath)) {
try {
const body = fs.readFileSync(signedPath, 'utf-8');
console.error(`Response body written to ${signedPath}:\n${body}`);
} catch {
// Ignore read errors on binary/garbage content
}
try {
fs.unlinkSync(signedPath);
} catch {
// Best-effort cleanup
}
}
throw new Error(`Signing failed for ${file}: curl exited with status ${result.status}`);
}
if (!fs.existsSync(signedPath)) {
throw new Error(`Signing failed for ${file}: no output file produced at ${signedPath}`);
}
const signedSize = fs.statSync(signedPath).size;
if (signedSize === 0) {
fs.unlinkSync(signedPath);
throw new Error(`Signing failed for ${file}: signed output is empty`);
}
replaceWithSigned(file, signedPath);
console.log(` -> signed in ${durationMs} ms (${formatBytes(signedSize)})`);
}
function main(): void {
const directory = path.resolve(argv.directory);
const url = argv.url;
if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {
console.error(`Directory does not exist or is not a directory: ${directory}`);
process.exit(1);
}
console.log(`sign-directory-windows: directory=${directory}; url=${url}`);
const files = collectFilesToSign(directory);
if (files.length === 0) {
// Having zero files usually means the app layout changed and our walk roots no longer
// match what electron-builder would sign. Fail so this is caught in CI rather than
// silently shipping an unsigned binary.
console.error(
`No .exe files found under ${directory} in any of the expected roots (top level, ` +
'resources/app.asar.unpacked, swiftshader). This likely indicates a change in the ' +
'electron-builder output layout that sign-directory-windows has not been updated for.'
);
process.exit(1);
}
console.log(`Found ${files.length} file(s) to sign:`);
for (const file of files) {
console.log(` - ${path.relative(directory, file)}`);
}
const overallStarted = Date.now();
for (const file of files) {
signFile(file, url);
}
const overallDuration = Date.now() - overallStarted;
console.log(`Signed ${files.length} file(s) in ${overallDuration} ms.`);
}
main();
================================================
FILE: applications/electron/scripts/sign-directory.ts
================================================
/********************************************************************************
* Copyright (C) 2025 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
*
* SPDX-License-Identifier: MIT
********************************************************************************/
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs/yargs';
import path from 'path';
import fs from 'fs';
import child_process from 'child_process';
import { walkFiles } from './sign-utils';
const signCommand = path.join(__dirname, 'sign.sh');
const notarizeCommand = path.join(__dirname, 'notarize.sh');
const entitlements = path.resolve(__dirname, '..', 'entitlements.plist');
// File extensions and patterns that need code signing on macOS
const BINARY_EXTENSIONS = ['.dylib', '.so', '.node', '.framework'];
const BINARY_PATTERNS = [
/^MacOS\//, // Executable files in MacOS directory
/^Contents\/MacOS\//, // Executable files in Contents/MacOS directory
];
const EXECUTABLE_NAMES = [
'node', 'electron', 'rg', 'macos-trash', 'chrome-sandbox'
];
// Function to check if a file is likely a binary that needs signing
function isBinaryFile(filePath: string): boolean {
const extension = path.extname(filePath);
const fileName = path.basename(filePath);
const relativePath = filePath.replace(/^.*?\.app\//, ''); // Get path relative to .app bundle
// Check by extension
if (BINARY_EXTENSIONS.includes(extension)) {
return true;
}
// Check by executable name
if (EXECUTABLE_NAMES.includes(fileName)) {
return true;
}
// Check by pattern
for (const pattern of BINARY_PATTERNS) {
if (pattern.test(relativePath)) {
return true;
}
}
// Check if file is executable (Unix-only check)
try {
const stat = fs.statSync(filePath);
if ((stat.mode & 0o111) !== 0) { // Check if execute bit is set
// Further verify it's a binary with 'file' command if available
try {
const fileType = child_process.execSync(`file "${filePath}"`).toString();
return fileType.includes('Mach-O') ||
fileType.includes('executable') ||
fileType.includes('shared library') ||
fileType.includes('dynamically linked');
} catch (e) {
// If 'file' command fails, fall back to assuming it's a binary if it has execute permission
return true;
}
}
} catch (e) {
// If stat fails, skip this check
}
return false;
}
// Function to recursively find binaries in a directory
function findBinariesToSign(dirPath: string): string[] {
const result = walkFiles(dirPath, isBinaryFile, { skipDirs: ['node_modules', '.git'] });
// Sort by path depth (deepest first) to ensure nested binaries are signed first
return result.sort((a, b) => {
const aDepth = a.split(path.sep).length;
const bDepth = b.split(path.sep).length;
return bDepth - aDepth;
});
}
const signFile = (file: string) => {
const stat = fs.lstatSync(file);
const mode = stat.isFile() ? stat.mode : undefined;
// Get SHA hash of file before signing - only for actual files, not directories
let shaBeforeSigning: string | undefined;
if (stat.isFile()) {
shaBeforeSigning = child_process.execSync(`shasum -a 256 "${file}"`).toString().trim();
}
console.log(`Signing ${file}...`);
child_process.spawnSync(signCommand, [
path.basename(file),
entitlements
], {
cwd: path.dirname(file),
maxBuffer: 1024 * 10000,
env: process.env,
stdio: 'inherit',
encoding: 'utf-8'
});
// Get SHA hash of file after signing - only for actual files, not directories
if (stat.isFile()) {
const shaAfterSigning = child_process.execSync(`shasum -a 256 "${file}"`).toString().trim();
// Log a warning if the SHA hash hasn't changed after signing
if (shaBeforeSigning === shaAfterSigning) {
console.warn(`WARNING: SHA hash did not change after signing for ${file}. This might indicate the file was not properly signed.`);
}
}
if (mode) {
console.log(`Setting attributes of ${file}...`);
fs.chmodSync(file, mode);
}
};
const argv = yargs(hideBin(process.argv))
.option('directory', { alias: 'd', type: 'string', default: 'dist', description: 'The directory which contains the application to be signed' })
.version(false)
.wrap(120)
.parseSync();
execute();
async function execute(): Promise<void> {
console.log(`signCommand: ${signCommand}; notarizeCommand: ${notarizeCommand}; entitlements: ${entitlements}; directory: ${argv.directory}`);
// First sign all individual binaries inside the app bundle
const binariesToSign = findBinariesToSign(argv.directory);
for (const binaryPath of binariesToSign) {
signFile(binaryPath);
}
// Then sign the main app bundle
console.log('Signing main application bundle...');
signFile(argv.directory);
// Notarize app
console.log('Notarizing application...');
child_process.spawnSync(notarizeCommand, [
path.basename(argv.directory),
'eclipse.theia'
], {
cwd: path.dirname(argv.directory),
maxBuffer: 1024 * 10000,
env: process.env,
stdio: 'inherit',
encoding: 'utf-8'
});
}
================================================
FILE: applications/electron/scripts/sign-utils.ts
================================================
/********************************************************************************
* Copyright (C) 2026 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
*
* SPDX-License-Identifier: MIT
********************************************************************************/
import fs from 'fs';
import path from 'path';
export interface WalkOptions {
/** Directory names to skip entirely while recursing (e.g. `['node_modules', '.git']`). */
skipDirs?: string[];
/** If true, do not recurse into subdirectories - only list direct children. Default: false. */
shallow?: boolean;
}
/**
* Recursively walks `root` and returns all file paths for which `filter` returns `true`.
* If `root` does not exist, returns an empty array.
*/
export function walkFiles(root: string, filter: (file: string) => boolean, opts: WalkOptions = {}): string[] {
const result: string[] = [];
if (!fs.existsSync(root)) {
return result;
}
const skipDirs = new Set(opts.skipDirs ?? []);
const visit = (currentPath: string): void => {
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentPath, entry.name);
if (entry.isDirectory()) {
if (skipDirs.has(entry.name)) {
continue;
}
if (opts.shallow) {
continue;
}
visit(fullPath);
} else if (entry.isFile() && filter(fullPath)) {
result.push(fullPath);
}
}
};
visit(root);
return result;
}
/**
* Replaces `originalPath` with `signedPath` on disk, preserving the file mode of the original.
* On POSIX `renameSync` atomically replaces the destination, so no separate unlink is needed.
*/
export function replaceWithSigned(originalPath: string, signedPath: string): void {
const originalMode = fs.statSync(originalPath).mode;
fs.renameSync(signedPath, originalPath);
fs.chmodSync(originalPath, originalMode);
}
/** Format a byte count as a human-readable string (e.g. `12.3 MB`). */
export function formatBytes(bytes: number): string {
if (!Number.isFinite(bytes) || bytes < 0) {
return `${bytes}`;
}
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let value = bytes;
let unitIndex = 0;
while (value >= 1024 && unitIndex < units.length - 1) {
value /= 1024;
unitIndex++;
}
return `${value.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
}
================================================
FILE: applications/electron/scripts/sign.sh
================================================
#!/bin/bash -x
# Enable debug output
set -x
INPUT=$1
ENTITLEMENTS=$2
NEEDS_UNZIP=false
echo "=== DEBUG: Starting signing process for $INPUT ==="
# if folder, zip it
if [ -d "${INPUT}" ]; then
echo "=== DEBUG: Input is a directory, zipping it ==="
NEEDS_UNZIP=true
zip -r -q -y unsigned.zip "${INPUT}"
rm -rf "${INPUT}"
INPUT=unsigned.zip
fi
# copy file to storage server
echo "=== DEBUG: Copying $INPUT to storage server ==="
scp -p "${INPUT}" genie.theia@projects-storage.eclipse.org:./
if [ $? -eq 0 ]; then
echo "=== DEBUG: Successfully copied $INPUT to storage server ==="
else
echo "=== ERROR: Failed to copy $INPUT to storage server ==="
exit 1
fi
rm -f "${INPUT}"
# copy entitlements to storage server
echo "=== DEBUG: Copying entitlements file to storage server ==="
scp -p "${ENTITLEMENTS}" genie.theia@projects-storage.eclipse.org:./entitlements.plist
if [ $? -eq 0 ]; then
echo "=== DEBUG: Successfully copied entitlements to storage server ==="
else
echo "=== ERROR: Failed to copy entitlements to storage server ==="
exit 1
fi
# name to use on server
REMOTE_NAME=${INPUT##*/}
# sign over ssh
# https://wiki.eclipse.org/IT_Infrastructure_Doc#Web_service
ssh -q genie.theia@projects-storage.eclipse.org curl -f -o "\"signed-${REMOTE_NAME}\"" -F file=@"\"${REMOTE_NAME}\"" -F entitlements=@entitlements.plist https://cbi.eclipse.org/macos/codesign/sign
if [ $? -eq 0 ]; then
echo "=== DEBUG: Remote signing completed successfully ==="
else
echo "=== ERROR: Remote signing failed ==="
# Try to get error information
ssh -q genie.theia@projects-storage.eclipse.org "cat \"signed-${REMOTE_NAME}\" || echo 'No output file found'"
exit 1
fi
# copy signed file back from server
echo "=== DEBUG: Copying signed file back from storage server ==="
scp -T -p genie.theia@projects-storage.eclipse.org:"\"./signed-${REMOTE_NAME}\"" "${INPUT}"
if [ $? -eq 0 ]; then
echo "=== DEBUG: Successfully retrieved signed file ==="
else
echo "=== ERROR: Failed to retrieve signed file ==="
exit 1
fi
# Check if the file was actually signed
echo "=== DEBUG: Verifying if file was signed properly ==="
if [ -f "${INPUT}" ]; then
# Get file size to verify it's not empty
FILE_SIZE=$(stat -f%z "${INPUT}" 2>/dev/null || stat -c%s "${INPUT}" 2>/dev/null)
echo "=== DEBUG: Signed file size: $FILE_SIZE bytes ==="
# On macOS, we can verify code signature
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "=== DEBUG: Checking code signature with codesign -vv ==="
codesign -vv "${INPUT}" || echo "=== WARNING: codesign verification failed ==="
fi
else
echo "=== ERROR: Signed file not found ==="
exit 1
fi
# ensure storage server is clean
echo "=== DEBUG: Cleaning up remote files ==="
ssh -q genie.theia@projects-storage.eclipse.org rm -f "\"${REMOTE_NAME}\"" "\"signed-${REMOTE_NAME}\"" entitlements.plist
echo "=== DEBUG: Remote cleanup completed ==="
# if unzip needed
if [ "$NEEDS_UNZIP" = true ]; then
echo "=== DEBUG: Unzipping signed archive ==="
unzip -qq "${INPUT}"
if [ $? -ne 0 ]; then
# echo contents if unzip failed
echo "=== ERROR: Unzip failed, showing file contents ==="
output=$(cat $INPUT)
echo "$output"
exit 1
fi
echo "=== DEBUG: Unzip successful, removing zip file ==="
rm -f "${INPUT}"
# Perform deep codesign check on the directory if running on macOS
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "=== DEBUG: Performing deep codesign verification on directory ==="
# Check if spctl is available (macOS security assessment tool)
if command -v spctl &> /dev/null; then
# Check if the directory is an app bundle
if [[ -d "$1" && "$1" == *.app ]]; then
echo "=== DEBUG: Verifying app bundle with spctl --assess --verbose ==="
spctl --assess --verbose "$1" || echo "=== WARNING: App bundle verification failed, may not pass notarization ==="
fi
fi
# Find all binary files and check their signatures
echo "=== DEBUG: Checking individual binary signatures in $1 ==="
find "$1" -type f -exec file {} \; | grep -E "Mach-O|dylib" | cut -d: -f1 | while read binary; do
echo "Checking signature for $binary"
codesign --verify --deep --strict --verbose=2 "$binary" || echo "=== WARNING: Binary $binary has signature issues, may not pass notarization ==="
# Check for hardened runtime
codesign -d --verbose=4 "$binary" 2>&1 | grep -q 'Runtime Version=10.0.0' || echo "=== WARNING: Binary $binary may not have hardened runtime enabled ==="
done
fi
fi
echo "=== DEBUG: Signing process completed for $1 ==="
================================================
FILE: applications/electron/scripts/theia-electron-main.js
================================================
const path = require('path');
const fs = require('fs');
const os = require('os');
const { copyBundledPlugins } = require('./appimage-helpers');
// Update to override the supported VS Code API version.
// process.env.VSCODE_API_VERSION = '1.50.0'
// Detect if running as AppImage
const isAppImage = !!process.env.APPIMAGE;
// When packaged with asar, __dirname is inside app.asar (e.g., .../app.asar/scripts)
// but plugins are in extraResources at .../app/plugins (outside the asar)
const isInsideAsar = __dirname.includes('.asar');
const bundledPluginsDir = isInsideAsar
? path.join(process.resourcesPath, 'app', 'plugins')
: path.resolve(__dirname, '../', 'plugins');
if (isAppImage) {
// When running as AppImage, use a user-writable directory for the built-in plugins
// The AppImage mount point (/tmp/.mount_*) is read-only
const configDir = process.env.THEIA_CONFIG_DIR || path.join(os.homedir(), '.theia-ide');
const userPluginsDir = path.join(configDir, 'builtInPlugins');
const packageJsonPath = path.resolve(__dirname, '../', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const currentVersion = packageJson.version;
// Copy bundled plugins to user directory if needed (first run or version update)
const useUserDir = copyBundledPlugins(bundledPluginsDir, userPluginsDir, currentVersion);
// If copying fails, fall back to the read-only bundled directory (will be improved in follow up of GH-630)
process.env.THEIA_DEFAULT_PLUGINS = `local-dir:${useUserDir ? userPluginsDir : bundledPluginsDir}`;
} else {
// Use a set of builtin plugins in our application.
process.env.THEIA_DEFAULT_PLUGINS = `local-dir:${bundledPluginsDir}`;
}
// Handover to the auto-generated electron application handler.
require('../lib/backend/electron-main.js');
================================================
FILE: applications/electron/scripts/update-blockmap.ts
================================================
/********************************************************************************
* Copyright (C) 2023 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
*
* SPDX-License-Identifier: MIT
********************************************************************************/
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs/yargs';
import { executeAppBuilderAsJson } from 'app-builder-lib/out/util/appBuilder';
// eslint-disable-next-line import/no-extraneous-dependencies
import { BlockMapDataHolder } from 'builder-util-runtime';
import { rmSync } from 'fs';
import * as path from 'path';
const BLOCK_MAP_FILE_SUFFIX = '.blockmap';
const argv = yargs(hideBin(process.argv))
.option('executable', { alias: 'e', type: 'string', default: 'TheiaIDE.exe', description: 'The executable for which the blockmap needs to be updated' })
.version(false)
.wrap(120)
.parseSync();
execute();
async function execute(): Promise<void> {
const executable = argv.executable;
const executablePath = path.resolve(
__dirname,
'../dist/',
executable
);
const blockMapFile = `${executablePath}${BLOCK_MAP_FILE_SUFFIX}`;
console.log(`Exe: ${executablePath}; Blockmap: ${blockMapFile}`);
rmSync(blockMapFile, {
force: true,
});
await executeAppBuilderAsJson<BlockMapDataHolder>(['blockmap', '--input', executablePath, '--output', blockMapFile]);
};
================================================
FILE: applications/electron/scripts/update-checksum.ts
================================================
/********************************************************************************
* Copyright (C) 2021 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
*
* SPDX-License-Identifier: MIT
********************************************************************************/
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as jsyaml from 'js-yaml';
import * as path from 'path';
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs/yargs';
const argv = yargs(hideBin(process.argv))
.option('executable', { alias: 'e', type: 'string', default: 'TheiaIDE.AppImage', description: 'The executable for which the checksum needs to be updated' })
.option('yaml', { alias: 'y', type: 'string', default: 'latest-linux.yml', description: 'The yaml file where the checksum needs to be updated' })
.option('platform', { alias: 'p', type: 'string', default: 'linux', description: 'The OS platform' })
.option('updatepaths', { alias: 'u', type: 'boolean', default: true, description: 'Whether to update the paths from absolute to relative' })
.option('fileextension', { alias: 'f', type: 'string', default: '.AppImage', description: 'Only paths/urls with this extension will be updated' })
.version(false)
.wrap(120)
.parseSync();
execute();
async function execute(): Promise<void> {
const executable = argv.executable;
const yaml = argv.yaml;
const platform = argv.platform;
const updatePaths = argv.updatepaths;
const fileExtension = argv.fileextension;
const executablePath = path.resolve(
__dirname,
'../dist/',
executable
);
const yamlPath = path.resolve(
__dirname,
'../dist/',
yaml
);
console.log(`Exe: ${executablePath}; Yaml: ${yamlPath}; Platform: ${platform}; Update Paths: ${updatePaths}; File Extension: ${fileExtension}`);
const hash = await hashFile(executablePath, 'sha512', 'base64', {});
const size = fs.statSync(executablePath).size;
const yamlContents: string = fs.readFileSync(yamlPath, { encoding: 'utf8' });
console.log(`Initial Yaml Contents: ${yamlContents}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const latestYaml: any = jsyaml.safeLoad(yamlContents);
if (latestYaml.path.endsWith(fileExtension)) {
latestYaml.sha512 = hash;
if (updatePaths) {
latestYaml.path = updatedPath(latestYaml.path, latestYaml.version, platform);
}
}
for (const file of latestYaml.files) {
if (file.url.endsWith(fileExtension)) {
file.sha512 = hash;
file.size = size;
if (updatePaths) {
file.url = updatedPath(file.url, latestYaml.version, platform);
}
}
}
// line width -1 to avoid adding >- on long strings like a hash
const newYamlContents = jsyaml.dump(latestYaml, { lineWidth: -1 });
console.log(`New Yaml Contents: ${newYamlContents}`);
fs.writeFileSync(yamlPath, newYamlContents);
}
function hashFile(file: fs.PathLike, algorithm = 'sha512', encoding: BufferEncoding = 'base64', options: string | {
flags?: string;
encoding?: BufferEncoding;
fd?: number;
mode?: number;
autoClose?: boolean;
emitClose?: boolean;
start?: number;
end?: number;
highWaterMark?: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}): Promise<any> {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(algorithm);
hash.on('error', reject).setEncoding(encoding);
fs.createReadStream(
file,
Object.assign({}, options, {
highWaterMark: 1024 * 1024,
})
)
.on('error', reject)
.on('end', () => {
hash.end();
resolve(hash.read());
})
.pipe(
hash,
{
end: false,
}
);
});
}
function updatedPath(toUpdate: string, version: string, platform: string): string {
const extensionIndex = toUpdate.lastIndexOf('.');
return '../../' + version + '/' + platform + '/' + toUpdate.substring(0, extensionIndex) + '-' + version + toUpdate.substring(extensionIndex);
}
================================================
FILE: applications/electron/test/app.spec.js
================================================
const os = require('os');
const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');
const { remote } = require('webdriverio');
const { expect } = require('chai');
const THEIA_LOAD_TIMEOUT = 15000; // 15 seconds
// Set environment variable to disable splash screen (works with asar packaging)
process.env.THEIA_NO_SPLASH = '1';
// Resolve the application directory from cwd so this spec can be shared across products
const appDir = process.cwd();
// Directory for saving screenshots on failure or for debugging
const screenshotDir = path.join(appDir, 'test-screenshots');
if (!fs.existsSync(screenshotDir)) {
fs.mkdirSync(screenshotDir, { recursive: true });
}
async function saveScreenshot(browser, name) {
try {
const filePath = path.join(screenshotDir, `${name}.png`);
await browser.saveScreenshot(filePath);
console.log(`Screenshot saved: ${filePath}`);
} catch (err) {
console.error(`Failed to save screenshot "${name}":`, err.message);
}
}
const builderConfig = fs.readFileSync(path.join(appDir, 'electron-builder.yml'), 'utf8');
const productName = builderConfig.match(/^productName:\s*(.+)$/m)[1].trim();
const packageName = require(path.join(appDir, 'package.json')).name;
function isMacArm() {
if (os.platform() !== 'darwin') {
return false;
}
try {
// Check the architecture using uname -m
const arch = execSync('uname -m').toString().trim();
return arch === 'arm64';
} catch (error) {
// Fall back to node's arch property if uname fails
return os.arch() === 'arm64';
}
}
function getBinaryPath() {
const distFolder = path.join(appDir, 'dist');
switch (os.platform()) {
case 'linux':
return path.join(distFolder, 'linux-unpacked', packageName);
case 'win32':
return path.join(distFolder, 'win-unpacked', `${productName}.exe`);
case 'darwin':
const macFolder = isMacArm() ? 'mac-arm64' : 'mac';
const binaryPath = path.join(
distFolder, macFolder, `${productName}.app`, 'Contents', 'MacOS', productName
);
console.log(`Using binary path for Mac ${isMacArm() ? 'ARM64' : 'Intel'}: ${binaryPath}`);
return binaryPath;
default:
return undefined;
}
};
// Utility for keyboard shortcuts that execute commands where
// the key combination is the same on all platforms *except that*
// the Command key is used instead of Control on MacOS. Note that
// sometimes MacOS also uses Control. This is not handled, here
function macSafeKeyCombo(keys) {
if (os.platform() === 'darwin' && keys.includes('Control')) {
// Puppeteer calls the Command key "Meta"
return keys.map(k => k === 'Control' ? 'Meta' : k);
}
return keys;
};
describe('Theia App', function () {
// In mocha, 'this' is a common context between sibling beforeEach, afterEach, it, etc methods within the same describe.
// Each describe has its own context.
beforeEach(async function () {
const binary = getBinaryPath();
if (!binary) {
throw new Error('Tests are not supported for this platform.');
}
// Start app and store connection in context (this)
this.browser = await remote({
// Change to info to get detailed events of webdriverio
logLevel: 'info',
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
// Path to built and packaged theia
binary: binary,
// Hand in workspace to load as runtime parameter
args: [path.join(appDir, 'test', 'workspace')],
},
},
});
const appShell = await this.browser.$('#theia-app-shell');
// mocha waits for returned promise to resolve
// Theia is loaded once the app shell is present
await appShell.waitForExist({
timeout: THEIA_LOAD_TIMEOUT,
timeoutMsg: 'Theia took too long to load.',
});
// If workspace trust dialog appears, trust the workspace
const dialog = await this.browser.$('.dialogOverlay.workspace-trust-dialog');
const dialogAppeared = await dialog.waitForExist({ timeout: 5000 }).catch(() => false);
if (dialogAppeared) {
// Click the main action button to trust the workspace
const trustButton = await this.browser.$('.dialogOverlay.workspace-trust-dialog .dialogControl button.theia-button.main');
const buttonClickable = await trustButton.waitForClickable({ timeout: 2000 }).catch(() => false);
if (buttonClickable) {
await trustButton.click();
// Wait for dialog to close
await dialog.waitForExist({ timeout: 2000, reverse: true }).catch(() => { });
}
}
});
afterEach(async function () {
// Save screenshot on test failure for debugging CI issues
if (this.currentTest.state === 'failed') {
const testName = this.currentTest.title.replace(/\s+/g, '-').toLowerCase();
await saveScreenshot(this.browser, `FAILED-${testName}`);
}
const CLOSE_TIMEOUT = 10000; // 10 seconds
try {
await Promise.race([
this.browser.closeWindow(),
new Promise(resolve => setTimeout(resolve, CLOSE_TIMEOUT))
]);
} catch (err) {
// Workaround: Puppeteer cannot properly connect to electron and throws an error.
// However, the window is closed and that's all we want here.
if (`${err}`.includes('Protocol error (Target.createTarget)')) {
return;
}
// Rethrow for unexpected errors to fail test.
throw err;
}
});
it('Correct window title', async function () {
// Wait a bit to make sure workspace is set and title got updated
await new Promise(r => setTimeout(r, 2000));
const windowTitle = await this.browser.getTitle();
expect(windowTitle).to.include('workspace');
});
it('Builtin extensions', async function () {
// Wait a bit to make sure key handlers are registered.
await new Promise(r => setTimeout(r, 5000));
// Open extensions view
await this.browser.keys(macSafeKeyCombo(['Control', 'Shift', 'x']));
const builtinContainer = await this.browser.$(
'#vsx-extensions-view-container--vsx-extensions\\:builtin'
);
// Expand builtin extensions
const builtinHeader = await builtinContainer.$('.theia-header.header');
await builtinHeader.moveTo({ xOffset: 1, yOffset: 1 });
await builtinHeader.waitForDisplayed();
await builtinHeader.waitForClickable();
await builtinHeader.click();
// Wait for expansion to finish (plugins may take time to scan, especially with asar packaging)
const builtin = await this.browser.$(
'#vsx-extensions\\:builtin .theia-TreeContainer'
);
await builtin.waitForExist({ timeout: 10000 });
// Get names of all builtin extensions
const extensions = await builtin.$$('.theia-vsx-extension .name');
const extensionNames = await Promise.all(
extensions.map(e => e.getText())
);
// Exemplary check a few extensions
expect(extensionNames).to.include('Debugger for Java');
expect(extensionNames).to.include('TypeScript and JavaScript Language Features (built-in)');
});
it('Search in workspace', async function () {
// Wait a bit to make sure key handlers are registered
await new Promise(r => setTimeout(r, 5000));
// Open search view (Ctrl+Shift+F)
await this.browser.keys(macSafeKeyCombo(['Control', 'Shift', 'f']));
// Wait for search input to appear
const searchInput = await this.browser.$('#search-input-field');
await searchInput.waitForExist({ timeout: 5000 });
await searchInput.waitForDisplayed();
// Search for text that exists in the test workspace README.md
await searchInput.setValue('Test Workspace');
// Wait for search results to appear
const searchResults = await this.browser.$('.t-siw-search-container .resultLine');
await searchResults.waitForExist({ timeout: 10000, timeoutMsg: 'Search results did not appear. Ripgrep may not be working correctly with asar packaging.' });
// Verify we got results
const resultsText = await searchResults.getText();
expect(resultsText).to.include('Test Workspace');
});
it('Quick file open', async function () {
// Wait a bit to make sure key handlers are registered
await new Promise(r => setTimeout(r, 5000));
// Open quick file picker (Ctrl+P)
await this.browser.keys(macSafeKeyCombo(['Control', 'p']));
// Wait for quick input to appear
const quickInput = await this.browser.$('.quick-input-widget');
await quickInput.waitForExist({ timeout: 5000 });
await quickInput.waitForDisplayed();
// Type filename to search for
const inputBox = await this.browser.$('.quick-input-box input');
await inputBox.waitForExist({ timeout: 5000 });
await inputBox.setValue('README');
// Wait for file to appear in results
const fileResult = await this.browser.$('.quick-input-list-row');
await fileResult.waitForExist({ timeout: 10000, timeoutMsg: 'Quick file open results did not appear. Ripgrep may not be working correctly with asar packaging.' });
// Verify README.md appears in results
const resultLabel = await this.browser.$('.quick-input-list-label');
const labelText = await resultLabel.getText();
expect(labelText.toLowerCase()).to.include('readme');
});
it('Integrated terminal', async function () {
// Wait a bit to make sure key handlers are registered
await new Promise(r => setTimeout(r, 5000));
// Create a new terminal (Ctrl+Shift+`) to ensure it is focused and visible,
// even when the terminal manager uses tabbed layout in the bottom panel.
await this.browser.keys(['Control', 'Shift', '`']);
// Wait for terminal widget to appear
const terminal = await this.browser.$('.xterm');
await terminal.waitForExist({ timeout: 10000, timeoutMsg: 'Terminal did not open. PTY may not be working correctly with asar packaging.' });
await terminal.waitForDisplayed();
// Verify terminal is visible
const isDisplayed = await terminal.isDisplayed();
expect(isDisplayed).to.equal(true);
});
});
================================================
FILE: applications/electron/test/workspace/README.md
================================================
# Test Workspace
This is the test workspace for E2E tests.
================================================
FILE: applications/electron/tsconfig.eslint.json
================================================
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true
},
"include": [
"./scripts",
"./test"
]
}
================================================
FILE: applications/electron/tsconfig.json
================================================
{
"extends": "../../configs/base.tsconfig",
"include": [],
"compilerOptions": {
"composite": true,
"esModuleInterop": true
},
"references": [
{
"path": "../../theia-extensions/launcher"
},
{
"path": "../../theia-extensions/product"
},
{
"path": "../../theia-extensions/updater"
}
]
}
================================================
FILE: applications/electron/webpack.config.js
================================================
/**
* This file can be edited to customize webpack configuration.
* To reset delete this file and rerun theia build again.
*/
// @ts-check
const configs = require('./gen-webpack.config.js');
const nodeConfig = require('./gen-webpack.node.config.js');
const TerserPlugin = require('terser-webpack-plugin');
const fs = require('fs');
const path = require('path');
/**
* Webpack plugin to patch the bundled ripgrep path for asar compatibility.
* When packaged with asar, __dirname resolves inside app.asar but the native binaries
* are extracted to app.asar.unpacked via asarUnpack.
*
* The native-webpack-plugin bundles ripgrep path resolution directly into main.js,
* so we need to patch the bundle after emit to add asar path rewriting.
*/
class PatchRipgrepPlugin {
apply(compiler) {
compiler.hooks.afterEmit.tapAsync('PatchRipgrepPlugin', (compilation, callback) => {
const mainJsPath = path.join(compiler.outputPath, 'main.js');
if (fs.existsSync(mainJsPath)) {
let content = fs.readFileSync(mainJsPath, 'utf8');
// Match the ripgrep path.join(__dirname, ...) call regardless of how
// the path module is referenced or how the result is exported.
// Webpack output varies across modes:
// Production (minified): i.join(__dirname,"./native/rg"+("win32"===...))
// Dev (harmony): (__webpack_require__(/*! path */ "path").join)(__dirname, `./native/rg${...}`)
// Dev (CommonJS): path.join(__dirname, `./native/rg${...}`)
// The .join call may be direct (EXPR.join(...)) or parenthesized ((EXPR.join)(...)).
// Both string concat (prod) and template literal (dev) arg forms are matched.
const rgSuffix = `("win32"===process.platform?".exe":"")`;
const prodArgs = /["']\.\/native\/rg["']\s*\+\s*\(["']win32["']\s*===\s*process\.platform\s*\?\s*["']\.exe["']\s*:\s*["']["']\s*\)/;
const devArgs = /`\.\/native\/rg\$\{process\.platform\s*===\s*['"]win32['"]\s*\?\s*['"]\.exe['"]\s*:\s*['"]['"]}\s*`/;
// Match both EXPR.join(__dirname, ARGS) and (EXPR.join)(__dirname, ARGS)
// Use [^=,;\n] (not \s) to allow spaces in webpack comments like /*! path */
const joinCall = (argsPattern) => new RegExp(`\\(?[^=,;\\n]+?\\.join\\)?\\(\\s*__dirname\\s*,\\s*${argsPattern.source}\\s*\\)`, 'g');
const prodPattern = joinCall(prodArgs);
const devPattern = joinCall(devArgs);
let patched = false;
const patchFn = (match) => {
patched = true;
return `(()=>{const _p=require("path"),_r=_p.join(__dirname,"./native/rg"+${rgSuffix});return _r.includes(".asar"+_p.sep)?_r.replace(".asar"+_p.sep,".asar.unpacked"+_p.sep):_r})()`;
};
let newContent = content.replace(prodPattern, patchFn);
if (!patched) {
newContent = content.replace(devPattern, patchFn);
}
if (patched) {
fs.writeFileSync(mainJsPath, newContent);
console.log('Patched main.js ripgrep path for asar compatibility');
} else {
const idx = content.indexOf('rgPath');
if (idx !== -1) {
console.error('Could not patch ripgrep path. Context around rgPath:');
console.error(content.substring(Math.max(0, idx - 200), idx + 300));
}
throw new Error('Could not find ripgrep pattern to patch in main.js. The pattern may have changed in @theia/native-webpack-plugin.');
}
}
callback();
});
}
}
/**
* Expose bundled modules on window.theia.moduleName namespace, e.g.
* window['theia']['@theia/core/lib/common/uri'].
* Such syntax can be used by external code, for instance, for testing.
configs[0].module.rules.push({
test: /\.js$/,
loader: require.resolve('@theia/application-manager/lib/expose-loader')
}); */
/**
* Do no run TerserPlugin with parallel: true
* Each spawned node may take the full memory configured via NODE_OPTIONS / --max_old_space_size
* In total this may lead to OOM issues
*/
if (nodeConfig.config.optimization) {
nodeConfig.config.optimization.minimizer = [
new TerserPlugin({
parallel: false,
exclude: /^(lib|builtins)\//,
terserOptions: {
keep_classnames: /AbortSignal/
}
})
];
}
for (const config of configs) {
config.optimization = {
minimizer: [
new TerserPlugin({
parallel: false
})
]
};
}
// Add the ripgrep patch plugin to the node config
nodeConfig.config.plugins = nodeConfig.config.plugins || [];
nodeConfig.config.plugins.push(new PatchRipgrepPlugin());
module.exports = [
...configs,
nodeConfig.config
];
================================================
FILE: applications/electron-next/.eslintrc.js
================================================
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: [
'../../configs/build.eslintrc.json'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.eslint.json'
}
};
================================================
FILE: applications/electron-next/electron-builder.yml
================================================
appId: eclipse.theia.next
productName: TheiaIDENext
copyright: Copyright © 2020-2025 Eclipse Foundation, Inc
electronDist: ../../node_modules/electron/dist
electronVersion: 39.8.7
asar: true
asarUnpack:
- "**/lib/backend/native/**"
- "**/lib/backend/shell-integrations/**"
- "**/lib/build/Release/**"
- "**/lib/prebuilds/**"
nodeGypRebuild: false
npmRebuild: false
directories:
buildResources: resources
# node_modules and package.json are copied automatically
# Exclude node_modules manually because electron is copied by electron-builder and we are using a bundled backend
files:
- src-gen
- lib
- resources/icons/WindowIcon/512-512.png
- resources/TheiaIDENextSplash.svg
- scripts
- "!**node_modules/**"
extraResources:
- from: ../../plugins
to: app/plugins
linux:
icon: resources/icons/LinuxLauncherIcons
category: Development
mimeTypes:
- inode/directory
vendor: Eclipse Foundation, Inc
target:
- deb
- AppImage
deb:
artifactName: ${productName}.${ext}
appImage:
artifactName: ${productName}.${ext}
afterPack: ./scripts/after-pack.js
================================================
FILE: applications/electron-next/package.json
================================================
{
"private": true,
"name": "theia-ide-next-electron-app",
"description": "Eclipse Theia IDE Next product",
"productName": "Theia IDE Next",
"version": "1.71.100",
"main": "scripts/theia-electron-main.js",
"license": "MIT",
"author": "Eclipse Theia <theia-dev@eclipse.org>",
"homepage": "https://github.com/eclipse-theia/theia-ide#readme",
"bugs": {
"url": "https://github.com/eclipse-theia/theia/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/eclipse-theia/theia-ide.git"
},
"engines": {
"yarn": ">=1.7.0 <2",
"node": ">=22"
},
"theia": {
"target": "electron",
"frontend": {
"config": {
"applicationName": "Theia IDE Next",
"brandingVariant": "next",
"availableUpdateChannels": [
"next"
],
"reloadOnReconnect": true,
"preferences": {
"toolbar.showToolbar": true,
"updates.channel": "next",
"ai-features.chat.tokenUsageIndicator.enabled": true
},
"electron": {
"uriScheme": "theia-next",
"showWindowEarly": false,
"splashScreenOptions": {
"content": "resources/TheiaIDENextSplash.svg",
"height": 276,
"width": 446
}
}
}
},
"backend": {
"config": {
"frontendConnectionTimeout": -1,
"startupTimeout": -1,
"resolveSystemPlugins": false,
"configurationFolder": ".theia-ide-next"
}
},
"generator": {
"config": {
"preloadTemplate": "./resources/preload.html"
}
}
},
"dependencies": {
"@theia/ai-anthropic": "1.72.0-next.20",
"@theia/ai-chat": "1.72.0-next.20",
"@theia/ai-chat-ui": "1.72.0-next.20",
"@theia/ai-claude-code": "1.72.0-next.20",
"@theia/ai-code-completion": "1.72.0-next.20",
"@theia/ai-codex": "1.72.0-next.20",
"@theia/ai-copilot": "1.72.0-next.20",
"@theia/ai-core": "1.72.0-next.20",
"@theia/ai-core-ui": "1.72.0-next.20",
"@theia/ai-editor": "1.72.0-next.20",
"@theia/ai-google": "1.72.0-next.20",
"@theia/ai-history": "1.72.0-next.20",
"@theia/ai-huggingface": "1.72.0-next.20",
"@theia/ai-ide": "1.72.0-next.20",
"@theia/ai-llamafile": "1.72.0-next.20",
"@theia/ai-mcp": "1.72.0-next.20",
"@theia/ai-mcp-server": "1.72.0-next.20",
"@theia/ai-mcp-ui": "1.72.0-next.20",
"@theia/ai-ollama": "1.72.0-next.20",
"@theia/ai-openai": "1.72.0-next.20",
"@theia/ai-scanoss": "1.72.0-next.20",
"@theia/ai-terminal": "1.72.0-next.20",
"@theia/ai-vercel-ai": "1.72.0-next.20",
"@theia/bulk-edit": "1.72.0-next.20",
"@theia/callhierarchy": "1.72.0-next.20",
"@theia/collaboration": "1.72.0-next.20",
"@theia/console": "1.72.0-next.20",
"@theia/core": "1.72.0-next.20",
"@theia/debug": "1.72.0-next.20",
"@theia/dev-container": "1.72.0-next.20",
"@theia/editor": "1.72.0-next.20",
"@theia/editor-preview": "1.72.0-next.20",
"@theia/electron": "1.72.0-next.20",
"@theia/external-terminal": "1.72.0-next.20",
"@theia/file-search": "1.72.0-next.20",
"@theia/filesystem": "1.72.0-next.20",
"@theia/getting-started": "1.72.0-next.20",
"@theia/keymaps": "1.72.0-next.20",
"@theia/markers": "1.72.0-next.20",
"@theia/memory-inspector": "1.72.0-next.20",
"@theia/messages": "1.72.0-next.20",
"@theia/metrics": "1.72.0-next.20",
"@theia/mini-browser": "1.72.0-next.20",
"@theia/monaco": "1.72.0-next.20",
"@theia/navigator": "1.72.0-next.20",
"@theia/notebook": "1.72.0-next.20",
"@theia/outline-view": "1.72.0-next.20",
"@theia/output": "1.72.0-next.20",
"@theia/plugin-dev": "1.72.0-next.20",
"@theia/plugin-ext": "1.72.0-next.20",
"@theia/plugin-ext-vscode": "1.72.0-next.20",
"@theia/preferences": "1.72.0-next.20",
"@theia/preview": "1.72.0-next.20",
"@theia/process": "1.72.0-next.20",
"@theia/property-view": "1.72.0-next.20",
"@theia/remote": "1.72.0-next.20",
"@theia/remote-wsl": "1.72.0-next.20",
"@theia/scanoss": "1.72.0-next.20",
"@theia/scm": "1.72.0-next.20",
"@theia/search-in-workspace": "1.72.0-next.20",
"@theia/secondary-window": "1.72.0-next.20",
"@theia/task": "1.72.0-next.20",
"@theia/terminal": "1.72.0-next.20",
"@theia/terminal-manager": "1.72.0-next.20",
"@theia/test": "1.72.0-next.20",
"@theia/timeline": "1.72.0-next.20",
"@theia/toolbar": "1.72.0-next.20",
"@theia/typehierarchy": "1.72.0-next.20",
"@theia/userstorage": "1.72.0-next.20",
"@theia/variable-resolver": "1.72.0-next.20",
"@theia/vsx-registry": "1.72.0-next.20",
"@theia/workspace": "1.72.0-next.20",
"fs-extra": "^9.1.0",
"theia-ide-launcher-ext": "1.71.100",
"theia-ide-product-ext": "1.71.100",
"theia-ide-updater-ext": "1.71.100"
},
"devDependencies": {
"@theia/cli": "1.72.0-next.20",
"@theia/bundle-plugin": "1.72.0-next.20",
"@types/js-yaml": "^3.12.10",
"@types/yargs": "17.0.7",
"@wdio/cli": "^6.12.1",
"@wdio/local-runner": "^6.12.1",
"@wdio/mocha-framework": "^6.11.0",
"@wdio/spec-reporter": "^6.11.0",
"app-builder-lib": "26.0.12",
"chai": "^4.5.0",
"concurrently": "^3.6.1",
"electron": "39.8.7",
"electron-builder": "26.0.12",
"electron-chromedriver": "^28.3.3",
"electron-mocha": "^12.3.1",
"electron-osx-sign": "^0.6.0",
"js-yaml": "^3.14.2",
"mocha": "^8.4.0",
"rimraf": "^2.7.1",
"ts-node": "^10.9.2",
"wdio-chromedriver-service": "^6.0.4",
"webdriverio": "^6.12.1",
"yargs": "17.2.1"
},
"scripts": {
"clean": "theia clean && rimraf node_modules",
"clean:dist": "rimraf dist",
"build": "yarn -s rebuild && theia build --app-target=\"electron\" --mode development",
"build:prod": "yarn -s rebuild && theia build --app-target=\"electron\"",
"rebuild": "theia rebuild:electron --cacheRoot ../..",
"watch": "concurrently -n compile,build \"theiaext watch --preserveWatchOutput\" \"theia build --watch --mode development\"",
"start": "electron scripts/theia-electron-main.js --plugins=local-dir:../../plugins",
"start:debug": "yarn start --log-level=debug",
"package": "yarn clean:dist && yarn rebuild && electron-builder -c.mac.identity=null --publish never",
"package:prod": "yarn deploy",
"deploy": "yarn clean:dist && yarn rebuild && electron-builder -c.mac.identity=null --publish always",
"package:preview": "yarn clean:dist && yarn rebuild && electron-builder -c.mac.identity=null --dir",
"update:theia": "ts-node ../../scripts/update-theia-version.ts",
"update:next": "ts-node ../../scripts/update-theia-version.ts next",
"test": "mocha --timeout 60000 \"../electron/test/*.spec.js\"",
"lint": "eslint --ext js,jsx,ts,tsx scripts",
"lint:fix": "eslint --ext js,jsx,ts,tsx scripts --fix"
}
}
================================================
FILE: applications/electron-next/resources/LICENSE
================================================
MIT License
Copyright (c) 2026 Eclipse Theia IDE Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: applications/electron-next/resources/preload.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<style>
html,
body {
background-color: black;
}
.theia-preload {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* Above styles copied from https://github.com/eclipse-theia/theia/blob/5aeef6c0c683b4e91713ab736957e6655b486adc/packages/core/src/browser/style/index.css#L147-L151 */
/* Otherwise, there is a flickering when Theia's CSS loads. */
background-image: none;
}
.theia-preload::after {
/* remove default loading animation */
content: none;
}
.spinner-container {
display: flex;
flex-direction: center;
align-self: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.custom-spinner {
align-self: center;
}
.custom-spinner svg {
width: 16vw;
height: 16vh;
animation-delay: 0;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-name: theia-ide-spinner;
animation-timing-function: ease;
}
@keyframes theia-ide-spinner {
0% {
filter: brightness(1) saturate(1);
transform: scale(1.0);
}
50% {
filter: brightness(1.35) saturate(0.75);
transform: scale(0.8);
}
100% {
filter: brightness(1) saturate(1);
transform: scale(1.0);
}
}
</style>
</head>
<body>
<div class='spinner-container'>
<div class='custom-spinner'>
<svg id="spinner" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" preserveAspectRatio="xMinYMin meet"
viewBox="0, 0, 1150, 540.6">
<g id="Layer_1" fill="#8B5CF6">
<path
d="M880.199,2.8 C1028.1,2.8 1147.9,122.6 1147.9,270.5 C1147.9,418.3 1028.1,538.2 880.2,538.2 L290.1,538.2 C269,538.2 251.9,521.1 251.9,500 C251.9,478.9 269,461.8 290.1,461.8 L427.6,461.8 C448.6,461.8 465.7,444.7 465.7,423.6 C465.7,402.5 448.6,385.4 427.6,385.4 L396.999,385.4 C375.9,385.4 358.8,368.3 358.8,347.2 C358.8,326.1 375.9,309 397,309 L488.703,309 C509.918,308.941 526.373,291.65 526.9,270.8 C526.9,249.7 509.8,232.6 488.7,232.6 L167.8,232.6 C146.7,232.6 129.6,215.5 129.6,194.4 C129.6,173.3 146.7,156.2 167.8,156.2 L404.604,156.2 C425.818,156.141 442.273,138.85 442.8,118 C442.8,96.9 425.7,79.8 404.6,79.8 L351.2,79.8 C330.1,79.8 313,62.7 313,41.6 C313,20.5 330.1,2.4 351.2,2.4 L880.199,2.8 z M837.4,92 L837.4,92 C755.2,92 688.7,158.6 688.7,240.7 L688.7,300.2 C688.7,382.4 755.2,448.9 837.4,448.9 C919.5,448.9 986.1,382.4 986.1,300.2 L986.1,240.7 C986.1,158.6 919.5,92 837.4,92 L837.4,92 z M888.2,232.6 C908,232.6 924.1,248.7 924.1,268.5 L924.1,273.1 C924.1,292.9 908,309 888.2,309 L776.6,309 C756.8,309 740.7,292.9 740.7,273.1 L740.7,268.5 C740.7,248.7 756.8,232.6 776.6,232.6 L888.2,232.6 z" />
<path
d="M170.1,461.8 C190,461.8 206,477.8 206,497.7 L206,502.3 C206,522.1 190,538.2 170.1,538.2 L38,538.2 C18.2,538.2 2.1,522.1 2.1,502.3 L2.1,497.7 C2.1,477.8 18.2,461.8 38,461.8 L170.1,461.8 z" />
<path
d="M231.3,3.4 C251.1,3.4 267.1,19.5 267.1,39.3 L267.1,44 C267.1,63.8 251.1,79.8 231.3,79.8 L83.8,79.8 C64,79.8 47.9,63.8 47.9,44 L47.9,39.3 C47.9,19.5 64,3.4 83.8,3.4 L231.3,3.4 z" />
<path
d="M277.1,309 C296.9,309 313,325.1 313,344.9 L313,349.5 C313,369.3 296.9,385.4 277.1,385.4 L196.1,385.4 C176.3,385.4 160.2,369.3 160.2,349.5 L160.2,344.9 C160.2,325.1 176.3,309 196.1,309 L277.1,309 z" />
</g>
</svg>
</div>
</div>
</body>
</html>
================================================
FILE: applications/electron-next/scripts/after-pack.js
================================================
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Signing and notarizing are not needed for the Next product
// (it is not built on Jenkins as a full release).
// Only the Linux sandbox fix is required for AppImage builds.
// taken and modified from: https://github.com/gergof/electron-builder-sandbox-fix/blob/a2251d7d8f22be807d2142da0cf768c78d4cfb0a/lib/index.js
exports.default = async function (context) {
if (context.electronPlatformName !== 'linux') {
return;
}
const executable = path.join(
context.appOutDir,
context.packager.executableName
);
const loaderScript = `#!/usr/bin/env bash
set -u
SCRIPT_DIR="$( cd "$( dirname "\${BASH_SOURCE[0]}" )" && pwd )"
exec "$SCRIPT_DIR/${context.packager.executableName}.bin" "--no-sandbox" "$@"
`;
try {
await fs.promises.rename(executable, executable + '.bin');
await fs.promises.writeFile(executable, loaderScript);
await fs.promises.chmod(executable, 0o755);
} catch (e) {
throw new Error('Failed to create loader for sandbox fix:\n' + e);
}
};
================================================
FILE: applications/electron-next/scripts/appimage-helpers.js
================================================
const fs = require('fs');
const path = require('path');
/**
* Reads the plugin copy metadata file and returns its content.
* @param metadataPath - Path to the metadata file
* @returns The metadata object or undefined if not found
*/
function readPluginCopyMetadata(metadataPath) {
if (!fs.existsSync(metadataPath)) {
return undefined;
}
try {
return JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
} catch (err) {
console.warn('Could not read built-in plugin copy metadata file:', err.message);
return undefined;
}
}
/**
* Writes the plugin copy metadata file with version and timestamp.
* @param metadataPath - Path to the metadata file
* @param version - Current version
*/
function writePluginCopyMetadata(metadataPath, version) {
const metadata = {
version: version,
copiedAt: new Date().toISOString()
};
fs.writeFileSync(metadataPath, JSON.stringify(metadata, undefined, 2));
}
/**
* Copies bundled plugins from AppImage to user directory if needed.
* @param bundledPluginsDir - Path to bundled plugins in AppImage
* @param userPluginsDir - Path to user built-in plugins directory
* @param currentVersion - Current Theia IDE version
* @returns true if the builtins were copied to the user dir, false if there was an error
*/
function copyBundledPlugins(bundledPluginsDir, userPluginsDir, currentVersion) {
const metadataFile = path.join(userPluginsDir, '.builtInPlugins-metadata');
// Ensure the user plugins directory exists
if (!fs.existsSync(userPluginsDir)) {
fs.mkdirSync(userPluginsDir, { recursive: true });
}
// Check if built-in plugins need to be copied
const metadata = readPluginCopyMetadata(metadataFile);
let shouldCopy = false;
if (!metadata) {
shouldCopy = true;
} else if (metadata.version !== currentVersion) {
console.log(`Theia IDE updated from ${metadata.version} to ${currentVersion}. Updating built-in plugins...`);
shouldCopy = true;
}
if (!shouldCopy) {
console.log('Built-in plugins were already copied.');
return true;
}
console.log(`Copying bundled plugins from AppImage to ${userPluginsDir}...`);
try {
// Clean existing plugins directory to remove old/obsolete plugins
fs.rmSync(userPluginsDir, { recursive: true, force: true });
fs.mkdirSync(userPluginsDir, { recursive: true });
const pluginEntries = fs.readdirSync(bundledPluginsDir, { withFileTypes: true });
for (const entry of pluginEntries) {
const srcPath = path.join(bundledPluginsDir, entry.name);
const destPath = path.join(userPluginsDir, entry.name);
fs.cpSync(srcPath, destPath, { recursive: true });
}
writePluginCopyMetadata(metadataFile, currentVersion);
console.log(`Bundled plugins copied successfully to ${userPluginsDir}.`);
} catch (err) {
console.error('Failed to copy bundled plugins:', err.message);
return false;
}
return true;
}
module.exports = {
copyBundledPlugins,
};
================================================
FILE: applications/electron-next/scripts/theia-electron-main.js
================================================
const path = require('path');
const fs = require('fs');
const os = require('os');
const { copyBundledPlugins } = require('./appimage-helpers');
// Update to override the supported VS Code API version.
// process.env.VSCODE_API_VERSION = '1.50.0'
// Detect if running as AppImage
const isAppImage = !!process.env.APPIMAGE;
// When packaged with asar, __dirname is inside app.asar (e.g., .../app.asar/scripts)
// but plugins are in extraResources at .../app/plugins (outside the asar)
const isInsideAsar = __dirname.includes('.asar');
const bundledPluginsDir = isInsideAsar
? path.join(process.resourcesPath, 'app', 'plugins')
: path.resolve(__dirname, '../', 'plugins');
if (isAppImage) {
// When running as AppImage, use a user-writable directory for the built-in plugins
// The AppImage mount point (/tmp/.mount_*) is read-only
const configDir = process.env.THEIA_CONFIG_DIR || path.join(os.homedir(), '.theia-ide-next');
const userPluginsDir = path.join(configDir, 'builtInPlugins');
const packageJsonPath = path.resolve(__dirname, '../', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const currentVersion = packageJson.version;
// Copy bundled plugins to user directory if needed (first run or version update)
const useUserDir = copyBundledPlugins(bundledPluginsDir, userPluginsDir, currentVersion);
// If copying fails, fall back to the read-only bundled directory (will be improved in follow up of GH-630)
process.env.THEIA_DEFAULT_PLUGINS = `local-dir:${useUserDir ? userPluginsDir : bundledPluginsDir}`;
} else {
// Use a set of builtin plugins in our application.
process.env.THEIA_DEFAULT_PLUGINS = `local-dir:${bundledPluginsDir}`;
}
// Handover to the auto-generated electron application handler.
require('../lib/backend/electron-main.js');
================================================
FILE: applications/electron-next/test/workspace/README.md
================================================
# Test Workspace
This is the test workspace for E2E tests.
================================================
FILE: applications/electron-next/tsconfig.eslint.json
================================================
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true
},
"include": [
"./scripts"
]
}
================================================
FILE: applications/electron-next/tsconfig.json
================================================
{
"extends": "../../configs/base.tsconfig",
"include": [],
"compilerOptions": {
"composite": true,
"esModuleInterop": true
},
"references": [
{
"path": "../../theia-extensions/product"
},
{
"path": "../../theia-extensions/updater"
}
]
}
================================================
FILE: applications/electron-next/webpack.config.js
================================================
/**
* This file can be edited to customize webpack configuration.
* To reset delete this file and rerun theia build again.
*/
// @ts-check
const configs = require('./gen-webpack.config.js');
const nodeConfig = require('./gen-webpack.node.config.js');
const TerserPlugin = require('terser-webpack-plugin');
const fs = require('fs');
const path = require('path');
/**
* Webpack plugin to patch the bundled ripgrep path for asar compatibility.
* When packaged with asar, __dirname resolves inside app.asar but the native binaries
* are extracted to app.asar.unpacked via asarUnpack.
*
* The native-webpack-plugin bundles ripgrep path resolution directly into main.js,
* so we need to patch the bundle after emit to add asar path rewriting.
*/
class PatchRipgrepPlugin {
apply(compiler) {
compiler.hooks.afterEmit.tapAsync('PatchRipgrepPlugin', (compilation, callback) => {
const mainJsPath = path.join(compiler.outputPath, 'main.js');
if (fs.existsSync(mainJsPath)) {
let content = fs.readFileSync(mainJsPath, 'utf8');
// Match the ripgrep path.join(__dirname, ...) call regardless of how
// the path module is referenced or how the result is exported.
// Webpack output varies across modes:
// Production (minified): i.join(__dirname,"./native/rg"+("win32"===...))
// Dev (harmony): (__webpack_require__(/*! path */ "path").join)(__dirname, `./native/rg${...}`)
// Dev (CommonJS): path.join(__dirname, `./native/rg${...}`)
// The .join call may be direct (EXPR.join(...)) or parenthesized ((EXPR.join)(...)).
// Both string concat (prod) and template literal (dev) arg forms are matched.
const rgSuffix = `("win32"===process.platform?".exe":"")`;
const prodArgs = /["']\.\/native\/rg["']\s*\+\s*\(["']win32["']\s*===\s*process\.platform\s*\?\s*["']\.exe["']\s*:\s*["']["']\s*\)/;
const devArgs = /`\.\/native\/rg\$\{process\.platform\s*===\s*['"]win32['"]\s*\?\s*['"]\.exe['"]\s*:\s*['"]['"]}\s*`/;
// Match both EXPR.join(__dirname, ARGS) and (EXPR.join)(__dirname, ARGS)
// Use [^=,;\n] (not \s) to allow spaces in webpack comments like /*! path */
const joinCall = (argsPattern) => new RegExp(`\\(?[^=,;\\n]+?\\.join\\)?\\(\\s*__dirname\\s*,\\s*${argsPattern.source}\\s*\\)`, 'g');
const prodPattern = joinCall(prodArgs);
const devPattern = joinCall(devArgs);
let patched = false;
const patchFn = (match) => {
patched = true;
return `(()=>{const _p=require("path"),_r=_p.join(__dirname,"./native/rg"+${rgSuffix});return _r.includes(".asar"+_p.sep)?_r.replace(".asar"+_p.sep,".asar.unpacked"+_p.sep):_r})()`;
};
let newContent = content.replace(prodPattern, patchFn);
if (!patched) {
newContent = content.replace(devPattern, patchFn);
}
if (patched) {
fs.writeFileSync(mainJsPath, newContent);
console.log('Patched main.js ripgrep path for asar compatibility');
} else {
const idx = content.indexOf('rgPath');
if (idx !== -1) {
console.error('Could not patch ripgrep path. Context around rgPath:');
console.error(content.substring(Math.max(0, idx - 200), idx + 300));
}
throw new Error('Could not find ripgrep pattern to patch in main.js. The pattern may have changed in @theia/native-webpack-plugin.');
}
}
callback();
});
}
}
/**
* Expose bundled modules on window.theia.moduleName namespace, e.g.
* window['theia']['@theia/core/lib/common/uri'].
* Such syntax can be used by external code, for instance, for testing.
configs[0].module.rules.push({
test: /\.js$/,
loader: require.resolve('@theia/application-manager/lib/expose-loader')
}); */
/**
* Do no run TerserPlugin with parallel: true
* Each spawned node may take the full memory configured via NODE_OPTIONS / --max_old_space_size
* In total this may lead to OOM issues
*/
if (nodeConfig.config.optimization) {
nodeConfig.config.optimization.minimizer = [
new TerserPlugin({
parallel: false,
exclude: /^(lib|builtins)\//,
terserOptions: {
keep_classnames: /AbortSignal/
}
})
];
}
for (const config of configs) {
config.optimization = {
minimizer: [
new TerserPlugin({
parallel: false
})
]
};
}
// Add the ripgrep patch plugin to the node config
nodeConfig.config.plugins = nodeConfig.config.plugins || [];
nodeConfig.config.plugins.push(new PatchRipgrepPlugin());
module.exports = [
...configs,
nodeConfig.config
];
================================================
FILE: browser.Dockerfile
================================================
# Builder stage
FROM node:24-bookworm AS build-stage
# install required tools to build the application
RUN apt-get update && apt-get install -y libxkbfile-dev libsecret-1-dev
WORKDIR /home/theia
# Copy repository files
COPY . .
# Remove unnecesarry files for the browser application
# Download plugins and build application production mode
# Use yarn autoclean to remove unnecessary files from package dependencies
RUN yarn config set network-timeout 600000 -g && \
yarn --pure-lockfile && \
yarn build:extensions && \
yarn download:plugins && \
yarn browser build && \
yarn && \
yarn autoclean --init && \
echo *.ts >> .yarnclean && \
echo *.ts.map >> .yarnclean && \
echo *.spec.* >> .yarnclean && \
yarn autoclean --force && \
yarn cache clean && \
rm -rf .git applications/electron theia-extensions/launcher theia-extensions/updater node_modules
# Production stage uses a small base image
FROM node:24-bookworm-slim AS production-stage
# Create theia user and directories
# Application will be copied to /home/theia
# Default workspace is located at /home/project
RUN adduser --system --group --home /home/theia theia
RUN chmod g+rw /home && \
mkdir -p /home/project && \
chown -R theia:theia /home/theia && \
chown -R theia:theia /home/project;
# Install required tools for application: Temurin JDK, JDK, SSH, Bash, Maven
# Node is already available in base image
RUN apt-get update && apt-get install -y wget apt-transport-https && \
apt-get update && apt-get install -y git openssh-client openssh-server bash libsecret-1-0 openjdk-17-jdk maven && \
apt-get purge -y wget && \
apt-get clean
ENV HOME=/home/theia
WORKDIR /home/theia
# Copy application from builder-stage
COPY --from=build-stage --chown=theia:theia /home/theia /home/theia
EXPOSE 3000
# Specify default shell for Theia and the Built-In plugins directory
ENV SHELL=/bin/bash \
THEIA_DEFAULT_PLUGINS=local-dir:/home/theia/plugins
# Use installed git instead of dugite
ENV USE_LOCAL_GIT=true
# Switch to Theia user
USER theia
WORKDIR /home/theia/applications/browser
# Launch the backend application via node
ENTRYPOINT [ "node", "/home/theia/applications/browser/lib/backend/main.js" ]
# Arguments passed to the application
CMD [ "/home/project", "--hostname=0.0.0.0" ]
================================================
FILE: cleanup/Jenkinsfile
================================================
pipeline {
agent {
label 'windows'
}
triggers { cron('@weekly') }
options {
timeout(time: 1, unit: 'HOURS')
disableConcurrentBuilds()
}
stages {
stage('Cleanup Windows temp directory') {
steps {
script {
listTemp('before cleanup', '%temp%')
cleanFiles('tmp/plugin-download', '%temp%', 'theia-plugin-download**')
cleanDirs('tmp/yarn', '%temp%', 'yarn--**')
cleanDirs('tmp/lighthouse', '%temp%', 'lighthouse.*')
listTemp('after cleanup', '%temp%')
cleanDir('appdata/local/electron', '\"%LocalAppData%\"\\electron\\Cache')
cleanYarnCache('appdata/local/yarn')
}
}
}
}
}
Object listTemp(String label, String temp) {
echo "in listTemp(): ${label}"
bat "DIR ${temp}"
return
}
Object cleanFiles(String label, String parent, String pattern) {
echo "in cleanFile() - clean: ${label} files"
echo "parent: ${parent}, pattern: ${pattern}"
// use "returnStatus" option to avoid an exception being thrown if no
// matching files are found, failing the pipeline
s = bat(
script: "FORFILES /p ${parent} /m ${pattern} /C \"cmd /c Del /q @file\"",
returnStatus: true
)
if (s != 0) {
echo "No ${pattern} file found... Good I guess"
}
}
Object cleanDirs(String label, String parent, String pattern) {
echo "Before ${label} Cleanup:"
bat "FOR /D /R ${parent} %%i in (${pattern}) do echo \"%%i\""
bat "FOR /D /R ${parent} %%i in (${pattern}) do @rmdir /s /q \"%%i\""
echo "After ${label} Cleanup:"
bat "FOR /D /R ${parent} %%i in (${pattern}) do echo \"%%i\""
return
}
Object cleanDir(String label, String parent) {
echo "Before ${label} Cleanup:"
bat "FOR /D /R ${parent} %%i in (*) do echo \"%%i\""
bat "if exist ${parent} @rmdir /s /q ${parent}"
echo "After ${label} Cleanup:"
bat "FOR /D /R ${parent} %%i in (*) do echo \"%%i\""
return
}
Object cleanYarnCache(String label) {
echo "Cleaning-up: ${label}"
sh 'yarn cache clean --all'
return
}
================================================
FILE: configs/base.eslintrc.json
================================================
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 6,
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"@typescript-eslint",
"@typescript-eslint/tslint",
"import",
"no-null"
],
"env": {
"browser": true,
"mocha": true,
"node": true
},
"ignorePatterns": [
"node_modules",
"lib"
]
}
================================================
FILE: configs/base.tsconfig.json
================================================
{
"compilerOptions": {
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"noImplicitAny": true,
"noEmitOnError": false,
"noImplicitThis": true,
"noUnusedLocals": true,
"strictNullChecks": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"downlevelIteration": true,
"resolveJsonModule": true,
"module": "commonjs",
"moduleResolution": "node",
"target": "ES2017",
"jsx": "react",
"lib": [
"ES2017",
"ES2020.Promise",
"dom"
],
"sourceMap": true,
"composite": true
}
}
================================================
FILE: configs/build.eslintrc.json
================================================
{
"extends": [
"./base.eslintrc.json",
"./errors.eslintrc.json"
]
}
================================================
FILE: configs/errors.eslintrc.json
================================================
{
"$schema": "https://json.schemastore.org/eslintrc",
"rules": {
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/indent": "off",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true
}
],
"@typescript-eslint/semi": [
"error",
"always"
],
"@typescript-eslint/type-annotation-spacing": "error",
"arrow-body-style": [
"error",
"as-needed"
],
"arrow-parens": [
"error",
"as-needed"
],
"camelcase": "off",
"comma-dangle": "off",
"curly": "error",
"eol-last": "error",
"eqeqeq": [
"error",
"smart"
],
"guard-for-in": "error",
"id-blacklist": "off",
"id-match": "off",
"max-len": [
"error",
{
"code": 180
}
],
"no-magic-numbers": "off",
"no-multiple-empty-lines": [
"error",
{
"max": 1
}
],
"no-new-wrappers": "error",
"no-null/no-null": "error",
"no-shadow": "off",
"@typescript-eslint/no-shadow": [
"error",
{
"hoist": "all"
}
],
"no-tabs": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-underscore-dangle": "off",
"no-unused-expressions": "error",
"no-var": "error",
"no-void": "error",
"one-var": [
"error",
"never"
],
"prefer-const": [
"error",
{
"destructuring": "all"
}
],
"radix": "off",
"space-before-function-paren": [
"error",
{
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}
],
"spaced-comment": [
"error",
"always",
{
"exceptions": [
"*",
"+",
"-",
"/"
]
}
],
"@typescript-eslint/tslint/config": [
"error",
{
"rules": {
"file-header": [
true,
"SPDX-License-Identifier: MIT"
],
"jsdoc-format": [
true,
"check-multiline-start"
],
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"typedef": [
true,
"call-signature",
"property-declaration"
],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
]
}
}
],
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
"files": [
"dev-packages",
"*.{spec,espec,slow-spec}.{js,ts}"
],
"rules": {
"import/no-extraneous-dependencies": "off"
}
}
]
}
================================================
FILE: configs/license-check-config.json
================================================
{
"project": "ecd.theia",
"inputFile": "yarn.lock",
"batch": 50,
"timeout": 240,
"summary": "license-check-summary.txt"
}
================================================
FILE: configs/tsconfig.eslint.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": true
},
"include": [
"../scripts"
]
}
================================================
FILE: configs/warnings.eslintrc.json
================================================
{
"plugins": [
"deprecation"
],
"rules": {
"@typescript-eslint/await-thenable": "warn",
"no-return-await": "warn",
"deprecation/deprecation": "warn"
}
}
================================================
FILE: configs/xss.eslintrc.json
================================================
{
"extends": ["plugin:no-unsanitized/DOM"],
"plugins": ["no-unsanitized", "react"],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"no-unsanitized/method": [
"warn", {
"escape": {
"methods": ["DOMPurify.sanitize"]
}
}
],
"no-unsanitized/property
gitextract_jxq8o1lq/ ├── .eslintrc.js ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ └── feature_request.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── build-next-release.yml │ ├── build-next.yml │ ├── build.yml │ ├── license-check-workflow.yml │ ├── publish-builder-img.yml │ └── publish-theia-ide-img.yml ├── .gitignore ├── .vscode/ │ ├── launch.json │ ├── settings.json │ └── theia.code-snippets ├── ADOPTER.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── NOTICE.md ├── PUBLISHING.md ├── README.md ├── TheiaIDE logo/ │ └── TheiaIDE.eps ├── applications/ │ ├── browser/ │ │ ├── package.json │ │ ├── resources/ │ │ │ └── preload.html │ │ ├── tsconfig.json │ │ └── webpack.config.js │ ├── electron/ │ │ ├── .eslintrc.js │ │ ├── electron-builder.yml │ │ ├── entitlements.plist │ │ ├── package.json │ │ ├── resources/ │ │ │ ├── LICENSE │ │ │ ├── icon.icns │ │ │ ├── icons/ │ │ │ │ └── MacLauncherIcons/ │ │ │ │ ├── 512-512-2.icns │ │ │ │ ├── Theia-16bp-alfa ignored.icns │ │ │ │ ├── icns-1bit/ │ │ │ │ │ ├── 128-128.icns │ │ │ │ │ ├── 16-16-1.icns │ │ │ │ │ ├── 256-256.icns │ │ │ │ │ ├── 32-32.icns │ │ │ │ │ ├── 48-48.icns │ │ │ │ │ └── 512-512-2 copy.icns │ │ │ │ ├── icns-8bit/ │ │ │ │ │ ├── 128-128.icns │ │ │ │ │ ├── 16-16.icns │ │ │ │ │ ├── 256-256.icns │ │ │ │ │ ├── 32-32.icns │ │ │ │ │ ├── 48-48.icns │ │ │ │ │ └── 512-512.icns │ │ │ │ ├── icon.icns │ │ │ │ └── icon.icon/ │ │ │ │ └── icon.json │ │ │ └── preload.html │ │ ├── scripts/ │ │ │ ├── after-pack.js │ │ │ ├── appimage-helpers.js │ │ │ ├── generate-app-update-yml.js │ │ │ ├── notarize.sh │ │ │ ├── sign-directory-windows.ts │ │ │ ├── sign-directory.ts │ │ │ ├── sign-utils.ts │ │ │ ├── sign.sh │ │ │ ├── theia-electron-main.js │ │ │ ├── update-blockmap.ts │ │ │ └── update-checksum.ts │ │ ├── test/ │ │ │ ├── app.spec.js │ │ │ └── workspace/ │ │ │ └── README.md │ │ ├── tsconfig.eslint.json │ │ ├── tsconfig.json │ │ └── webpack.config.js │ └── electron-next/ │ ├── .eslintrc.js │ ├── electron-builder.yml │ ├── package.json │ ├── resources/ │ │ ├── LICENSE │ │ └── preload.html │ ├── scripts/ │ │ ├── after-pack.js │ │ ├── appimage-helpers.js │ │ └── theia-electron-main.js │ ├── test/ │ │ └── workspace/ │ │ └── README.md │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ └── webpack.config.js ├── browser.Dockerfile ├── cleanup/ │ └── Jenkinsfile ├── configs/ │ ├── base.eslintrc.json │ ├── base.tsconfig.json │ ├── build.eslintrc.json │ ├── errors.eslintrc.json │ ├── license-check-config.json │ ├── tsconfig.eslint.json │ ├── warnings.eslintrc.json │ └── xss.eslintrc.json ├── docs/ │ └── developing-with-local-theia.md ├── lerna.json ├── next/ │ ├── Jenkinsfile │ └── NEXT_INTEGRATION_BUILD.md ├── package.json ├── patches/ │ └── @theia+terminal+1.72.0-next.20.patch ├── releng/ │ ├── preview/ │ │ ├── Jenkinsfile.build │ │ ├── Jenkinsfile.sign │ │ └── Jenkinsfile.upload │ └── promote/ │ └── Jenkinsfile ├── scripts/ │ ├── build-with-local-theia.js │ ├── generate-next-icons.js │ ├── make-files-writeable.ts │ └── update-theia-version.ts ├── theia-extensions/ │ ├── launcher/ │ │ ├── .eslintrc.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── browser/ │ │ │ │ ├── create-launcher-contribution.ts │ │ │ │ ├── create-launcher-frontend-module.ts │ │ │ │ ├── desktopfile-service.ts │ │ │ │ └── launcher-service.ts │ │ │ └── node/ │ │ │ ├── desktopfile-endpoint.ts │ │ │ ├── launcher-backend-module.ts │ │ │ ├── launcher-endpoint.ts │ │ │ └── launcher-util.ts │ │ └── tsconfig.json │ ├── product/ │ │ ├── .eslintrc.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── browser/ │ │ │ │ ├── branding-util.tsx │ │ │ │ ├── style/ │ │ │ │ │ └── index.css │ │ │ │ ├── theia-ide-about-dialog.tsx │ │ │ │ ├── theia-ide-config.ts │ │ │ │ ├── theia-ide-contribution.tsx │ │ │ │ ├── theia-ide-frontend-module.ts │ │ │ │ └── theia-ide-getting-started-widget.tsx │ │ │ └── electron-main/ │ │ │ ├── icon-contribution.ts │ │ │ └── theia-ide-main-module.ts │ │ └── tsconfig.json │ └── updater/ │ ├── .eslintrc.js │ ├── package.json │ ├── src/ │ │ ├── common/ │ │ │ └── updater/ │ │ │ └── theia-updater.ts │ │ ├── electron-browser/ │ │ │ ├── theia-updater-frontend-module.ts │ │ │ └── updater/ │ │ │ ├── theia-updater-frontend-contribution.ts │ │ │ └── theia-updater-preferences.ts │ │ └── electron-main/ │ │ └── update/ │ │ ├── theia-updater-impl.ts │ │ └── theia-updater-main-module.ts │ └── tsconfig.json └── tsconfig.json
SYMBOL INDEX (174 symbols across 31 files)
FILE: applications/electron-next/scripts/appimage-helpers.js
function readPluginCopyMetadata (line 9) | function readPluginCopyMetadata(metadataPath) {
function writePluginCopyMetadata (line 26) | function writePluginCopyMetadata(metadataPath, version) {
function copyBundledPlugins (line 41) | function copyBundledPlugins(bundledPluginsDir, userPluginsDir, currentVe...
FILE: applications/electron-next/webpack.config.js
class PatchRipgrepPlugin (line 20) | class PatchRipgrepPlugin {
method apply (line 21) | apply(compiler) {
FILE: applications/electron/scripts/after-pack.js
constant DELETE_PATHS (line 11) | const DELETE_PATHS = [
FILE: applications/electron/scripts/appimage-helpers.js
function readPluginCopyMetadata (line 9) | function readPluginCopyMetadata(metadataPath) {
function writePluginCopyMetadata (line 26) | function writePluginCopyMetadata(metadataPath, version) {
function copyBundledPlugins (line 41) | function copyBundledPlugins(bundledPluginsDir, userPluginsDir, currentVe...
FILE: applications/electron/scripts/sign-directory-windows.ts
constant DEFAULT_SIGN_URL (line 26) | const DEFAULT_SIGN_URL = 'https://cbi.eclipse.org/authenticode/sign';
function isExeFile (line 45) | function isExeFile(filePath: string): boolean {
function collectFilesToSign (line 55) | function collectFilesToSign(unpackedDir: string): string[] {
function signFile (line 62) | function signFile(file: string, url: string): void {
function main (line 122) | function main(): void {
FILE: applications/electron/scripts/sign-directory.ts
constant BINARY_EXTENSIONS (line 22) | const BINARY_EXTENSIONS = ['.dylib', '.so', '.node', '.framework'];
constant BINARY_PATTERNS (line 23) | const BINARY_PATTERNS = [
constant EXECUTABLE_NAMES (line 27) | const EXECUTABLE_NAMES = [
function isBinaryFile (line 32) | function isBinaryFile(filePath: string): boolean {
function findBinariesToSign (line 78) | function findBinariesToSign(dirPath: string): string[] {
function execute (line 134) | async function execute(): Promise<void> {
FILE: applications/electron/scripts/sign-utils.ts
type WalkOptions (line 13) | interface WalkOptions {
function walkFiles (line 24) | function walkFiles(root: string, filter: (file: string) => boolean, opts...
function replaceWithSigned (line 57) | function replaceWithSigned(originalPath: string, signedPath: string): vo...
function formatBytes (line 64) | function formatBytes(bytes: number): string {
FILE: applications/electron/scripts/update-blockmap.ts
constant BLOCK_MAP_FILE_SUFFIX (line 18) | const BLOCK_MAP_FILE_SUFFIX = '.blockmap';
function execute (line 28) | async function execute(): Promise<void> {
FILE: applications/electron/scripts/update-checksum.ts
function execute (line 28) | async function execute(): Promise<void> {
function hashFile (line 80) | function hashFile(file: fs.PathLike, algorithm = 'sha512', encoding: Buf...
function updatedPath (line 115) | function updatedPath(toUpdate: string, version: string, platform: string...
FILE: applications/electron/test/app.spec.js
constant THEIA_LOAD_TIMEOUT (line 8) | const THEIA_LOAD_TIMEOUT = 15000;
function saveScreenshot (line 22) | async function saveScreenshot(browser, name) {
function isMacArm (line 35) | function isMacArm() {
function getBinaryPath (line 49) | function getBinaryPath() {
function macSafeKeyCombo (line 72) | function macSafeKeyCombo(keys) {
FILE: applications/electron/webpack.config.js
class PatchRipgrepPlugin (line 20) | class PatchRipgrepPlugin {
method apply (line 21) | apply(compiler) {
FILE: scripts/build-with-local-theia.js
constant ROOT_DIR (line 31) | const ROOT_DIR = path.resolve(__dirname, '..');
constant DEFAULT_THEIA_PATH (line 32) | const DEFAULT_THEIA_PATH = path.resolve(ROOT_DIR, '..', 'theia');
function getArgValue (line 37) | function getArgValue(flag, defaultValue) {
function run (line 91) | function run(cmd, cwd = ROOT_DIR, description = '') {
function readJson (line 123) | function readJson(filePath) {
function getTheiaDependencies (line 130) | function getTheiaDependencies(packageJsonPath) {
function findTheiaPackages (line 150) | function findTheiaPackages(theiaPath) {
function collectAllTheiaDependencies (line 177) | function collectAllTheiaDependencies() {
function buildTheia (line 206) | function buildTheia() {
function linkTheiaPackages (line 215) | function linkTheiaPackages() {
function unlinkTheiaPackages (line 275) | function unlinkTheiaPackages() {
function buildIde (line 305) | function buildIde() {
function packageApp (line 319) | function packageApp() {
function main (line 326) | async function main() {
FILE: scripts/generate-next-icons.js
constant SOURCE_DIR (line 21) | const SOURCE_DIR = path.resolve(__dirname, '../applications/electron/res...
constant TARGET_DIR (line 22) | const TARGET_DIR = path.resolve(__dirname, '../applications/electron-nex...
constant ICON_MAPPINGS (line 24) | const ICON_MAPPINGS = [
constant THEIA_BLUE (line 31) | const THEIA_BLUE = '#00ADEE';
constant NEXT_PURPLE (line 32) | const NEXT_PURPLE = '#8B5CF6';
function hasImageMagick (line 34) | function hasImageMagick() {
function generateWithImageMagick (line 43) | function generateWithImageMagick(srcPath, destPath) {
function generateWithSharp (line 61) | async function generateWithSharp(srcPath, destPath) {
function main (line 102) | async function main() {
FILE: scripts/make-files-writeable.ts
function execute (line 28) | async function execute(): Promise<void> {
function makeWritable (line 40) | function makeWritable(dir: string): void {
FILE: scripts/update-theia-version.ts
function execute (line 15) | async function execute(): Promise<void> {
function updateTheiaVersions (line 44) | function updateTheiaVersions(dependencies: PackageJson.Dependency, theia...
FILE: theia-extensions/launcher/src/browser/create-launcher-contribution.ts
class CreateLauncherCommandContribution (line 19) | class CreateLauncherCommandContribution implements FrontendApplicationCo...
method onStart (line 31) | onStart(_app: FrontendApplication): MaybePromise<void> {
FILE: theia-extensions/launcher/src/browser/desktopfile-service.ts
type DesktopFileOptions (line 13) | interface DesktopFileOptions {
class DesktopFileService (line 20) | class DesktopFileService {
method isInitialized (line 22) | async isInitialized(): Promise<boolean> {
method createOrUpdateDesktopfile (line 30) | async createOrUpdateDesktopfile(create: boolean, options?: DesktopFile...
method endpoint (line 38) | protected endpoint(): string {
FILE: theia-extensions/launcher/src/browser/launcher-service.ts
class LauncherService (line 14) | class LauncherService {
method isInitialized (line 16) | async isInitialized(uriScheme?: string): Promise<boolean> {
method createLauncher (line 25) | async createLauncher(create: boolean, uriScheme?: string): Promise<voi...
method endpoint (line 33) | protected endpoint(): string {
FILE: theia-extensions/launcher/src/node/desktopfile-endpoint.ts
type DesktopFileInformation (line 20) | interface DesktopFileInformation {
class TheiaDesktopFileServiceEndpoint (line 26) | class TheiaDesktopFileServiceEndpoint implements BackendApplicationContr...
method configure (line 34) | configure(app: Application): void {
method isInitialized (line 42) | protected async isInitialized(_request: Request, response: Response): ...
method readAppImageInformationFromStorage (line 74) | protected async readAppImageInformationFromStorage(storageFile: string...
method createOrUpdateDesktopfile (line 87) | protected async createOrUpdateDesktopfile(request: Request, response: ...
method getDesktopFileContents (line 145) | protected getDesktopFileContents(applicationName: string, appImagePath...
method getDesktopURLFileContents (line 158) | protected getDesktopURLFileContents(applicationName: string, appImageP...
FILE: theia-extensions/launcher/src/node/launcher-endpoint.ts
type PathEntry (line 21) | interface PathEntry {
class TheiaLauncherServiceEndpoint (line 27) | class TheiaLauncherServiceEndpoint implements BackendApplicationContribu...
method configure (line 36) | configure(app: Application): void {
method isInitialized (line 44) | private async isInitialized(request: Request, response: Response): Pro...
method readLauncherPathsFromStorage (line 65) | private async readLauncherPathsFromStorage(storageFile: string): Promi...
method getLogFilePath (line 77) | private async getLogFilePath(): Promise<string> {
method createLauncher (line 83) | private async createLauncher(request: Request, response: Response): Pr...
FILE: theia-extensions/launcher/src/node/launcher-util.ts
function getStorageFilePath (line 13) | async function getStorageFilePath(envServer: EnvVariablesServer, fileNam...
FILE: theia-extensions/product/src/browser/branding-util.tsx
type ExternalBrowserLinkProps (line 14) | interface ExternalBrowserLinkProps {
function renderProductName (line 20) | function renderProductName(): React.ReactNode {
function BrowserLink (line 26) | function BrowserLink(props: ExternalBrowserLinkProps): JSX.Element {
function renderWhatIs (line 37) | function renderWhatIs(windowService: WindowService): React.ReactNode {
function renderExtendingCustomizing (line 55) | function renderExtendingCustomizing(windowService: WindowService): React...
function renderSupport (line 73) | function renderSupport(windowService: WindowService): React.ReactNode {
function renderTickets (line 86) | function renderTickets(windowService: WindowService): React.ReactNode {
function renderSourceCode (line 107) | function renderSourceCode(windowService: WindowService): React.ReactNode {
function renderDocumentation (line 120) | function renderDocumentation(windowService: WindowService): React.ReactN...
function renderCollaboration (line 132) | function renderCollaboration(windowService: WindowService): React.ReactN...
function renderDownloads (line 147) | function renderDownloads(): React.ReactNode {
FILE: theia-extensions/product/src/browser/theia-ide-about-dialog.tsx
class TheiaIDEAboutDialog (line 17) | class TheiaIDEAboutDialog extends AboutDialog {
method constructor (line 27) | constructor(
method doInit (line 33) | protected async doInit(): Promise<void> {
method render (line 38) | protected render(): React.ReactNode {
method renderContent (line 44) | protected renderContent(): React.ReactNode {
method renderTitle (line 87) | protected renderTitle(): React.ReactNode {
method renderVersion (line 94) | protected renderVersion(): React.ReactNode {
FILE: theia-extensions/product/src/browser/theia-ide-config.ts
type BrandingVariant (line 12) | type BrandingVariant = 'stable' | 'next';
function getBrandingVariant (line 14) | function getBrandingVariant(): BrandingVariant {
function applyBranding (line 23) | function applyBranding(): void {
FILE: theia-extensions/product/src/browser/theia-ide-contribution.tsx
class TheiaIDEContribution (line 34) | class TheiaIDEContribution implements CommandContribution, MenuContribut...
method registerCommands (line 42) | registerCommands(commandRegistry: CommandRegistry): void {
method registerMenus (line 51) | registerMenus(menus: MenuModelRegistry): void {
FILE: theia-extensions/product/src/browser/theia-ide-getting-started-widget.tsx
class TheiaIDEGettingStartedWidget (line 24) | class TheiaIDEGettingStartedWidget extends GettingStartedWidget {
method doInit (line 37) | protected async doInit(): Promise<void> {
method onActivateRequest (line 44) | protected onActivateRequest(msg: Message): void {
method render (line 52) | protected render(): React.ReactNode {
method renderActions (line 119) | protected renderActions(): React.ReactNode {
method renderHeader (line 144) | protected renderHeader(): React.ReactNode {
method renderVersion (line 151) | protected renderVersion(): React.ReactNode {
method renderAIBanner (line 163) | protected renderAIBanner(): React.ReactNode {
FILE: theia-extensions/product/src/electron-main/icon-contribution.ts
class IconContribution (line 19) | class IconContribution implements ElectronMainApplicationContribution {
method onStart (line 21) | onStart(application: ElectronMainApplication): void {
FILE: theia-extensions/updater/src/common/updater/theia-updater.ts
type UpdaterSettings (line 14) | interface UpdaterSettings {
type TheiaUpdater (line 20) | interface TheiaUpdater extends RpcServer<TheiaUpdaterClient> {
type UpdaterError (line 31) | interface UpdaterError {
type UpdateInfo (line 36) | interface UpdateInfo {
type UpdateAvailabilityInfo (line 40) | interface UpdateAvailabilityInfo {
type TheiaUpdaterClient (line 45) | interface TheiaUpdaterClient {
FILE: theia-extensions/updater/src/electron-browser/updater/theia-updater-frontend-contribution.ts
class TheiaUpdaterClientImpl (line 52) | class TheiaUpdaterClientImpl implements TheiaUpdaterClient {
method notifyReadyToInstall (line 66) | notifyReadyToInstall(): void {
method updateAvailable (line 70) | updateAvailable(available: boolean, updateInfo?: UpdateInfo): void {
method reportError (line 74) | reportError(error: UpdaterError): void {
method reportCancelled (line 78) | reportCancelled(): void {
class ElectronMenuUpdater (line 86) | class ElectronMenuUpdater {
method update (line 91) | public update(): void {
method setMenu (line 95) | private setMenu(): void {
class TheiaUpdaterFrontendContribution (line 102) | class TheiaUpdaterFrontendContribution implements CommandContribution, M...
method init (line 129) | protected init(): void {
method syncUpdaterSettings (line 160) | protected syncUpdaterSettings(): void {
method registerCommands (line 169) | registerCommands(registry: CommandRegistry): void {
method registerMenus (line 184) | registerMenus(registry: MenuModelRegistry): void {
method handleDownloadUpdate (line 193) | protected async handleDownloadUpdate(updateInfo?: UpdateInfo): Promise...
method handleNoUpdate (line 224) | protected async handleNoUpdate(): Promise<void> {
method handleUpdatesAvailable (line 228) | protected async handleUpdatesAvailable(): Promise<void> {
method handleError (line 242) | protected async handleError(error: UpdaterError): Promise<void> {
method stopProgress (line 257) | private stopProgress(): void {
FILE: theia-extensions/updater/src/electron-browser/updater/theia-updater-preferences.ts
constant DEFAULT_UPDATE_CHANNELS (line 13) | const DEFAULT_UPDATE_CHANNELS = ['stable', 'preview'];
function getAvailableUpdateChannels (line 15) | function getAvailableUpdateChannels(): string[] {
FILE: theia-extensions/updater/src/electron-main/update/theia-updater-impl.ts
constant STABLE_CHANNEL_WINDOWS (line 20) | const STABLE_CHANNEL_WINDOWS = 'https://download.eclipse.org/theia/ide/v...
constant STABLE_CHANNEL_MACOS (line 21) | const STABLE_CHANNEL_MACOS = 'https://download.eclipse.org/theia/ide/lat...
constant STABLE_CHANNEL_MACOS_ARM (line 22) | const STABLE_CHANNEL_MACOS_ARM = 'https://download.eclipse.org/theia/ide...
constant STABLE_CHANNEL_LINUX (line 23) | const STABLE_CHANNEL_LINUX = 'https://download.eclipse.org/theia/ide/lat...
constant PREVIEW_CHANNEL_WINDOWS (line 25) | const PREVIEW_CHANNEL_WINDOWS = 'https://download.eclipse.org/theia/ide-...
constant PREVIEW_CHANNEL_MACOS (line 26) | const PREVIEW_CHANNEL_MACOS = 'https://download.eclipse.org/theia/ide-pr...
constant PREVIEW_CHANNEL_MACOS_ARM (line 27) | const PREVIEW_CHANNEL_MACOS_ARM = 'https://download.eclipse.org/theia/id...
constant PREVIEW_CHANNEL_LINUX (line 28) | const PREVIEW_CHANNEL_LINUX = 'https://download.eclipse.org/theia/ide-pr...
constant NEXT_CHANNEL_LINUX (line 32) | const NEXT_CHANNEL_LINUX = 'https://github.com/eclipse-theia/theia-ide/r...
class TheiaUpdaterImpl (line 40) | class TheiaUpdaterImpl implements TheiaUpdater, ElectronMainApplicationC...
method constructor (line 54) | constructor() {
method checkForUpdates (line 87) | checkForUpdates(): void {
method setUpdaterSettings (line 93) | setUpdaterSettings(settings: UpdaterSettings): void {
method onRestartToUpdateRequested (line 103) | onRestartToUpdateRequested(): void {
method cancel (line 107) | cancel(): void {
method downloadUpdate (line 113) | downloadUpdate(): void {
method onStart (line 131) | onStart(application: ElectronMainApplication): void {
method onStop (line 134) | onStop(application: ElectronMainApplication): void {
method scheduleUpdateChecks (line 138) | private scheduleUpdateChecks(): void {
method stopUpdateCheckTimer (line 156) | private stopUpdateCheckTimer(): void {
method setClient (line 163) | setClient(client: TheiaUpdaterClient | undefined): void {
method getFeedURL (line 173) | protected getFeedURL(channel: string): string {
method disconnectClient (line 193) | disconnectClient(client: TheiaUpdaterClient): void {
method dispose (line 200) | dispose(): void {
Condensed preview — 136 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (383K chars).
[
{
"path": ".eslintrc.js",
"chars": 549,
"preview": "/** @type {import('eslint').Linter.Config} */\nmodule.exports = {\n root: true,\n extends: [\n './configs/base."
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 456,
"preview": "---\nname: Bug Report\nabout: Create a report to help us improve\n---\n\n<!-- Please provide a detailed description of the bu"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 161,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Question\n url: https://github.com/eclipse-theia/theia/discussio"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 255,
"preview": "---\nname: Feature Request\nabout: Propose an idea for the project\n---\n\n<!-- Please fill out the following content for a f"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 813,
"preview": "<!--\nThank you for your Pull Request. Please provide a description and review\nthe requirements below.\n\nContributors guid"
},
{
"path": ".github/workflows/build-next-release.yml",
"chars": 2981,
"preview": "name: Build Theia IDE Next Release (Linux)\n\non:\n workflow_dispatch:\n schedule:\n - cron: \"0 2 * * 1-5\" # Runs every "
},
{
"path": ".github/workflows/build-next.yml",
"chars": 3629,
"preview": "name: Build Theia IDE next version\n\non:\n workflow_dispatch:\n schedule:\n - cron: \"0 3 * * 1\" # Runs every monday at "
},
{
"path": ".github/workflows/build.yml",
"chars": 5070,
"preview": "name: Build, package and test\n\non:\n push:\n branches:\n - master\n paths-ignore:\n - '**/*.md'\n - 'The"
},
{
"path": ".github/workflows/license-check-workflow.yml",
"chars": 3277,
"preview": "name: 3PP License Check\n\non:\n push:\n branches:\n - master\n paths:\n - 'yarn.lock'\n workflow_dispatch:\n "
},
{
"path": ".github/workflows/publish-builder-img.yml",
"chars": 815,
"preview": "name: Publish builder image\n\non:\n schedule:\n - cron: \"0 0 1 * *\" # runs 1st day of every month\n workflow_dispatch:\n"
},
{
"path": ".github/workflows/publish-theia-ide-img.yml",
"chars": 1870,
"preview": "name: Publish Theia IDE Docker Image\n\non:\n workflow_dispatch:\n inputs:\n tag:\n description: The image's t"
},
{
"path": ".gitignore",
"chars": 247,
"preview": ".DS_Store\n**/node_modules\n**/.browser_modules\n**/dist\n**/lib\n**/src-gen\n**/gen-webpack.config.js\n**/gen-webpack.node.con"
},
{
"path": ".vscode/launch.json",
"chars": 6274,
"preview": "{\n // Use IntelliSense to learn about possible Node.js debug attributes.\n // Hover to view descriptions of existing at"
},
{
"path": ".vscode/settings.json",
"chars": 97,
"preview": "{\n \"[markdown]\": {\n \"editor.defaultFormatter\": \"davidanson.vscode-markdownlint\"\n }\n}"
},
{
"path": ".vscode/theia.code-snippets",
"chars": 687,
"preview": "{\n \"Copyright-JS/JSX/TS/TSX/CSS\": {\n \"prefix\": [\n \"header\",\n \"copyright\"\n ],\n "
},
{
"path": "ADOPTER.md",
"chars": 2948,
"preview": "# Adopter Guide\n\nThis repository serves as a template for building desktop products on the [Eclipse Theia platform](http"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3900,
"preview": "<div id=\"theia-logo\" align=\"left\">\n <br />\n <img src=\"https://raw.githubusercontent.com/eclipse-theia/theia/master"
},
{
"path": "CONTRIBUTING.md",
"chars": 4986,
"preview": "# Contributing to Eclipse Theia\n\nTheia is a young open-source project with a modular architecture. One of the\ngoals is t"
},
{
"path": "Dockerfile",
"chars": 787,
"preview": "# See the associated GitHub workflow, that builds and publishes\n# this docker image to Docker Hub:\n# .github/workflows/p"
},
{
"path": "LICENSE",
"chars": 1082,
"preview": "MIT License\n\nCopyright (c) 2020 Eclipse Theia IDE Authors\n\nPermission is hereby granted, free of charge, to any person o"
},
{
"path": "NOTICE.md",
"chars": 8549,
"preview": "# Notices for Eclipse Theia\n\nThis content is produced and maintained by the Eclipse Theia project.\n\n* Project home: http"
},
{
"path": "PUBLISHING.md",
"chars": 16067,
"preview": "# Publishing Guide for the Eclipse Theia IDE\n\nThis document provides a unified, structured guide for publishing a new ve"
},
{
"path": "README.md",
"chars": 7397,
"preview": "<br/>\n<div id=\"theia-logo\" align=\"center\">\n <br />\n <img src=\"https://raw.githubusercontent.com/eclipse-theia/thei"
},
{
"path": "applications/browser/package.json",
"chars": 5128,
"preview": "{\n \"private\": true,\n \"name\": \"theia-ide-browser-app\",\n \"description\": \"Eclipse Theia IDE browser product\",\n \"product"
},
{
"path": "applications/browser/resources/preload.html",
"chars": 4491,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <style>\n html,\n body {\n background-color: black;\n "
},
{
"path": "applications/browser/tsconfig.json",
"chars": 283,
"preview": "{\n \"extends\": \"../../configs/base.tsconfig\",\n \"include\": [],\n \"compilerOptions\": {\n \"composite\": true\n "
},
{
"path": "applications/browser/webpack.config.js",
"chars": 1028,
"preview": "/**\n * This file can be edited to customize webpack configuration.\n * To reset delete this file and rerun theia build ag"
},
{
"path": "applications/electron/.eslintrc.js",
"chars": 237,
"preview": "/** @type {import('eslint').Linter.Config} */\nmodule.exports = {\n extends: [\n '../../configs/build.eslintrc.js"
},
{
"path": "applications/electron/electron-builder.yml",
"chars": 2320,
"preview": "appId: eclipse.theia\nproductName: TheiaIDE\ncopyright: Copyright © 2020-2025 Eclipse Foundation, Inc\nelectronDist: ../../"
},
{
"path": "applications/electron/entitlements.plist",
"chars": 491,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "applications/electron/package.json",
"chars": 7001,
"preview": "{\n \"private\": true,\n \"name\": \"theia-ide-electron-app\",\n \"description\": \"Eclipse Theia IDE product\",\n \"productName\": "
},
{
"path": "applications/electron/resources/LICENSE",
"chars": 1088,
"preview": "MIT License\n\nCopyright (c) 2020 Eclipse Theia Blueprint Authors\n\nPermission is hereby granted, free of charge, to any pe"
},
{
"path": "applications/electron/resources/icons/MacLauncherIcons/icon.icon/icon.json",
"chars": 1778,
"preview": "{\n \"fill\" : {\n \"automatic-gradient\" : \"extended-srgb:0.00000,0.53333,1.00000,1.00000\"\n },\n \"groups\" : [\n {\n "
},
{
"path": "applications/electron/resources/preload.html",
"chars": 4253,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <style>\n html,\n body {\n background-color: black;\n "
},
{
"path": "applications/electron/scripts/after-pack.js",
"chars": 4156,
"preview": "#!/usr/bin/env node\n\nconst fs = require('fs');\nconst path = require('path');\nconst util = require('util');\nconst child_p"
},
{
"path": "applications/electron/scripts/appimage-helpers.js",
"chars": 3126,
"preview": "const fs = require('fs');\nconst path = require('path');\n\n/**\n * Reads the plugin copy metadata file and returns its cont"
},
{
"path": "applications/electron/scripts/generate-app-update-yml.js",
"chars": 1901,
"preview": "#!/usr/bin/env node\n\n/********************************************************************************\n * Copyright (C) "
},
{
"path": "applications/electron/scripts/notarize.sh",
"chars": 1965,
"preview": "#!/bin/bash -x\n\nINPUT=$1\nAPP_ID=$2\nNEEDS_UNZIP=false\nUUID_REGEX='\"uuid\"\\s*:\\s*\"([^\"]+)'\nSTATUS_REGEX='\"status\"\\s*:\\s*\"(["
},
{
"path": "applications/electron/scripts/sign-directory-windows.ts",
"chars": 6163,
"preview": "/********************************************************************************\n * Copyright (C) 2026 EclipseSource an"
},
{
"path": "applications/electron/scripts/sign-directory.ts",
"chars": 5615,
"preview": "/********************************************************************************\n * Copyright (C) 2025 EclipseSource an"
},
{
"path": "applications/electron/scripts/sign-utils.ts",
"chars": 2712,
"preview": "/********************************************************************************\n * Copyright (C) 2026 EclipseSource an"
},
{
"path": "applications/electron/scripts/sign.sh",
"chars": 4809,
"preview": "#!/bin/bash -x\n\n# Enable debug output\nset -x\n\nINPUT=$1\nENTITLEMENTS=$2\nNEEDS_UNZIP=false\n\necho \"=== DEBUG: Starting sign"
},
{
"path": "applications/electron/scripts/theia-electron-main.js",
"chars": 1859,
"preview": "const path = require('path');\nconst fs = require('fs');\nconst os = require('os');\nconst { copyBundledPlugins } = require"
},
{
"path": "applications/electron/scripts/update-blockmap.ts",
"chars": 1551,
"preview": "/********************************************************************************\n * Copyright (C) 2023 EclipseSource an"
},
{
"path": "applications/electron/scripts/update-checksum.ts",
"chars": 4440,
"preview": "/********************************************************************************\n * Copyright (C) 2021 EclipseSource an"
},
{
"path": "applications/electron/test/app.spec.js",
"chars": 10085,
"preview": "const os = require('os');\nconst path = require('path');\nconst fs = require('fs');\nconst { execSync } = require('child_pr"
},
{
"path": "applications/electron/test/workspace/README.md",
"chars": 60,
"preview": "# Test Workspace\n\nThis is the test workspace for E2E tests.\n"
},
{
"path": "applications/electron/tsconfig.eslint.json",
"chars": 154,
"preview": "{\n \"extends\": \"./tsconfig.json\",\n \"compilerOptions\": {\n \"noEmit\": true\n },\n \"include\": [\n \"./scr"
},
{
"path": "applications/electron/tsconfig.json",
"chars": 380,
"preview": "{\n \"extends\": \"../../configs/base.tsconfig\",\n \"include\": [],\n \"compilerOptions\": {\n \"composite\": true,\n "
},
{
"path": "applications/electron/webpack.config.js",
"chars": 5108,
"preview": "/**\n * This file can be edited to customize webpack configuration.\n * To reset delete this file and rerun theia build ag"
},
{
"path": "applications/electron-next/.eslintrc.js",
"chars": 237,
"preview": "/** @type {import('eslint').Linter.Config} */\nmodule.exports = {\n extends: [\n '../../configs/build.eslintrc.js"
},
{
"path": "applications/electron-next/electron-builder.yml",
"chars": 1098,
"preview": "appId: eclipse.theia.next\nproductName: TheiaIDENext\ncopyright: Copyright © 2020-2025 Eclipse Foundation, Inc\nelectronDis"
},
{
"path": "applications/electron-next/package.json",
"chars": 6947,
"preview": "{\n \"private\": true,\n \"name\": \"theia-ide-next-electron-app\",\n \"description\": \"Eclipse Theia IDE Next product\",\n \"prod"
},
{
"path": "applications/electron-next/resources/LICENSE",
"chars": 1082,
"preview": "MIT License\n\nCopyright (c) 2026 Eclipse Theia IDE Authors\n\nPermission is hereby granted, free of charge, to any person o"
},
{
"path": "applications/electron-next/resources/preload.html",
"chars": 4068,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <style>\n html,\n body {\n background-color: black;\n "
},
{
"path": "applications/electron-next/scripts/after-pack.js",
"chars": 1118,
"preview": "#!/usr/bin/env node\n\nconst fs = require('fs');\nconst path = require('path');\n\n// Signing and notarizing are not needed f"
},
{
"path": "applications/electron-next/scripts/appimage-helpers.js",
"chars": 3126,
"preview": "const fs = require('fs');\nconst path = require('path');\n\n/**\n * Reads the plugin copy metadata file and returns its cont"
},
{
"path": "applications/electron-next/scripts/theia-electron-main.js",
"chars": 1864,
"preview": "const path = require('path');\nconst fs = require('fs');\nconst os = require('os');\nconst { copyBundledPlugins } = require"
},
{
"path": "applications/electron-next/test/workspace/README.md",
"chars": 60,
"preview": "# Test Workspace\n\nThis is the test workspace for E2E tests.\n"
},
{
"path": "applications/electron-next/tsconfig.eslint.json",
"chars": 136,
"preview": "{\n \"extends\": \"./tsconfig.json\",\n \"compilerOptions\": {\n \"noEmit\": true\n },\n \"include\": [\n \"./scr"
},
{
"path": "applications/electron-next/tsconfig.json",
"chars": 313,
"preview": "{\n \"extends\": \"../../configs/base.tsconfig\",\n \"include\": [],\n \"compilerOptions\": {\n \"composite\": true,\n "
},
{
"path": "applications/electron-next/webpack.config.js",
"chars": 5109,
"preview": "/**\n * This file can be edited to customize webpack configuration.\n * To reset delete this file and rerun theia build ag"
},
{
"path": "browser.Dockerfile",
"chars": 2330,
"preview": "# Builder stage\nFROM node:24-bookworm AS build-stage\n\n# install required tools to build the application\nRUN apt-get upda"
},
{
"path": "cleanup/Jenkinsfile",
"chars": 2240,
"preview": "pipeline {\n agent {\n label 'windows'\n }\n triggers { cron('@weekly') }\n options {\n timeout(time"
},
{
"path": "configs/base.eslintrc.json",
"chars": 403,
"preview": "{\n \"parser\": \"@typescript-eslint/parser\",\n \"parserOptions\": {\n \"sourceType\": \"module\",\n \"ecmaVersion\": 6,\n \"e"
},
{
"path": "configs/base.tsconfig.json",
"chars": 706,
"preview": "{\n \"compilerOptions\": {\n \"skipLibCheck\": true,\n \"declaration\": true,\n \"declarationMap\": true,\n "
},
{
"path": "configs/build.eslintrc.json",
"chars": 80,
"preview": "{\n \"extends\": [\n \"./base.eslintrc.json\",\n \"./errors.eslintrc.json\"\n ]\n}\n"
},
{
"path": "configs/errors.eslintrc.json",
"chars": 2966,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/eslintrc\",\n \"rules\": {\n \"@typescript-eslint/consistent-type-definitions"
},
{
"path": "configs/license-check-config.json",
"chars": 141,
"preview": "{\n \"project\": \"ecd.theia\",\n \"inputFile\": \"yarn.lock\",\n \"batch\": 50,\n \"timeout\": 240,\n \"summary\": \"license"
},
{
"path": "configs/tsconfig.eslint.json",
"chars": 140,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"noEmit\": true\n },\n \"include\": [\n \"../s"
},
{
"path": "configs/warnings.eslintrc.json",
"chars": 176,
"preview": "{\n \"plugins\": [\n \"deprecation\"\n ],\n \"rules\": {\n \"@typescript-eslint/await-thenable\": \"warn\",\n \"no-return-awa"
},
{
"path": "configs/xss.eslintrc.json",
"chars": 582,
"preview": "{\n \"extends\": [\"plugin:no-unsanitized/DOM\"],\n \"plugins\": [\"no-unsanitized\", \"react\"],\n \"parserOptions\": {\n \"ecmaFe"
},
{
"path": "docs/developing-with-local-theia.md",
"chars": 6056,
"preview": "# Developing with a Local Theia Framework\n\nThis guide explains how to build and test the Theia IDE against a local devel"
},
{
"path": "lerna.json",
"chars": 148,
"preview": "{\n \"$schema\": \"node_modules/lerna/schemas/lerna-schema.json\",\n \"version\": \"1.71.100\",\n \"command\": {\n \"run\": {\n "
},
{
"path": "next/Jenkinsfile",
"chars": 5737,
"preview": "/**\n * This Jenkinsfile builds Theia Next across the major OS platforms\n */\nimport groovy.json.JsonSlurper\n\ndistFolder ="
},
{
"path": "next/NEXT_INTEGRATION_BUILD.md",
"chars": 1236,
"preview": "# Integration build against Theia@next\n\nThe master branch has a script that may be used to update all theia versions to "
},
{
"path": "package.json",
"chars": 4394,
"preview": "{\n \"private\": true,\n \"version\": \"1.71.100\",\n \"license\": \"MIT\",\n \"author\": \"Rob Moran <github@thegecko.org>\",\n \"home"
},
{
"path": "patches/@theia+terminal+1.72.0-next.20.patch",
"chars": 751,
"preview": "diff --git a/node_modules/@theia/terminal/lib/node/shell-integration-injector.js b/node_modules/@theia/terminal/lib/node"
},
{
"path": "releng/preview/Jenkinsfile.build",
"chars": 15035,
"preview": "/**\n * This Jenkinsfile builds Theia across the major OS platforms\n * It's designed to be run only manually\n */\n\nimport "
},
{
"path": "releng/preview/Jenkinsfile.sign",
"chars": 14635,
"preview": "/**\n * This Jenkinsfile handles signing and notarizing Theia installers\n * It's designed to be run automatically after t"
},
{
"path": "releng/preview/Jenkinsfile.upload",
"chars": 17028,
"preview": "/**\n * This Jenkinsfile handles updating metadata and uploading the Theia installers\n * It's designed to be run automati"
},
{
"path": "releng/promote/Jenkinsfile",
"chars": 4238,
"preview": "/**\n * This Jenkinsfile promotes a given version of the Theia IDE from /theia/ide-preview to /theia/ide\n */\n\n/* groovyli"
},
{
"path": "scripts/build-with-local-theia.js",
"chars": 12599,
"preview": "#!/usr/bin/env node\n\n/**\n * Script to build Theia IDE with a local Theia framework development version.\n *\n * This allow"
},
{
"path": "scripts/generate-next-icons.js",
"chars": 4401,
"preview": "#!/usr/bin/env node\n// @ts-check\n\n/**\n * Generates next icons by recoloring the Theia IDE blue (#00ADEE) to\n * next purp"
},
{
"path": "scripts/make-files-writeable.ts",
"chars": 1999,
"preview": "/********************************************************************************\n * Copyright (C) 2025 EclipseSource an"
},
{
"path": "scripts/update-theia-version.ts",
"chars": 1813,
"preview": "/********************************************************************************\n * Copyright (C) 2021 EclipseSource an"
},
{
"path": "theia-extensions/launcher/.eslintrc.js",
"chars": 230,
"preview": "/** @type {import('eslint').Linter.Config} */\nmodule.exports = {\n extends: [\n '../../configs/build.eslintrc.js"
},
{
"path": "theia-extensions/launcher/package.json",
"chars": 1154,
"preview": "{\n \"name\": \"theia-ide-launcher-ext\",\n \"version\": \"1.71.100\",\n \"keywords\": [\n \"theia-extension\"\n ],\n \"license\": \""
},
{
"path": "theia-extensions/launcher/src/browser/create-launcher-contribution.ts",
"chars": 4299,
"preview": "/********************************************************************************\n * Copyright (C) 2022-2024 EclipseSour"
},
{
"path": "theia-extensions/launcher/src/browser/create-launcher-frontend-module.ts",
"chars": 982,
"preview": "/********************************************************************************\n * Copyright (C) 2022-2024 EclipseSour"
},
{
"path": "theia-extensions/launcher/src/browser/desktopfile-service.ts",
"chars": 1469,
"preview": "/********************************************************************************\n * Copyright (C) 2024 STMicroelectroni"
},
{
"path": "theia-extensions/launcher/src/browser/launcher-service.ts",
"chars": 1421,
"preview": "/********************************************************************************\n * Copyright (C) 2022 EclipseSource an"
},
{
"path": "theia-extensions/launcher/src/node/desktopfile-endpoint.ts",
"chars": 7629,
"preview": "/********************************************************************************\n * Copyright (C) 2024 STMicroelectroni"
},
{
"path": "theia-extensions/launcher/src/node/launcher-backend-module.ts",
"chars": 1056,
"preview": "/********************************************************************************\n * Copyright (C) 2022-2024 EclipseSour"
},
{
"path": "theia-extensions/launcher/src/node/launcher-endpoint.ts",
"chars": 4649,
"preview": "/********************************************************************************\n * Copyright (C) 2022-2024 EclipseSour"
},
{
"path": "theia-extensions/launcher/src/node/launcher-util.ts",
"chars": 923,
"preview": "/********************************************************************************\n * Copyright (C) 2024 STMicroelectroni"
},
{
"path": "theia-extensions/launcher/tsconfig.json",
"chars": 188,
"preview": "{\n \"extends\": \"../../configs/base.tsconfig\",\n \"compilerOptions\": {\n \"rootDir\": \"src\",\n \"outDir\": \"lib\",\n \"bas"
},
{
"path": "theia-extensions/product/.eslintrc.js",
"chars": 230,
"preview": "/** @type {import('eslint').Linter.Config} */\nmodule.exports = {\n extends: [\n '../../configs/build.eslintrc.js"
},
{
"path": "theia-extensions/product/package.json",
"chars": 1349,
"preview": "{\n \"private\": true,\n \"name\": \"theia-ide-product-ext\",\n \"version\": \"1.71.100\",\n \"description\": \"Eclipse Theia IDE Pro"
},
{
"path": "theia-extensions/product/src/browser/branding-util.tsx",
"chars": 7533,
"preview": "/********************************************************************************\n * Copyright (C) 2020 EclipseSource an"
},
{
"path": "theia-extensions/product/src/browser/style/index.css",
"chars": 1795,
"preview": "/********************************************************************************\n * Copyright (C) 2020 EclipseSource an"
},
{
"path": "theia-extensions/product/src/browser/theia-ide-about-dialog.tsx",
"chars": 3582,
"preview": "/********************************************************************************\n * Copyright (C) 2020 EclipseSource an"
},
{
"path": "theia-extensions/product/src/browser/theia-ide-config.ts",
"chars": 1032,
"preview": "/********************************************************************************\n * Copyright (C) 2026 EclipseSource an"
},
{
"path": "theia-extensions/product/src/browser/theia-ide-contribution.tsx",
"chars": 2663,
"preview": "/********************************************************************************\n * Copyright (C) 2021 Ericsson and oth"
},
{
"path": "theia-extensions/product/src/browser/theia-ide-frontend-module.ts",
"chars": 1912,
"preview": "/********************************************************************************\n * Copyright (C) 2020 TypeFox, Eclipse"
},
{
"path": "theia-extensions/product/src/browser/theia-ide-getting-started-widget.tsx",
"chars": 6104,
"preview": "/********************************************************************************\n * Copyright (C) 2020 EclipseSource an"
},
{
"path": "theia-extensions/product/src/electron-main/icon-contribution.ts",
"chars": 1706,
"preview": "/********************************************************************************\n * Copyright (C) 2021 EclipseSource an"
},
{
"path": "theia-extensions/product/src/electron-main/theia-ide-main-module.ts",
"chars": 809,
"preview": "/********************************************************************************\n * Copyright (C) 2021 EclipseSource an"
},
{
"path": "theia-extensions/product/tsconfig.json",
"chars": 227,
"preview": "{\n \"extends\": \"../../configs/base.tsconfig\",\n \"compilerOptions\": {\n \"rootDir\": \"src\",\n \"outDir\": \"li"
},
{
"path": "theia-extensions/updater/.eslintrc.js",
"chars": 230,
"preview": "/** @type {import('eslint').Linter.Config} */\nmodule.exports = {\n extends: [\n '../../configs/build.eslintrc.js"
},
{
"path": "theia-extensions/updater/package.json",
"chars": 1396,
"preview": "{\n \"private\": true,\n \"name\": \"theia-ide-updater-ext\",\n \"version\": \"1.71.100\",\n \"description\": \"Eclipse Theia IDE Upd"
},
{
"path": "theia-extensions/updater/src/common/updater/theia-updater.ts",
"chars": 1555,
"preview": "/********************************************************************************\n * Copyright (C) 2020 TypeFox, Eclipse"
},
{
"path": "theia-extensions/updater/src/electron-browser/theia-updater-frontend-module.ts",
"chars": 1893,
"preview": "/********************************************************************************\n * Copyright (C) 2020 TypeFox, Eclipse"
},
{
"path": "theia-extensions/updater/src/electron-browser/updater/theia-updater-frontend-contribution.ts",
"chars": 9645,
"preview": "/********************************************************************************\n * Copyright (C) 2020 TypeFox, Eclipse"
},
{
"path": "theia-extensions/updater/src/electron-browser/updater/theia-updater-preferences.ts",
"chars": 1728,
"preview": "/********************************************************************************\n * Copyright (C) 2020 EclipseSource an"
},
{
"path": "theia-extensions/updater/src/electron-main/update/theia-updater-impl.ts",
"chars": 7879,
"preview": "/********************************************************************************\n * Copyright (C) 2020 TypeFox, Eclipse"
},
{
"path": "theia-extensions/updater/src/electron-main/update/theia-updater-main-module.ts",
"chars": 1585,
"preview": "/********************************************************************************\n * Copyright (C) 2020 TypeFox, Eclipse"
},
{
"path": "theia-extensions/updater/tsconfig.json",
"chars": 227,
"preview": "{\n \"extends\": \"../../configs/base.tsconfig\",\n \"compilerOptions\": {\n \"rootDir\": \"src\",\n \"outDir\": \"li"
},
{
"path": "tsconfig.json",
"chars": 423,
"preview": "{\n \"extends\": \"./configs/base.tsconfig.json\",\n \"include\": [],\n \"compilerOptions\": {\n \"composite\": true,\n \"allow"
}
]
// ... and 17 more files (download for full content)
About this extraction
This page contains the full source code of the eclipse-theia/theia-ide GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 136 files (351.1 KB), approximately 91.6k tokens, and a symbol index with 174 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.