Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "third-party/nodepod"]
path = third-party/nodepod
url = https://github.com/livesession/Nodepod
13 changes: 13 additions & 0 deletions apps/studio/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xyd studio</title>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
79 changes: 79 additions & 0 deletions apps/studio/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"name": "@xyd-js/studio",
"version": "0.0.0-prealpha.1",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@codingame/monaco-vscode-ai-service-override": "~30.0.1",
"@codingame/monaco-vscode-api": "~30.0.1",
"@codingame/monaco-vscode-chat-service-override": "~30.0.1",
"@codingame/monaco-vscode-configuration-service-override": "~30.0.1",
"@codingame/monaco-vscode-editor-service-override": "~30.0.1",
"@codingame/monaco-vscode-extensions-service-override": "~30.0.1",
"@codingame/monaco-vscode-extension-gallery-service-override": "~30.0.1",
"@codingame/monaco-vscode-files-service-override": "~30.0.1",
"@codingame/monaco-vscode-keybindings-service-override": "~30.0.1",
"@codingame/monaco-vscode-language-detection-worker-service-override": "~30.0.1",
"@codingame/monaco-vscode-languages-service-override": "~30.0.1",
"@codingame/monaco-vscode-lifecycle-service-override": "~30.0.1",
"@codingame/monaco-vscode-localization-service-override": "~30.0.1",
"@codingame/monaco-vscode-model-service-override": "~30.0.1",
"@codingame/monaco-vscode-notifications-service-override": "~30.0.1",
"@codingame/monaco-vscode-quickaccess-service-override": "~30.0.1",
"@codingame/monaco-vscode-search-service-override": "~30.0.1",
"@codingame/monaco-vscode-snippets-service-override": "~30.0.1",
"@codingame/monaco-vscode-storage-service-override": "~30.0.1",
"@codingame/monaco-vscode-textmate-service-override": "~30.0.1",
"@codingame/monaco-vscode-theme-defaults-default-extension": "~30.0.1",
"@codingame/monaco-vscode-theme-seti-default-extension": "~30.0.1",
"@codingame/monaco-vscode-theme-service-override": "~30.0.1",
"@codingame/monaco-vscode-views-service-override": "~30.0.1",
"@codingame/monaco-vscode-workbench-service-override": "~30.0.1",
"@codingame/monaco-vscode-explorer-service-override": "~30.0.1",
"@codingame/monaco-vscode-terminal-service-override": "~30.0.1",
"@codingame/monaco-vscode-view-status-bar-service-override": "~30.0.1",
"@codingame/monaco-vscode-view-title-bar-service-override": "~30.0.1",
"@codingame/monaco-vscode-view-banner-service-override": "~30.0.1",
"@codingame/monaco-vscode-output-service-override": "~30.0.1",
"@codingame/monaco-vscode-preferences-service-override": "~30.0.1",
"@codingame/monaco-vscode-scm-service-override": "~30.0.1",
"@codingame/monaco-vscode-git-base-default-extension": "~30.0.1",
"@codingame/monaco-vscode-markers-service-override": "~30.0.1",
"@codingame/monaco-vscode-log-service-override": "~30.0.1",
"@codingame/monaco-vscode-dialogs-service-override": "~30.0.1",
"@codingame/monaco-vscode-environment-service-override": "~30.0.1",
"@codingame/monaco-vscode-javascript-default-extension": "~30.0.1",
"@codingame/monaco-vscode-typescript-basics-default-extension": "~30.0.1",
"@codingame/monaco-vscode-json-default-extension": "~30.0.1",
"@codingame/monaco-vscode-css-default-extension": "~30.0.1",
"@codingame/monaco-vscode-html-default-extension": "~30.0.1",
"@codingame/monaco-vscode-markdown-basics-default-extension": "~30.0.1",
"@codingame/monaco-vscode-yaml-default-extension": "~30.0.1",
"@codingame/monaco-vscode-standalone-languages": "~30.0.1",
"@codingame/monaco-vscode-standalone-typescript-language-features": "~30.0.1",
"@codingame/monaco-vscode-standalone-json-language-features": "~30.0.1",
"@codingame/monaco-vscode-standalone-css-language-features": "~30.0.1",
"@codingame/monaco-vscode-standalone-html-language-features": "~30.0.1",
"monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~30.0.1",
"@scelar/nodepod": "workspace:*",
"@xterm/xterm": "^6.0.0",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-webgl": "^0.19.0",
"vscode": "npm:@codingame/monaco-vscode-extension-api@~30.0.1",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@codingame/monaco-vscode-rollup-vsix-plugin": "~30.0.1",
"@vitejs/plugin-react": "^6.0.1",
"typescript": "^5.6.2",
"vite": "^8.0.9"
}
}
57 changes: 57 additions & 0 deletions apps/studio/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useEffect, useRef, useState } from 'react'
import { ensureServicesInitialized } from './setup'
import { registerAiChat } from './features/ai'
import { registerPreview } from './features/preview'
import { registerGitCommands } from './features/git'

