feat(gpt-runner-web): add init gpt file suppport when root path not have gpt files
This commit is contained in:
@@ -180,5 +180,12 @@ ${content}
|
||||
tips += fileTips
|
||||
}
|
||||
|
||||
tips += `When you want to create/modify/delete a file or talk about a file, you should always return the full path of the file.
|
||||
|
||||
For example, if I provide you with a file path \`src/component/button.ts\`, you should return \`src/component/button.ts\` instead of \`button.ts\ when you talk about it.
|
||||
|
||||
Return full path is very important !!!
|
||||
`
|
||||
|
||||
return tips
|
||||
}
|
||||
|
||||
@@ -31,6 +31,13 @@ export interface GetGptFilesTreeResData {
|
||||
filesInfoTree: GptFileInfoTree
|
||||
}
|
||||
|
||||
export interface InitGptFilesReqParams {
|
||||
rootPath: string
|
||||
gptFilesNames: string[]
|
||||
}
|
||||
|
||||
export type InitGptFilesResData = null
|
||||
|
||||
export type GetProjectConfigReqParams = null
|
||||
export interface GetProjectConfigResData {
|
||||
gptRunnerVersion: string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { z } from 'zod'
|
||||
import type { ChatStreamReqParams, GetCommonFilesReqParams, GetGptFilesReqParams, GetUserConfigReqParams, OpenEditorReqParams, StorageClearReqParams, StorageGetItemReqParams, StorageRemoveItemReqParams, StorageSetItemReqParams } from '../types'
|
||||
import type { ChatStreamReqParams, GetCommonFilesReqParams, GetGptFilesReqParams, GetUserConfigReqParams, InitGptFilesReqParams, OpenEditorReqParams, StorageClearReqParams, StorageGetItemReqParams, StorageRemoveItemReqParams, StorageSetItemReqParams } from '../types'
|
||||
import { SingleChatMessageSchema, SingleFileConfigSchema } from './config.zod'
|
||||
import { ServerStorageNameSchema } from './enum.zod'
|
||||
|
||||
@@ -16,6 +16,11 @@ export const GetGptFilesReqParamsSchema = z.object({
|
||||
rootPath: z.string(),
|
||||
}) satisfies z.ZodType<GetGptFilesReqParams>
|
||||
|
||||
export const InitGptFilesReqParamsSchema = z.object({
|
||||
rootPath: z.string(),
|
||||
gptFilesNames: z.array(z.string()),
|
||||
}) satisfies z.ZodType<InitGptFilesReqParams>
|
||||
|
||||
export const GetUserConfigReqParamsSchema = z.object({
|
||||
rootPath: z.string(),
|
||||
}) satisfies z.ZodType<GetUserConfigReqParams>
|
||||
|
||||
@@ -17,22 +17,27 @@ export function openInBrowser(props: OpenInBrowserProps) {
|
||||
}
|
||||
|
||||
export interface GetPortProps {
|
||||
defaultPort: number
|
||||
defaultPort?: number
|
||||
autoFreePort?: boolean
|
||||
}
|
||||
|
||||
export async function getPort(props: GetPortProps): Promise<number> {
|
||||
const { defaultPort, autoFreePort } = props
|
||||
|
||||
if (!autoFreePort)
|
||||
return defaultPort
|
||||
if (defaultPort) {
|
||||
if (!autoFreePort)
|
||||
return defaultPort
|
||||
|
||||
const canUseDefaultPort = await fp.isFreePort(defaultPort)
|
||||
const canUseDefaultPort = await fp.isFreePort(defaultPort)
|
||||
|
||||
if (canUseDefaultPort)
|
||||
return defaultPort
|
||||
if (canUseDefaultPort)
|
||||
return defaultPort
|
||||
}
|
||||
|
||||
const [freePort] = await fp.findFreePorts(1)
|
||||
const [freePort] = await fp.findFreePorts(1, {
|
||||
startPort: 3001,
|
||||
endPort: 9999,
|
||||
})
|
||||
|
||||
return freePort
|
||||
}
|
||||
|
||||
@@ -29,14 +29,20 @@ export async function registerServer(
|
||||
const { extensionUri } = ext
|
||||
const serverUri = vscode.Uri.joinPath(extensionUri, './dist/web/start-server.cjs')
|
||||
|
||||
// always get a random free port
|
||||
const finalPort = await getPort({
|
||||
defaultPort: 3003,
|
||||
autoFreePort: true,
|
||||
})
|
||||
|
||||
state.serverPort = finalPort
|
||||
|
||||
serverProcess = child_process.spawn('node', [serverUri.fsPath, '--port', String(finalPort)], {
|
||||
serverProcess = child_process.spawn('node', [
|
||||
serverUri.fsPath,
|
||||
'--port',
|
||||
String(finalPort),
|
||||
'--client-dist-path',
|
||||
vscode.Uri.joinPath(extensionUri, './dist/web/browser').fsPath,
|
||||
], {
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_OPTIONS: '--experimental-fetch',
|
||||
|
||||
BIN
packages/gpt-runner-web/client/public/favicon.ico
Normal file
BIN
packages/gpt-runner-web/client/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
@@ -1,18 +1,25 @@
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
// actual line weight is 8px, because we need to make it bigger to make it easier to grab
|
||||
const lineWeight = '8px'
|
||||
|
||||
export const DragLine = styled.div<{ $dragLineColor: string; $dragLineActiveColor: string; $dragLineWidth: string }>`
|
||||
position: absolute;
|
||||
background: ${({ $dragLineColor }) => $dragLineColor};
|
||||
/* z-index: 2; */
|
||||
/* background: ${({ $dragLineColor }) => $dragLineColor}; */
|
||||
border-color: ${({ $dragLineColor }) => $dragLineColor};
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
touch-action: none;
|
||||
|
||||
&:active {
|
||||
background: ${({ $dragLineActiveColor }) => $dragLineActiveColor};
|
||||
/* background: ${({ $dragLineActiveColor }) => $dragLineActiveColor}; */
|
||||
border-color: ${({ $dragLineActiveColor }) => $dragLineActiveColor};
|
||||
}
|
||||
|
||||
&[data-direction='left'] {
|
||||
cursor: col-resize;
|
||||
width: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
width: ${lineWeight};
|
||||
border-left-width: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@@ -20,7 +27,8 @@ export const DragLine = styled.div<{ $dragLineColor: string; $dragLineActiveColo
|
||||
|
||||
&[data-direction='right'] {
|
||||
cursor: col-resize;
|
||||
width: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
width: ${lineWeight};
|
||||
border-right-width: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@@ -28,7 +36,8 @@ export const DragLine = styled.div<{ $dragLineColor: string; $dragLineActiveColo
|
||||
|
||||
&[data-direction='top'] {
|
||||
cursor: row-resize;
|
||||
height: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
height: ${lineWeight};
|
||||
border-top-width: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@@ -36,7 +45,8 @@ export const DragLine = styled.div<{ $dragLineColor: string; $dragLineActiveColo
|
||||
|
||||
&[data-direction='bottom'] {
|
||||
cursor: row-resize;
|
||||
height: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
height: ${lineWeight};
|
||||
border-bottom-width: ${({ $dragLineWidth }) => $dragLineWidth};
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
@@ -42,6 +42,7 @@ export async function fetchChatgptStream(
|
||||
contextFilePaths,
|
||||
rootPath,
|
||||
} satisfies ChatStreamReqParams),
|
||||
openWhenHidden: true,
|
||||
onmessage: onMessage,
|
||||
onerror: onError,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type BaseResponse, type GetGptFilesReqParams, type GetGptFilesTreeResData, objectToQueryString } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { objectToQueryString } from '@nicepkg/gpt-runner-shared/common'
|
||||
import type { BaseResponse, GetGptFilesReqParams, GetGptFilesTreeResData, InitGptFilesReqParams, InitGptFilesResData } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { getGlobalConfig } from '../helpers/global-config'
|
||||
|
||||
export async function fetchGptFilesTree(params: GetGptFilesReqParams): Promise<BaseResponse<GetGptFilesTreeResData>> {
|
||||
@@ -13,3 +14,17 @@ export async function fetchGptFilesTree(params: GetGptFilesReqParams): Promise<B
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
export async function initGptFiles(params: InitGptFilesReqParams): Promise<BaseResponse<InitGptFilesResData>> {
|
||||
const res = await fetch(`${getGlobalConfig().serverBaseUrl}/api/gpt-files/init-gpt-files?${objectToQueryString({
|
||||
...params,
|
||||
})}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
})
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -31,9 +31,28 @@ export interface ChatPanelProps {
|
||||
}
|
||||
|
||||
export const ChatPanel: FC<ChatPanelProps> = (props) => {
|
||||
const { scrollDownRef, chatTreeView, fileTreeView, settingsView, chatId, onChatIdChange } = props
|
||||
const { createChatAndActive, getGptFileTreeItemFromChatId } = useGlobalStore()
|
||||
const { chatInstance, updateCurrentChatInstance, generateCurrentChatAnswer, regenerateCurrentLastChatAnswer, stopCurrentGeneratingChatAnswer } = useChatInstance({ chatId })
|
||||
const {
|
||||
scrollDownRef,
|
||||
chatTreeView,
|
||||
fileTreeView,
|
||||
settingsView,
|
||||
chatId,
|
||||
onChatIdChange,
|
||||
} = props
|
||||
|
||||
const {
|
||||
createChatAndActive,
|
||||
getGptFileTreeItemFromChatId,
|
||||
} = useGlobalStore()
|
||||
|
||||
const {
|
||||
chatInstance,
|
||||
updateCurrentChatInstance,
|
||||
generateCurrentChatAnswer,
|
||||
regenerateCurrentLastChatAnswer,
|
||||
stopCurrentGeneratingChatAnswer,
|
||||
} = useChatInstance({ chatId })
|
||||
|
||||
const status = chatInstance?.status ?? ChatMessageStatus.Success
|
||||
const [gptFileTreeItem, setGptFileTreeItem] = useState<GptFileTreeItem>()
|
||||
const [chatPanelRef, { width: chatPanelWidth }] = useElementSizeRealTime<HTMLDivElement>()
|
||||
@@ -334,8 +353,8 @@ export const ChatPanel: FC<ChatPanelProps> = (props) => {
|
||||
|
||||
{/* file tree */}
|
||||
{fileTreeView && <PopoverMenu
|
||||
isPopoverOpen={true}
|
||||
onPopoverDisplayChange={() => { }}
|
||||
// isPopoverOpen={true}
|
||||
// onPopoverDisplayChange={() => { }}
|
||||
childrenInMenuWhenOpen={false}
|
||||
clickOutSideToClose={false}
|
||||
menuStyle={{
|
||||
|
||||
@@ -21,7 +21,17 @@ export type GptTreeItemOtherInfo = GptFileInfoTreeItem
|
||||
|
||||
export const ChatSidebar: FC<ChatSidebarProps> = (props) => {
|
||||
const { rootPath } = props
|
||||
const { activeChatId, sidebarTree, expandChatTreeItem, createChatAndActive, updateSidebarTreeItem, updateActiveChatId, updateUserConfigFromRemote, updateSidebarTreeFromRemote } = useGlobalStore()
|
||||
const {
|
||||
activeChatId,
|
||||
sidebarTree,
|
||||
expandChatTreeItem,
|
||||
createChatAndActive,
|
||||
updateSidebarTreeItem,
|
||||
updateActiveChatId,
|
||||
updateUserConfigFromRemote,
|
||||
updateSidebarTreeFromRemote,
|
||||
} = useGlobalStore()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const { removeChatInstance } = useChatInstance({
|
||||
|
||||
@@ -10,9 +10,12 @@ export const FileTreeItemRightWrapper = styled.div`
|
||||
|
||||
export const FileTreeSidebarUnderSearchWrapper = styled.div`
|
||||
font-size: var(--type-ramp-base-font-size);
|
||||
margin-top: 0.25rem;
|
||||
color: var(--input-foreground);
|
||||
padding: 0.5rem 0;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
& ::part(control) {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`
|
||||
|
||||
export const FileTreeSidebarHighlight = styled(VSCodeBadge)`
|
||||
|
||||
@@ -363,7 +363,7 @@ const FileTree: FC<FileTreeProps> = (props: FileTreeProps) => {
|
||||
}
|
||||
|
||||
return <FileTreeSidebarUnderSearchWrapper>
|
||||
<FileTreeSidebarHighlight style={{ paddingLeft: 0 }}>{checkedFilePaths.length}</FileTreeSidebarHighlight>
|
||||
<FileTreeSidebarHighlight style={{ marginLeft: 0 }}>{checkedFilePaths.length}</FileTreeSidebarHighlight>
|
||||
Files.
|
||||
<FileTreeSidebarHighlight>{formatNumWithK(totalTokenNum)}</FileTreeSidebarHighlight>
|
||||
Tokens.
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { type FC, useState } from 'react'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import { type MaybePromise, sleep } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { IconButton } from '../../../../components/icon-button'
|
||||
import { initGptFiles } from '../../../../networks/gpt-files'
|
||||
import { getGlobalConfig } from '../../../../helpers/global-config'
|
||||
import { LoadingView } from '../../../../components/loading-view'
|
||||
import { StyledVSCodeTag, Title, Wrapper } from './init-gpt-files.styles'
|
||||
|
||||
export interface InitGptFilesProps {
|
||||
rootPath: string
|
||||
onCreated?: () => MaybePromise<void>
|
||||
}
|
||||
|
||||
export const InitGptFiles: FC<InitGptFilesProps> = (props) => {
|
||||
const { rootPath, onCreated } = props
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const { mutate: runInitGptFiles } = useMutation({
|
||||
mutationKey: ['initGptFiles', rootPath],
|
||||
mutationFn: () => initGptFiles({
|
||||
rootPath: getGlobalConfig().rootPath,
|
||||
gptFilesNames: ['copilot'],
|
||||
}),
|
||||
})
|
||||
|
||||
const handleCreate = async () => {
|
||||
setIsLoading(true)
|
||||
|
||||
try {
|
||||
await runInitGptFiles()
|
||||
await sleep(1000)
|
||||
await onCreated?.()
|
||||
}
|
||||
finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return <Wrapper>
|
||||
<Title>
|
||||
There is no
|
||||
<StyledVSCodeTag>xxx.gpt.md</StyledVSCodeTag>
|
||||
file in the current directory.
|
||||
</Title>
|
||||
<Title>
|
||||
Do you need to create a
|
||||
<StyledVSCodeTag>./gpt-presets/copilot.gpt.md</StyledVSCodeTag>
|
||||
file?
|
||||
</Title>
|
||||
<IconButton
|
||||
text='Yes, Create'
|
||||
hoverShowText={false}
|
||||
iconClassName='codicon-new-file'
|
||||
onClick={handleCreate}></IconButton>
|
||||
{isLoading && <LoadingView absolute></LoadingView>}
|
||||
</Wrapper>
|
||||
}
|
||||
|
||||
InitGptFiles.displayName = 'InitGptFiles'
|
||||
@@ -0,0 +1,30 @@
|
||||
import { VSCodeTag } from '@vscode/webview-ui-toolkit/react'
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 1rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`
|
||||
|
||||
export const Title = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 1rem;
|
||||
`
|
||||
|
||||
export const StyledVSCodeTag = styled(VSCodeTag)`
|
||||
margin: 0 0.5rem;
|
||||
|
||||
&::part(control) {
|
||||
font-size: 1.1rem;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
`
|
||||
@@ -18,6 +18,7 @@ import { ChatSidebar } from './components/chat-sidebar'
|
||||
import { ChatPanel } from './components/chat-panel'
|
||||
import FileTree from './components/file-tree'
|
||||
import { Settings } from './components/settings'
|
||||
import { InitGptFiles } from './components/init-gpt-files'
|
||||
|
||||
enum TabId {
|
||||
Explore = 'explore',
|
||||
@@ -28,7 +29,7 @@ enum TabId {
|
||||
const Chat: FC = () => {
|
||||
const isMobile = useIsMobile()
|
||||
const { width: windowWidth, height: windowHeight } = useWindowSize()
|
||||
const { activeChatId, updateActiveChatId } = useGlobalStore()
|
||||
const { activeChatId, sidebarTree, updateActiveChatId, updateSidebarTreeFromRemote } = useGlobalStore()
|
||||
const { chatInstance } = useChatInstance({ chatId: activeChatId })
|
||||
const [scrollDownRef, scrollDown, getScrollBottom] = useScrollDown()
|
||||
const [tabActiveId, setTabActiveId] = useState(TabId.Explore)
|
||||
@@ -37,6 +38,7 @@ const Chat: FC = () => {
|
||||
queryKey: ['fetchProjectInfo'],
|
||||
queryFn: () => fetchProjectInfo(),
|
||||
})
|
||||
const rootPath = getGlobalConfig().rootPath
|
||||
|
||||
// when active chat id change, change tab active id
|
||||
useEffect(() => {
|
||||
@@ -63,25 +65,25 @@ const Chat: FC = () => {
|
||||
}, [scrollDownRef.current])
|
||||
|
||||
const renderSidebar = useCallback(() => {
|
||||
if (!getGlobalConfig().rootPath)
|
||||
if (!rootPath)
|
||||
return null
|
||||
|
||||
return <SidebarWrapper className='sidebar-wrapper'>
|
||||
<ChatSidebar rootPath={getGlobalConfig().rootPath}></ChatSidebar>
|
||||
<ChatSidebar rootPath={rootPath}></ChatSidebar>
|
||||
</SidebarWrapper>
|
||||
}, [])
|
||||
|
||||
const renderFileTree = useCallback(() => {
|
||||
if (!getGlobalConfig().rootPath)
|
||||
if (!rootPath)
|
||||
return null
|
||||
|
||||
return <SidebarWrapper className='sidebar-wrapper'>
|
||||
<FileTree rootPath={getGlobalConfig().rootPath}></FileTree>
|
||||
<FileTree rootPath={rootPath}></FileTree>
|
||||
</SidebarWrapper>
|
||||
}, [])
|
||||
|
||||
const renderSettings = useCallback((showSingleFileConfig = false) => {
|
||||
if (!getGlobalConfig().rootPath)
|
||||
if (!rootPath)
|
||||
return null
|
||||
|
||||
return <SidebarWrapper className='sidebar-wrapper'>
|
||||
@@ -108,12 +110,19 @@ const Chat: FC = () => {
|
||||
updateActiveChatId,
|
||||
])
|
||||
|
||||
if (!getGlobalConfig().rootPath)
|
||||
if (!rootPath)
|
||||
return <ErrorView text="Please provide the root path!"></ErrorView>
|
||||
|
||||
if (fetchProjectInfoRes?.data?.nodeVersionValidMessage)
|
||||
return <ErrorView text={fetchProjectInfoRes?.data?.nodeVersionValidMessage}></ErrorView>
|
||||
|
||||
if (!sidebarTree?.length) {
|
||||
return <InitGptFiles
|
||||
rootPath={rootPath}
|
||||
onCreated={() => updateSidebarTreeFromRemote(rootPath)}
|
||||
></InitGptFiles>
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
const viewStyle: CSSProperties = {
|
||||
height: '100%',
|
||||
|
||||
@@ -291,6 +291,7 @@ export const MarkdownStyle = createGlobalStyle`
|
||||
padding: 0 0.25rem;
|
||||
white-space: nowrap;
|
||||
background: var(--button-primary-background);
|
||||
color: var(--button-primary-foreground);
|
||||
border-radius: 0.25rem;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,16 @@ const dirname = PathUtils.getCurrentDirName(import.meta.url, () => __dirname)
|
||||
|
||||
const resolvePath = (...paths: string[]) => path.resolve(dirname, ...paths)
|
||||
|
||||
export const clientDistPath = resolvePath('../dist/browser')
|
||||
export const DEFAULT_CLIENT_DIST_PATH = resolvePath('../dist/browser')
|
||||
|
||||
export interface StartServerProps {
|
||||
port?: number
|
||||
autoFreePort?: boolean
|
||||
clientDistPath?: string
|
||||
}
|
||||
|
||||
export async function startServer(props: StartServerProps): Promise<Express> {
|
||||
const { port = 3003, autoFreePort } = props
|
||||
const { port = 3003, autoFreePort, clientDistPath = DEFAULT_CLIENT_DIST_PATH } = props
|
||||
|
||||
const finalPort = await getPort({
|
||||
defaultPort: port,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { getGptFilesInfo, loadUserConfig } from '@nicepkg/gpt-runner-core'
|
||||
import type { GptInitFileName } from '@nicepkg/gpt-runner-core'
|
||||
import { getGptFilesInfo, initGptFiles, loadUserConfig } from '@nicepkg/gpt-runner-core'
|
||||
import { PathUtils, sendFailResponse, sendSuccessResponse, verifyParamsByZod } from '@nicepkg/gpt-runner-shared/node'
|
||||
import type { GetGptFilesReqParams, GetGptFilesTreeResData } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { Debug, GetGptFilesReqParamsSchema, resetUserConfigUnsafeKey } from '@nicepkg/gpt-runner-shared/common'
|
||||
import type { GetGptFilesReqParams, GetGptFilesTreeResData, InitGptFilesReqParams, InitGptFilesResData } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { Debug, GetGptFilesReqParamsSchema, InitGptFilesReqParamsSchema, resetUserConfigUnsafeKey } from '@nicepkg/gpt-runner-shared/common'
|
||||
import type { ControllerConfig } from '../types'
|
||||
|
||||
const debug = new Debug('gpt-files.controller')
|
||||
@@ -45,5 +46,34 @@ export const gptFilesControllers: ControllerConfig = {
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
url: '/init-gpt-files',
|
||||
method: 'post',
|
||||
handler: async (req, res) => {
|
||||
const body = req.body as InitGptFilesReqParams
|
||||
|
||||
verifyParamsByZod(body, InitGptFilesReqParamsSchema)
|
||||
|
||||
const { rootPath, gptFilesNames } = body
|
||||
const finalPath = PathUtils.resolve(rootPath)
|
||||
|
||||
if (!PathUtils.isDirectory(finalPath)) {
|
||||
sendFailResponse(res, {
|
||||
message: 'rootPath is not a valid directory',
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await initGptFiles({
|
||||
rootPath: finalPath,
|
||||
gptFilesNames: gptFilesNames as GptInitFileName[],
|
||||
})
|
||||
|
||||
sendSuccessResponse(res, {
|
||||
data: null satisfies InitGptFilesResData,
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import { program } from 'commander'
|
||||
import pkg from '../package.json'
|
||||
import type { StartServerProps } from './index'
|
||||
import { startServer } from './index'
|
||||
|
||||
program.option('-p, --port <port>', 'Port number', parseInt)
|
||||
program.option('--auto-free-port', 'Automatically find a free port')
|
||||
program.option('--auto-open', 'Automatically open the browser')
|
||||
program.option('--client-dist-path <clientDistPath>', 'Client dist path')
|
||||
program.option('-v, --version', 'Version number')
|
||||
program.parse(process.argv)
|
||||
|
||||
interface ProgramOpts {
|
||||
port?: StartServerProps['port']
|
||||
port?: number
|
||||
autoFreePort?: boolean
|
||||
autoOpen?: boolean
|
||||
clientDistPath?: string
|
||||
version?: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
|
||||
#01 你充当前端开发专家。
|
||||
#02 user 将提供一些关于前端代码问题的具体信息,而你的工作就是想出为 user 解决问题的策略。这可能包括建议代码、代码逻辑思路策略。
|
||||
#03 你如果想要增删改文件,应该需要告诉 user 文件的完整路径,以及你想要增删改的内容。
|
||||
#04 你的代码应该遵循 SOLID and KISS and DRY principles
|
||||
#05 你应该一步步思考完再作答
|
||||
#06 你应该非常细心,不要遗漏 user 提问的任何信息或需求,回答要完整
|
||||
#03 你的代码应该遵循 SOLID and KISS and DRY principles
|
||||
#04 你应该一步步思考完再作答
|
||||
#05 你应该非常细心,不要遗漏 user 提问的任何信息或需求,回答要完整
|
||||
|
||||
# User Prompt
|
||||
|
||||
|
||||
Reference in New Issue
Block a user