Skip to content

Commit d439ff7

Browse files
committed
feat(gpt-runner-vscode): vscode is success load gpt-runner
1 parent b14f853 commit d439ff7

File tree

19 files changed

+294
-29
lines changed

19 files changed

+294
-29
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"typescript.inlayHints.parameterTypes.enabled": true,
1212
// "typescript.inlayHints.functionLikeReturnTypes.enabled": true,
1313
"cSpell.words": [
14+
"cachedir",
1415
"Chatgpt",
1516
"clsx",
1617
"codicon",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"workbench.colorCustomizations": {
3+
"activityBar.background": "#312F04",
4+
"titleBar.activeBackground": "#454106",
5+
"titleBar.activeForeground": "#FDFBE1"
6+
},
7+
"cSpell.words": [
8+
"nicepkg"
9+
]
10+
}

packages/gpt-runner-vscode/package.json

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,39 @@
2424
"onStartupFinished"
2525
],
2626
"contributes": {
27+
"viewsContainers": {
28+
"activitybar": [
29+
{
30+
"id": "gpt-runner",
31+
"title": "GPT Runner",
32+
"icon": "res/sidebar-icon.png"
33+
}
34+
]
35+
},
36+
"views": {
37+
"gpt-runner": [
38+
{
39+
"type": "webview",
40+
"id": "gpt-runner.chatView",
41+
"name": "GPT Runner Chat"
42+
}
43+
]
44+
},
2745
"commands": [
2846
{
2947
"command": "gpt-runner.reload",
3048
"title": "Reload GPT Runner",
3149
"category": "GPT Runner"
50+
},
51+
{
52+
"command": "gpt-runner.restartServer",
53+
"title": "GPT Runner Restart Server",
54+
"category": "GPT Runner"
55+
},
56+
{
57+
"command": "gpt-runner.openChat",
58+
"title": "GPT Runner Open Chat",
59+
"category": "GPT Runner"
3260
}
3361
],
3462
"configuration": {
@@ -50,10 +78,10 @@
5078
},
5179
"devDependencies": {
5280
"@types/vscode": "^1.71.0",
53-
"@nicepkg/gpt-runner": "workspace:*",
81+
"@nicepkg/gpt-runner-web": "workspace:*",
5482
"@nicepkg/gpt-runner-shared": "workspace:*",
5583
"esno": "^0.16.3",
5684
"eventemitter3": "^5.0.1",
57-
"unconfig": "^0.3.7"
85+
"unconfig": "^0.3.9"
5886
}
5987
}
16 KB
Loading

packages/gpt-runner-vscode/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { log } from './log'
55
import { ContextLoader } from './contextLoader'
66
import { getExtConfiguration } from './utils'
77
import { EXT_DISPLAY_NAME, EXT_NAME } from './constant'
8+
import { registerWebview } from './register/webview'
9+
import { registerServer } from './register/server'
810