// Bundled + VSIX extensions (static imports)
import './extensions'

import {
waitForVsixExtensions,
installMarketplaceExtensions,
applyDefaultExtensionSettings,
} from './extensions'

export function App() {
const [error, setError] = useState<string | null>(null)
const containerRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const container = containerRef.current
if (!container) return
let disposed = false

;(async () => {
try {
await ensureServicesInitialized(container)
if (disposed) return

// Wait for VSIX extensions (Symbols icons)
await waitForVsixExtensions()

await registerAiChat()
await registerPreview()
await registerGitCommands()

// Install marketplace extensions (GitHub Theme) + apply settings
const vscodeApi = await import('vscode')
await installMarketplaceExtensions(vscodeApi)
await applyDefaultExtensionSettings(vscodeApi)

console.log('[xyd studio] initialized')
} catch (e: any) {
console.error('[xyd studio] init failed:', e)
if (!disposed) setError(e.message || String(e))
}
})()

return () => { disposed = true }
}, [])

if (error) {
return <pre style={{ color: 'red', padding: 20 }}>{error}</pre>
}

return <div id="workbench" ref={containerRef} />
}
92 changes: 92 additions & 0 deletions apps/studio/src/extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Default extensions for xyd studio.
*
* 1. Bundled extensions (npm @codingame packages) — static imports
* 2. VSIX extensions — loaded via rollup-vsix-plugin at build time
* 3. Marketplace extensions — installed from OpenVSX at runtime
*/

// --- Bundled extensions (static imports) ---

// Theme defaults (Dark Modern, Light Modern, Dark+, Light+, etc.)
import '@codingame/monaco-vscode-theme-defaults-default-extension'

// Seti file icons (fallback)
import '@codingame/monaco-vscode-theme-seti-default-extension'

// Language grammars
import '@codingame/monaco-vscode-javascript-default-extension'
import '@codingame/monaco-vscode-typescript-basics-default-extension'
import '@codingame/monaco-vscode-json-default-extension'
import '@codingame/monaco-vscode-css-default-extension'
import '@codingame/monaco-vscode-html-default-extension'
import '@codingame/monaco-vscode-markdown-basics-default-extension'
import '@codingame/monaco-vscode-yaml-default-extension'

// Language features (intellisense)
import '@codingame/monaco-vscode-standalone-typescript-language-features'
import '@codingame/monaco-vscode-standalone-json-language-features'
import '@codingame/monaco-vscode-standalone-css-language-features'
import '@codingame/monaco-vscode-standalone-html-language-features'

// Git support (provides Git: Clone, Git: Init, etc. commands)
import '@codingame/monaco-vscode-git-base-default-extension'

// --- VSIX extensions (loaded at build time via rollup-vsix-plugin) ---

import { whenReady as symbolsReady } from '../symbols-web-0.0.25.vsix'

export async function waitForVsixExtensions() {
await symbolsReady
console.log('[xyd studio] VSIX extension loaded: Symbols icon theme')
}

// --- Marketplace extensions ---

interface MarketplaceExtension {
id: string
displayName: string
}

const marketplaceExtensions: MarketplaceExtension[] = [
{ id: 'GitHub.github-vscode-theme', displayName: 'GitHub Theme' },
]

