diff --git a/frontend/hoverContribution.js b/frontend/hoverContribution.js
new file mode 100644
index 0000000000000..003f3ca018e40
--- /dev/null
+++ b/frontend/hoverContribution.js
@@ -0,0 +1,88 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import {
+ DecreaseHoverVerbosityLevel,
+ GoToBottomHoverAction,
+ GoToTopHoverAction,
+ HideContentHoverAction,
+ IncreaseHoverVerbosityLevel,
+ PageDownHoverAction,
+ PageUpHoverAction,
+ ScrollDownHoverAction,
+ ScrollLeftHoverAction,
+ ScrollRightHoverAction,
+ ScrollUpHoverAction,
+ ShowDefinitionPreviewHoverAction,
+ ShowOrFocusHoverAction
+} from './hoverActions.js'
+import {
+ EditorContributionInstantiation,
+ registerEditorAction,
+ registerEditorContribution
+} from '../../../browser/editorExtensions.js'
+import { editorHoverBorder } from '../../../../platform/theme/common/colorRegistry.js'
+import { registerThemingParticipant } from '../../../../platform/theme/common/themeService.js'
+import { HoverParticipantRegistry } from './hoverTypes.js'
+import { MarkdownHoverParticipant } from './markdownHoverParticipant.js'
+import { MarkerHoverParticipant } from './markerHoverParticipant.js'
+import { ContentHoverController } from './contentHoverController.js'
+import { GlyphHoverController } from './glyphHoverController.js'
+import './hover.css'
+import { AccessibleViewRegistry } from '../../../../platform/accessibility/browser/accessibleViewRegistry.js'
+import {
+ ExtHoverAccessibleView,
+ HoverAccessibilityHelp,
+ HoverAccessibleView
+} from './hoverAccessibleViews.js'
+
+registerEditorContribution(
+ ContentHoverController.ID,
+ ContentHoverController,
+ EditorContributionInstantiation.BeforeFirstInteraction
+)
+registerEditorContribution(
+ GlyphHoverController.ID,
+ GlyphHoverController,
+ EditorContributionInstantiation.BeforeFirstInteraction
+)
+registerEditorAction(ShowOrFocusHoverAction)
+registerEditorAction(ShowDefinitionPreviewHoverAction)
+registerEditorAction(HideContentHoverAction)
+registerEditorAction(ScrollUpHoverAction)
+registerEditorAction(ScrollDownHoverAction)
+registerEditorAction(ScrollLeftHoverAction)
+registerEditorAction(ScrollRightHoverAction)
+registerEditorAction(PageUpHoverAction)
+registerEditorAction(PageDownHoverAction)
+registerEditorAction(GoToTopHoverAction)
+registerEditorAction(GoToBottomHoverAction)
+registerEditorAction(IncreaseHoverVerbosityLevel)
+registerEditorAction(DecreaseHoverVerbosityLevel)
+HoverParticipantRegistry.register(MarkdownHoverParticipant)
+HoverParticipantRegistry.register(MarkerHoverParticipant)
+
+// theming
+registerThemingParticipant((theme, collector) => {
+ const hoverBorder = theme.getColor(editorHoverBorder)
+ if (hoverBorder) {
+ collector.addRule(
+ `.monaco-editor .monaco-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(
+ 0.5
+ )}; }`
+ )
+ collector.addRule(
+ `.monaco-editor .monaco-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`
+ )
+ collector.addRule(
+ `.monaco-editor .monaco-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(
+ 0.5
+ )}; }`
+ )
+ }
+})
+AccessibleViewRegistry.register(new HoverAccessibleView())
+AccessibleViewRegistry.register(new HoverAccessibilityHelp())
+AccessibleViewRegistry.register(new ExtHoverAccessibleView())
diff --git a/frontend/src/lib/components/raw_apps/RawAppCodeEditor.svelte b/frontend/src/lib/components/raw_apps/RawAppCodeEditor.svelte
new file mode 100644
index 0000000000000..17f8d09db981a
--- /dev/null
+++ b/frontend/src/lib/components/raw_apps/RawAppCodeEditor.svelte
@@ -0,0 +1,195 @@
+
+
+
+ {#if !mounted}
+
+ {/if}
+
+
+
+
diff --git a/frontend/src/lib/components/raw_apps/readonly_filesystem.ts b/frontend/src/lib/components/raw_apps/readonly_filesystem.ts
new file mode 100644
index 0000000000000..35b157f170a0e
--- /dev/null
+++ b/frontend/src/lib/components/raw_apps/readonly_filesystem.ts
@@ -0,0 +1,191 @@
+import {
+ type IFileSystemProviderWithFileReadWriteCapability,
+ FileType,
+ type IFileChange,
+ type IFileDeleteOptions,
+ type IFileOverwriteOptions,
+ type IFileWriteOptions,
+ type IStat,
+ type IWatchOptions,
+ FileSystemProviderError,
+ FileSystemProviderErrorCode
+} from '@codingame/monaco-vscode-files-service-override'
+
+import { EventEmitter, Uri } from 'vscode'
+import type { Event } from 'vscode/vscode/vs/base/common/event'
+import type { IDisposable } from 'vscode/vscode/vs/base/common/lifecycle'
+import type { URI } from 'vscode/vscode/vs/base/common/uri'
+import type { FileSystemProviderCapabilities } from 'vscode/vscode/vs/platform/files/common/files'
+
+interface FileNode {
+ type: FileType
+ name: string
+ content?: string
+ children?: Map
+}
+
+export class ReadOnlyMemoryFileSystemProvider
+ implements IFileSystemProviderWithFileReadWriteCapability
+{
+ private readonly _onDidChangeFile = new EventEmitter()
+ private readonly _onDidChangeCapabilities = new EventEmitter()
+ private readonly _root: FileNode
+
+ constructor(private fileSystem: Record) {
+ this._root = {
+ type: FileType.Directory,
+ name: '',
+ children: new Map()
+ }
+ this._buildTree()
+ }
+
+ public rebuildTree(fs?: Record): void {
+ this._root.children?.clear()
+ if (fs) {
+ this.fileSystem = fs
+ }
+ this._buildTree()
+ // Notify watchers that everything might have changed
+ this._onDidChangeFile.fire([{ type: 0, resource: Uri.file('/') }])
+ }
+
+ private _buildTree() {
+ const fileSystem = this.fileSystem
+ for (const [path, content] of Object.entries(fileSystem)) {
+ // Normalize path to always start with / and split into segments
+ const normalizedPath = path.startsWith('/') ? path.slice(1) : path
+ const segments = normalizedPath.split('/')
+
+ let currentNode = this._root
+
+ // Create/traverse path segments
+ for (let i = 0; i < segments.length; i++) {
+ const segment = segments[i]
+ const isLast = i === segments.length - 1
+
+ if (!currentNode.children) {
+ currentNode.children = new Map()
+ }
+
+ if (isLast) {
+ // Add file
+ currentNode.children.set(segment, {
+ type: FileType.File,
+ name: segment,
+ content
+ })
+ } else {
+ // Create/traverse directory
+ if (!currentNode.children.has(segment)) {
+ currentNode.children.set(segment, {
+ type: FileType.Directory,
+ name: segment,
+ children: new Map()
+ })
+ }
+ currentNode = currentNode.children.get(segment)!
+ }
+ }
+ }
+ }
+
+ private _findNode(path: string): FileNode | undefined {
+ console.log('FIND NODE', path)
+ if (path === '/' || path === '') {
+ return this._root
+ }
+
+ const segments = path.startsWith('/') ? path.slice(1).split('/') : path.split('/')
+ let currentNode = this._root
+ for (const segment of segments) {
+ if (!currentNode.children?.has(segment)) {
+ return undefined
+ }
+ currentNode = currentNode.children.get(segment)!
+ }
+
+ return currentNode
+ }
+
+ // Required capabilities
+ capabilities: FileSystemProviderCapabilities = 2048 | 1024
+ onDidChangeCapabilities: Event = this._onDidChangeCapabilities.event
+ onDidChangeFile: Event = this._onDidChangeFile.event
+ onDidWatchError?: Event
+
+ async readFile(resource: URI): Promise {
+ const path = this.getPath(resource)
+ console.log('READ FILE', resource, path)
+
+ const node = this._findNode(path)
+ if (!node || node.type !== FileType.File || !node.content) {
+ throw FileSystemProviderError.create(
+ 'File not found',
+ FileSystemProviderErrorCode.FileNotFound
+ )
+ }
+
+ return new TextEncoder().encode(node.content)
+ }
+
+ async writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise {
+ throw new Error('Filesystem is read-only')
+ }
+
+ async stat(resource: URI): Promise {
+ const path = this.getPath(resource)
+ console.log('STAT', resource, path)
+
+ const node = this._findNode(path)
+ if (!node) {
+ throw FileSystemProviderError.create(
+ 'File not found',
+ FileSystemProviderErrorCode.FileNotFound
+ )
+ // throw new Error(`Path not found: ${path}`)
+ }
+
+ return {
+ type: node.type,
+ ctime: Date.now(),
+ mtime: Date.now(),
+ size: node.content ? new TextEncoder().encode(node.content).length : 0
+ }
+ }
+
+ async readdir(resource: URI): Promise<[string, FileType][]> {
+ const path = this.getPath(resource)
+ console.log('READDIR', path)
+
+ const node = this._findNode(path)
+ if (!node || node.type !== FileType.Directory || !node.children) {
+ throw FileSystemProviderError.create(
+ 'Directory not found',
+ FileSystemProviderErrorCode.FileNotFound
+ )
+ }
+
+ return Array.from(node.children.entries()).map(([name, child]) => [name, child.type])
+ }
+
+ watch(resource: URI, opts: IWatchOptions): IDisposable {
+ return { dispose: () => {} }
+ }
+
+ async mkdir(resource: URI): Promise {
+ throw new Error('Filesystem is read-only')
+ }
+
+ async delete(resource: URI, opts: IFileDeleteOptions): Promise {
+ throw new Error('Filesystem is read-only')
+ }
+
+ async rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise {
+ throw new Error('Filesystem is read-only')
+ }
+
+ private getPath(uri: URI): string {
+ return uri.path
+ }
+}
diff --git a/frontend/src/lib/components/raw_apps/vscode.ts b/frontend/src/lib/components/raw_apps/vscode.ts
new file mode 100644
index 0000000000000..05fe92eb34ab2
--- /dev/null
+++ b/frontend/src/lib/components/raw_apps/vscode.ts
@@ -0,0 +1,280 @@
+import * as vscode from 'vscode'
+
+import { getService, IWorkbenchLayoutService, LogLevel } from 'vscode/services'
+import { type RegisterLocalProcessExtensionResult } from 'vscode/extensions'
+import getConfigurationServiceOverride, {
+ type IStoredWorkspace
+} from '@codingame/monaco-vscode-configuration-service-override'
+import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'
+import getLifecycleServiceOverride from '@codingame/monaco-vscode-lifecycle-service-override'
+import getExplorerServiceOverride from '@codingame/monaco-vscode-explorer-service-override'
+import getSearchServiceOverride from '@codingame/monaco-vscode-search-service-override'
+import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'
+
+import {
+ RegisteredFileSystemProvider,
+ registerFileSystemOverlay,
+ RegisteredMemoryFile,
+ type IFileSystemProviderWithFileReadWriteCapability,
+ FileType,
+ type IFileChange,
+ type IFileDeleteOptions,
+ type IFileOverwriteOptions,
+ type IFileWriteOptions,
+ type IStat,
+ type IWatchOptions,
+ FileSystemProviderError,
+ FileSystemProviderErrorCode
+} from '@codingame/monaco-vscode-files-service-override'
+import { attachPart, type Parts } from '@codingame/monaco-vscode-views-service-override'
+import getMarkersServiceOverride from '@codingame/monaco-vscode-markers-service-override'
+import { type WrapperConfig } from 'monaco-editor-wrapper'
+import { sendUserToast } from '$lib/toast'
+import { EventEmitter, Uri } from 'vscode'
+import type { CancellationToken } from 'vscode/vscode/vs/base/common/cancellation'
+import type { Event } from 'vscode/vscode/vs/base/common/event'
+import type { IDisposable } from 'vscode/vscode/vs/base/common/lifecycle'
+import type { ReadableStreamEvents } from 'vscode/vscode/vs/base/common/stream'
+import type { URI } from 'vscode/vscode/vs/base/common/uri'
+import type {
+ IFileReadStreamOptions,
+ IFileOpenOptions,
+ FileSystemProviderCapabilities
+} from 'vscode/vscode/vs/platform/files/common/files'
+import { ReadOnlyMemoryFileSystemProvider } from './readonly_filesystem'
+
+export const configureMonacoWorkers = (logger?: any) => {
+ useWorkerFactory({
+ workerOverrides: {
+ ignoreMapping: true,
+ workerLoaders: {
+ // editorWorkerService: () => {
+ // return new Worker(
+ // new URL('monaco-editor-wrapper/workers/module/editor', import.meta.url),
+ // {
+ // type: 'module'
+ // }
+ // )
+ // },
+
+ TextEditorWorker: () =>
+ new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), {
+ type: 'module'
+ }),
+ css: () => {
+ return new Worker(new URL('monaco-editor-wrapper/workers/module/css', import.meta.url), {
+ type: 'module'
+ })
+ },
+ // typescript: () => {
+ // return new Worker(new URL('monaco-editor-wrapper/workers/module/ts', import.meta.url), {
+ // type: 'module'
+ // })
+ // },
+ TextMateWorker: () =>
+ new Worker(
+ new URL('@codingame/monaco-vscode-textmate-service-override/worker', import.meta.url),
+ { type: 'module' }
+ ),
+ LocalFileSearchWorker: () =>
+ new Worker(
+ new URL('@codingame/monaco-vscode-search-service-override/worker', import.meta.url),
+ { type: 'module' }
+ )
+ }
+ },
+ logger
+ })
+}
+
+export const runApplicationPlayground = async (
+ wrapper,
+ activityBar,
+ sidebar,
+ editors,
+ panel,
+ node_modules
+) => {
+ const workspaceFile = vscode.Uri.file('/.vscode/workspace.code-workspace')
+
+ const defaultViewsInit = () => {
+ for (const config of [
+ {
+ part: 'workbench.parts.activitybar',
+ element: activityBar
+ },
+ {
+ part: 'workbench.parts.sidebar',
+ element: sidebar
+ },
+ // {
+ // part: 'workbench.parts.auxiliarybar',
+ // element: auxiliaryBar
+ // },
+ { part: 'workbench.parts.editor', element: editors },
+ { part: 'workbench.parts.panel', element: panel }
+ ]) {
+ attachPart(config.part as Parts, config.element)
+ }
+ }
+
+ const wrapperConfig: WrapperConfig = {
+ $type: 'extended',
+ id: 'AAP',
+ logLevel: LogLevel.Debug,
+ htmlContainer: document.body,
+ vscodeApiConfig: {
+ serviceOverrides: {
+ ...getConfigurationServiceOverride(),
+ ...getKeybindingsServiceOverride(),
+ ...getLifecycleServiceOverride(),
+ // ...getBannerServiceOverride(),
+ // ...getTitleBarServiceOverride(),
+ // ...getModelServiceOverride(),
+ ...getSearchServiceOverride(),
+ ...getExplorerServiceOverride(),
+ ...getMarkersServiceOverride()
+ // ...getEnvironmentServiceOverride(),
+ },
+ enableExtHostWorker: true,
+ viewsConfig: {
+ viewServiceType: 'ViewsService',
+ viewsInitFunc: defaultViewsInit
+ },
+ workspaceConfig: {
+ enableWorkspaceTrust: true,
+ windowIndicator: {
+ label: 'mlc-app-playground',
+ tooltip: '',
+ command: ''
+ },
+ workspaceProvider: {
+ trusted: true,
+ async open() {
+ window.open(window.location.href)
+ return true
+ },
+ workspace: {
+ workspaceUri: workspaceFile
+ }
+ },
+ configurationDefaults: {
+ 'window.title': 'mlc-app-playground${separator}${dirty}${activeEditorShort}'
+ },
+ productConfiguration: {
+ nameShort: 'mlc-app-playground',
+ nameLong: 'mlc-app-playground'
+ }
+ },
+ userConfiguration: {
+ json: JSON.stringify({
+ 'workbench.colorTheme': 'Default Dark Modern',
+ 'editor.wordBasedSuggestions': 'off',
+ 'typescript.tsserver.web.projectWideIntellisense.enabled': true,
+ 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false,
+ 'editor.guides.bracketPairsHorizontal': true,
+ 'editor.experimental.asyncTokenization': false
+ })
+ }
+ },
+ extensions: [
+ {
+ config: {
+ name: 'mlc-app-playground',
+ publisher: 'TypeFox',
+ version: '1.0.0',
+ engines: {
+ vscode: '*'
+ }
+ }
+ }
+ ],
+ editorAppConfig: {
+ monacoWorkerFactory: configureMonacoWorkers
+ }
+ }
+
+ // const fileSystemProvider = new RegisteredFileSystemProvider(true)
+ // fileSystemProvider.registerFile(
+ // new RegisteredMemoryFile(Uri.file('/foo'), `async function foo() {}`)
+ // )
+ // // fileSystemProvider.registerFile(new RegisteredMemoryFile(testerTsUri, `async function foo() {}`))
+ // fileSystemProvider.registerFile(createDefaultWorkspaceFile(workspaceFile, '/'))
+ // registerFileSystemOverlay(1, fileSystemProvider)
+ let staticFileSystemProvider = new ReadOnlyMemoryFileSystemProvider({
+ '/.vscode/settings.json': JSON.stringify(
+ {
+ 'files.exclude': {
+ '.vscode/': true,
+ node_modules: false
+ }
+ },
+ null,
+ 2
+ ),
+ '/tsconfig.json': JSON.stringify(
+ {
+ compilerOptions: {
+ target: 'ES2020',
+ lib: ['ES2020', 'DOM', 'DOM.Iterable'],
+ module: 'NodeNext',
+ moduleResolution: 'NodeNext',
+ strict: true,
+ esModuleInterop: true,
+ skipLibCheck: true,
+ forceConsistentCasingInFileNames: true,
+ resolveJsonModule: true,
+ isolatedModules: true,
+ noUnusedLocals: true,
+ noUnusedParameters: true,
+ noImplicitReturns: true,
+ noFallthroughCasesInSwitch: true,
+ declaration: true,
+ sourceMap: true,
+ allowJs: true,
+ checkJs: true
+ },
+ include: ['./**/*.ts', './**/*.tsx', './**/*.js', './**/*.jsx'],
+ exclude: ['node_modules']
+ },
+ null,
+ 2
+ ),
+ [workspaceFile.path]: JSON.stringify(
+ {
+ folders: [
+ {
+ path: '/'
+ }
+ ]
+ },
+ null,
+ 2
+ )
+ })
+ let nodeModulesfileSystemProvider = new ReadOnlyMemoryFileSystemProvider(node_modules)
+ registerFileSystemOverlay(2, staticFileSystemProvider)
+ registerFileSystemOverlay(1, nodeModulesfileSystemProvider)
+
+ await wrapper.init(wrapperConfig)
+ const result = wrapper.getExtensionRegisterResult(
+ 'mlc-app-playground'
+ ) as RegisterLocalProcessExtensionResult
+ result.setAsDefaultApi()
+
+ await getService(IWorkbenchLayoutService)
+
+ // show explorer and not search
+ await vscode.commands.executeCommand('workbench.view.explorer')
+ sendUserToast('Welcome to the Monaco Language Client playground!')
+
+ //necessary for hmr to work
+ try {
+ defaultViewsInit()
+ } catch (e) {
+ console.log(e)
+ }
+
+ return nodeModulesfileSystemProvider
+ // await Promise.all([await vscode.window.showTextDocument(helloTsUri)])
+}