911
async function registerRoot(ext: ExtensionContext, status: StatusBarItem, cwd: string) {
1012
const contextLoader = new ContextLoader(cwd)
@@ -13,7 +15,8 @@ async function registerRoot(ext: ExtensionContext, status: StatusBarItem, cwd: s
1315

1416
log.appendLine(`📁 Root context loaded: ${cwd}`)
1517

16-
// registerAnnotations(cwd, contextLoader, status, ext)
18+
registerServer(cwd, contextLoader, ext)
19+
registerWebview(cwd, contextLoader, ext)
1720

1821
return contextLoader
1922
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import child_process from 'child_process'
2+
import type { Disposable, ExtensionContext } from 'vscode'
3+
import * as vscode from 'vscode'
4+
import type { ContextLoader } from '../contextLoader'
5+
import { EXT_NAME } from '../constant'
6+
7+
export async function registerServer(
8+
cwd: string,
9+
contextLoader: ContextLoader,
10+
ext: ExtensionContext,
11+
) {
12+
let serverDisposable: Disposable
13+
let serverProcess: child_process.ChildProcessWithoutNullStreams
14+
15+
const dispose = () => {
16+
serverProcess?.kill?.()
17+
serverDisposable?.dispose?.()
18+
}
19+
20+
const registerProvider = () => {
21+
dispose()
22+
23+
serverDisposable = vscode.commands.registerCommand(`${EXT_NAME}.restartServer`, () => {
24+
serverProcess?.kill?.()
25+
26+
const { extensionUri } = ext
27+
const serverUri = vscode.Uri.joinPath(extensionUri, './node_modules/@nicepkg/gpt-runner-web/dist/server.cjs')
28+
29+
serverProcess = child_process.spawn('node', [serverUri.fsPath], {
30+
env: {
31+
...process.env,
32+
NODE_OPTIONS: '--experimental-fetch',
33+
NODE_NO_WARNINGS: '1',
34+
},
35+
})
36+
37+
serverProcess.stdout.on('data', (data: string) => {
38+
console.log(`stdout: ${data}`)
39+
vscode.window.showInformationMessage(`Server running: ${data}`)
40+
})
41+
42+
serverProcess.stderr.on('data', (data: string) => {
43+
console.error(`stderr: ${data}`)
44+
vscode.window.showErrorMessage(`Server error: ${data}`)
45+
})
46+
47+
serverProcess.on('close', (code: string) => {
48+
console.log(`child process exited with code ${code}`)
49+
vscode.window.showWarningMessage(`Server stopped with code: ${code}`)
50+
})
51+
})
52+
53+
return serverDisposable
54+
}
55+
56+
ext.subscriptions.push(
57+
registerProvider(),
58+
)
59+
60+
contextLoader.emitter.on('contextReload', () => {
61+
registerProvider()
62+
})
63+
contextLoader.emitter.on('contextUnload', () => {
64+
dispose()
65+
})
66+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import type { ExtensionContext } from 'vscode'
4+
import * as vscode from 'vscode'
5+
import type { ContextLoader } from '../contextLoader'
6+
import { EXT_NAME } from '../constant'
7+
import { createHash } from '../utils'
8+
9+
class ChatViewProvider implements vscode.WebviewViewProvider {
10+
static readonly viewType = `${EXT_NAME}.chatView`
11+
12+
#view?: vscode.WebviewView
13+
#extContext: ExtensionContext
14+
15+
constructor(
16+
extContext: ExtensionContext,
17+
) {
18+
this.#extContext = extContext
19+
}
20+
21+
resolveWebviewView(
22+
webviewView: vscode.WebviewView,
23+
_context: vscode.WebviewViewResolveContext,
24+
_token: vscode.CancellationToken,
25+
) {
26+
const { extensionUri } = this.#extContext
27+
this.#view = webviewView
28+
29+
const baseUri = vscode.Uri.joinPath(extensionUri, './node_modules/@nicepkg/gpt-runner-web/dist/browser')
30+
31+
webviewView.webview.options = {
32+
// Allow scripts in the webview
33+
enableScripts: true,
34+
35+
localResourceRoots: [baseUri],
36+
}
37+
38+
webviewView.webview.html = this.#getHtmlForWebview(webviewView.webview)
39+
}
40+
41+
#getHtmlForWebview(webview: vscode.Webview) {
42+
const { extensionUri } = this.#extContext
43+
44+
const baseUri = vscode.Uri.joinPath(extensionUri, './node_modules/@nicepkg/gpt-runner-web/dist/browser')
45+
46+
webview.options = {
47+
enableScripts: true,
48+
localResourceRoots: [baseUri],
49+
}
50+
51+
const indexHtml = fs.readFileSync(path.join(baseUri.fsPath, 'index.html'), 'utf8')
52+
const nonce = createHash()
53+
54+
const indexHtmlWithBaseUri = indexHtml.replace(
55+
/\s+(href|src)="(.+?)"/g,
56+
(_, attr, url) => ` ${attr}="${webview.asWebviewUri(vscode.Uri.joinPath(baseUri, url))}"`,
57+
).replace(/\/\/\s*before-script/g, `
58+
window.globalConfig = {
59+
serverBaseUrl: 'http://localhost:3003',
60+
initialRoutePath: '/chat'
61+
}
62+
`).replace(/<script\s*([\w\W]+)?>/g,
63+
(_, attr) => `<script ${attr} nonce="${nonce}">`,
64+
)
65+
66+
console.log('indexHtmlWithBaseUri', indexHtmlWithBaseUri)
67+
68+
return indexHtmlWithBaseUri
69+
}
70+
}
71+
72+
export async function registerWebview(
73+
cwd: string,
74+
contextLoader: ContextLoader,
75+
ext: ExtensionContext,
76+
) {
77+
const provider = new ChatViewProvider(ext)
78+
let webviewDisposer: vscode.Disposable | undefined
79+
80+
const registerProvider = () => {
81+
webviewDisposer = vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, provider)
82+
return webviewDisposer
83+
}
84+
85+
ext.subscriptions.push(registerProvider())
86+
87+
contextLoader.emitter.on('contextReload', () => {
88+
registerProvider()
89+
})
90+
contextLoader.emitter.on('contextUnload', () => {
91+
webviewDisposer?.dispose?.()
92+
})
93+
}

packages/gpt-runner-vscode/src/utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,12 @@ export function getExtConfiguration(): ExtensionConfiguration {
3030
disabled,
3131
}
3232
}
33+
34+
export function createHash() {
35+
let text = ''
36+
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
37+
for (let i = 0; i < 32; i++)
38+
text += possible.charAt(Math.floor(Math.random() * possible.length))
39+
40+
return text
41+
}

packages/gpt-runner-web/client/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@
55
<meta charset="utf-8">
66
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
77
<title>GPT Runner</title>
8+
<script>
9+
// before-script
10+
</script>
11+
<base href="/">
812
<link href="/codicon/codicon.css" rel="stylesheet" />
913
</head>
1014

1115
<body>
1216
<div id="root"></div>
1317
<script type="module" src="/src/main.tsx"></script>
18+
<script>
19+
// after-script
20+
</script>
1421
</body>
1522

1623
</html>
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
import { getSearchParams } from '@nicepkg/gpt-runner-shared/browser'
22

3+
declare global {
4+
interface Window {
5+
globalConfig?: {
6+
rootPath?: string
7+
serverBaseUrl?: string
8+
initialRoutePath?: string
9+
}
10+
}
11+
}
12+
313
export const globalConfig = {
4-
rootPath: '/Users/yangxiaoming/Documents/codes/gpt-runner' || getSearchParams('rootPath'),
14+
rootPath: window?.globalConfig?.rootPath || '/Users/yangxiaoming/Documents/codes/gpt-runner' || getSearchParams('rootPath'),
15+
initialRoutePath: window?.globalConfig?.initialRoutePath || '/',
16+
serverBaseUrl: window?.globalConfig?.serverBaseUrl || 'http://localhost:3003',
517
}

0 commit comments

Comments
 (0)