export async function installMarketplaceExtensions(
vscodeApi: typeof import('vscode')
) {
for (const ext of marketplaceExtensions) {
try {
await vscodeApi.commands.executeCommand(
'workbench.extensions.installExtension',
ext.id
)
console.log(`[xyd studio] Installed extension: ${ext.displayName}`)
} catch (e) {
console.warn(`[xyd studio] Failed to install ${ext.displayName}:`, e)
}
}
}

// --- Apply defaults ---

export async function applyDefaultExtensionSettings(
vscodeApi: typeof import('vscode')
) {
try {
const config = vscodeApi.workspace.getConfiguration()
await config.update(
'workbench.colorTheme',
'GitHub Light Default',
vscodeApi.ConfigurationTarget.Global
)
await config.update(
'workbench.iconTheme',
'symbols',
vscodeApi.ConfigurationTarget.Global
)
console.log('[xyd studio] Applied: GitHub Light Default + Symbols icons')
} catch (e) {
console.warn('[xyd studio] Failed to apply default settings:', e)
}
}
115 changes: 115 additions & 0 deletions apps/studio/src/features/ai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { registerExtension } from '@codingame/monaco-vscode-api/extensions'
import { ExtensionHostKind } from '@codingame/monaco-vscode-extensions-service-override'
import * as vscode from 'vscode'

export async function registerAiChat() {
const { getApi } = registerExtension(
{
name: 'xydStudioAi',
publisher: 'xyd',
version: '1.0.0',
engines: { vscode: '*' },
contributes: {
chatParticipants: [
{
id: 'xyd.studio.participant',
fullName: 'xyd AI',
name: 'xyd',
isDefault: true,
modes: ['agent'],
locations: ['panel', 'terminal', 'editor'],
},
],
languageModelChatProviders: [
{
vendor: 'copilot',
displayName: 'xyd AI provider',
},
],
},
enabledApiProposals: [
'defaultChatParticipant',
'chatParticipantAdditions',
'chatParticipantPrivate',
'languageModelThinkingPart',
'chatProvider',
],
},
ExtensionHostKind.LocalProcess,
{ system: true }
)

const vscodeApi = await getApi()

// Register language model provider (mock - streams a demo response)
const eventEmitter = new vscodeApi.EventEmitter<void>()

vscodeApi.lm.registerLanguageModelChatProvider('copilot', {
provideLanguageModelChatInformation() {
return [
{
id: 'auto',
capabilities: { toolCalling: false },
family: 'xyd',
maxInputTokens: 100000,
maxOutputTokens: 100000,
name: 'xyd AI',
version: '1.0.0',
isDefault: true,
isUserSelectable: true,
},
]
},
async provideTokenCount() {
return 0
},
async provideLanguageModelChatResponse(
_model: any,
_messages: any,
_options: any,
progress: any
) {
// Demo: stream a response about xyd
const parts = [
"I'm **xyd AI** — ",
'your documentation assistant. ',
'I can help you with:\n\n',
'- Configuring `docs.json`\n',
'- Writing Markdown/MDX content\n',
'- Setting up OpenAPI documentation\n',
'- Choosing and customizing themes\n',
'- Installing and configuring plugins\n\n',
'_This is a demo response. ',
'Connect a real LLM backend to get actual AI assistance._',
]

for (const part of parts) {
progress.report(new vscodeApi.LanguageModelTextPart(part))
await new Promise((r) => setTimeout(r, 100))
}
},
onDidChangeLanguageModelChatInformation: eventEmitter.event,
})

// Register chat participant
vscodeApi.chat.createChatParticipant(
'xyd.studio.participant',
async (
request: any,
_context: any,
response: any
) => {
const modelResponse = await request.model.sendRequest([
vscodeApi.LanguageModelChatMessage.User(request.prompt),
])

for await (const part of modelResponse.stream) {
if (part instanceof vscode.LanguageModelTextPart) {
response.markdown(part.value)
}
}
}
)

console.log('[xyd studio] AI chat registered')
}
Loading
Loading