黄中银 3 долоо хоног өмнө
parent
commit
0cb65a6892

+ 23 - 4
ApqInstaller/electron/modules/installer.ts

@@ -886,7 +886,8 @@ export async function installAll(options: InstallOptions, onStatus: StatusCallba
     installGit: doGit = true,
     gitVersion = 'stable',
     gitPath,
-    installClaudeCode: doClaudeCode = false
+    installClaudeCode: doClaudeCode = false,
+    installClaudeCodeExt: doClaudeCodeExt = false
   } = options
 
   const platform = os.platform() as Platform
@@ -894,8 +895,9 @@ export async function installAll(options: InstallOptions, onStatus: StatusCallba
   // Claude Code 需要 Node.js 和 Git,计算步骤时考虑这一点
   const steps =
     [doNodejs, doVscode, doGit].filter(Boolean).length +
-    (doNodejs && doPnpm ? 1 : 0) +
-    (doClaudeCode ? 1 : 0)
+    (doPnpm ? 1 : 0) +
+    (doClaudeCode ? 1 : 0) +
+    (doClaudeCodeExt ? 1 : 0)
   let currentStep = 0
   const getProgress = (): number => Math.round((currentStep / steps) * 100)
 
@@ -1130,12 +1132,29 @@ export async function installAll(options: InstallOptions, onStatus: StatusCallba
     currentStep++
   }
 
+  // 安装 Claude Code for VS Code 扩展 (需要 VS Code 和 Claude Code)
+  if (doClaudeCodeExt) {
+    checkCancelled()
+    onStatus('all', `${STATUS_MESSAGES.INSTALLING} Claude Code for VS Code 插件...`, getProgress())
+
+    try {
+      // 使用 code 命令安装扩展
+      await executeCommand('code', ['--install-extension', 'anthropic.claude-code', '--force'], false)
+      logger.installInfo('Claude Code for VS Code 扩展安装成功')
+    } catch (error) {
+      logger.installWarn('Claude Code for VS Code 扩展安装失败', error)
+    }
+    currentStep++
+  }
+
   // 生成完成消息
   const installed: string[] = []
-  if (doNodejs) installed.push(doPnpm ? 'Node.js + pnpm' : 'Node.js')
+  if (doNodejs) installed.push('Node.js')
+  if (doPnpm) installed.push('pnpm')
   if (doVscode) installed.push('VS Code')
   if (doGit) installed.push('Git')
   if (doClaudeCode) installed.push('Claude Code')
+  if (doClaudeCodeExt) installed.push('Claude Code 插件')
 
   return installed
 }

+ 6 - 6
ApqInstaller/electron/modules/ipc-handlers.ts

@@ -806,7 +806,7 @@ export function registerHandlers(): void {
 
   // 统一安装入口
   registerHandler('install', async (_event, software: SoftwareTypeWithAll, options: InstallOptions = {}) => {
-    const { version, installPnpm = true, nodejsPath, vscodePath, gitPath } = options
+    const { version, nodejsPath, vscodePath, gitPath } = options
     const startTime = Date.now()
 
     // 状态回调
@@ -825,12 +825,12 @@ export function registerHandlers(): void {
 
       switch (software) {
         case 'nodejs':
-          await installNodejs(version, installPnpm, onStatus, nodejsPath)
+          await installNodejs(version, false, onStatus, nodejsPath)
           sendToRenderer('install-complete', {
-        software: 'nodejs',
-        message: installPnpm ? '✅ Node.js + pnpm 安装完成!' : '✅ Node.js 安装完成!',
-        i18nKey: installPnpm ? 'log.nodejsPnpmComplete' : 'log.nodejsComplete'
-      })
+            software: 'nodejs',
+            message: '✅ Node.js 安装完成!',
+            i18nKey: 'log.nodejsComplete'
+          })
           break
 
         case 'vscode':

+ 1 - 0
ApqInstaller/shared/types.ts

@@ -42,6 +42,7 @@ export interface InstallOptions {
   gitVersion?: string
   gitPath?: string // Git 自定义安装路径 (仅 Windows)
   installClaudeCode?: boolean
+  installClaudeCodeExt?: boolean // Claude Code for VS Code 扩展
   customPath?: string
 }
 

+ 2 - 3
ApqInstaller/src/App.vue

@@ -39,9 +39,9 @@ interface TabConfig {
 const tabs: TabConfig[] = [
   { id: 'intro', label: 'tabs.intro', component: markRaw(IntroView) },
   { id: 'nodejs', label: 'tabs.nodejs', component: markRaw(NodejsView), showInstalledDot: true, softwareType: 'nodejs' },
+  { id: 'claudeCode', label: 'tabs.claudeCode', component: markRaw(ClaudeCodeView), showInstalledDot: true, softwareType: 'claudeCode' },
   { id: 'vscode', label: 'tabs.vscode', component: markRaw(VscodeView), showInstalledDot: true, softwareType: 'vscode' },
   { id: 'git', label: 'tabs.git', component: markRaw(GitView), showInstalledDot: true, softwareType: 'git' },
-  { id: 'claudeCode', label: 'tabs.claudeCode', component: markRaw(ClaudeCodeView), showInstalledDot: true, softwareType: 'claudeCode' },
   { id: 'all', label: 'tabs.all', component: markRaw(BatchInstallView) }
 ]
 
@@ -58,8 +58,7 @@ async function handleInstall(software: SoftwareType) {
   const versionedSoftware = software as 'nodejs' | 'vscode' | 'git'
   const hasVersion = software === 'nodejs' || software === 'vscode' || software === 'git'
   const options = {
-    version: hasVersion ? versionsStore.selectedVersions[versionedSoftware] : undefined,
-    installPnpm: software === 'nodejs' ? installStore.installOptions.nodejs.installPnpm : undefined
+    version: hasVersion ? versionsStore.selectedVersions[versionedSoftware] : undefined
   }
   await installStore.doInstall(software, options)
 }

+ 1 - 0
ApqInstaller/src/i18n/en-US.ts

@@ -66,6 +66,7 @@ export default {
       claudeCodeExt: 'Claude Code for VS Code Extension',
       claudeCodeExtDesc: 'Use Claude Code\'s powerful features directly in VS Code without leaving your editor',
       claudeCodeExtRequiresCli: 'Requires Claude Code to be installed first (install in Claude Code tab)',
+      claudeCodeExtRequiresVscodeAndCli: 'Requires VS Code and Claude Code',
       installClaudeCodeExt: 'Install Extension',
       installVscodeFirst: 'Please install VS Code first'
     },

+ 1 - 0
ApqInstaller/src/i18n/zh-CN.ts

@@ -66,6 +66,7 @@ export default {
       claudeCodeExt: 'Claude Code for VS Code 插件',
       claudeCodeExtDesc: '在 VS Code 中使用 Claude Code 的强大功能,无需离开编辑器',
       claudeCodeExtRequiresCli: '需要先安装 Claude Code(在 Claude Code 标签页安装)',
+      claudeCodeExtRequiresVscodeAndCli: '需要 VS Code 和 Claude Code',
       installClaudeCodeExt: '安装插件',
       installVscodeFirst: '请先安装 VS Code'
     },

+ 5 - 8
ApqInstaller/src/stores/install.ts

@@ -24,7 +24,7 @@ interface InstallStatusState {
 }
 
 interface InstallOptionsState {
-  nodejs: { installPnpm: boolean; customPath?: string }
+  nodejs: { customPath?: string }
   vscode: { customPath?: string }
   git: { customPath?: string }
   all: {
@@ -33,6 +33,7 @@ interface InstallOptionsState {
     installGit: boolean
     installPnpm: boolean
     installClaudeCode: boolean
+    installClaudeCodeExt: boolean
     nodejsPath?: string
     vscodePath?: string
     gitPath?: string
@@ -70,7 +71,7 @@ export const useInstallStore = defineStore('install', () => {
 
   // 安装选项
   const installOptions = ref<InstallOptionsState>({
-    nodejs: { installPnpm: true },
+    nodejs: {},
     vscode: {},
     git: {},
     all: {
@@ -78,7 +79,8 @@ export const useInstallStore = defineStore('install', () => {
       installVscode: true,
       installGit: true,
       installPnpm: true,
-      installClaudeCode: true
+      installClaudeCode: true,
+      installClaudeCodeExt: true
     }
   })
 
@@ -131,11 +133,6 @@ export const useInstallStore = defineStore('install', () => {
       const result = await window.electronAPI.checkInstalled('all') as AllInstalledInfo
       if (result) {
         installedInfo.value = result
-        // 如果 pnpm 已安装,自动取消勾选安装选项
-        if (result.pnpm.installed) {
-          installOptions.value.nodejs.installPnpm = false
-          installOptions.value.all.installPnpm = false
-        }
       }
     } catch (error) {
       const errorMsg = error instanceof Error ? error.message : String(error)

+ 69 - 25
ApqInstaller/src/views/BatchInstallView.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { computed } from 'vue'
+import { computed, ref, onMounted } from 'vue'
 import { useI18n } from 'vue-i18n'
 import { useVersionsStore } from '@/stores/versions'
 import { useInstallStore } from '@/stores/install'
@@ -23,9 +23,26 @@ const needInstallVscode = computed(() => !installStore.isInstalled('vscode'))
 const needInstallGit = computed(() => !installStore.isInstalled('git'))
 const needInstallClaudeCode = computed(() => !installStore.isInstalled('claudeCode'))
 
+// Claude Code VS Code 扩展状态
+const claudeCodeExtInstalled = ref(false)
+const needInstallClaudeCodeExt = computed(() => !claudeCodeExtInstalled.value)
+
+async function checkClaudeCodeExtInstalled() {
+  try {
+    const result = await window.electronAPI.checkVscodeExtension('anthropic.claude-code')
+    claudeCodeExtInstalled.value = result.installed
+  } catch {
+    claudeCodeExtInstalled.value = false
+  }
+}
+
+onMounted(() => {
+  checkClaudeCodeExtInstalled()
+})
+
 // 是否有需要安装的软件
 const hasAnythingToInstall = computed(() =>
-  needInstallNodejs.value || needInstallPnpm.value || needInstallVscode.value || needInstallGit.value || needInstallClaudeCode.value
+  needInstallNodejs.value || needInstallPnpm.value || needInstallVscode.value || needInstallGit.value || needInstallClaudeCode.value || needInstallClaudeCodeExt.value
 )
 
 const isDisabled = computed(() =>
@@ -61,14 +78,15 @@ async function handleInstall() {
     installNodejs: needInstallNodejs.value,
     nodejsVersion: versionsStore.selectedVersions.nodejs,
     nodejsPath: installStore.installOptions.all.nodejsPath,
-    installPnpm: needInstallNodejs.value && installStore.installOptions.all.installPnpm,
+    installPnpm: needInstallPnpm.value && installStore.installOptions.all.installPnpm,
     installVscode: needInstallVscode.value,
     vscodeVersion: versionsStore.selectedVersions.vscode,
     vscodePath: installStore.installOptions.all.vscodePath,
     installGit: needInstallGit.value,
     gitVersion: versionsStore.selectedVersions.git,
     gitPath: installStore.installOptions.all.gitPath,
-    installClaudeCode: needInstallClaudeCode.value
+    installClaudeCode: needInstallClaudeCode.value,
+    installClaudeCodeExt: needInstallClaudeCodeExt.value && installStore.installOptions.all.installClaudeCodeExt
   }
 
   await installStore.doInstall('all', options)
@@ -125,7 +143,11 @@ async function handleCancel() {
       <!-- pnpm -->
       <div class="option-group">
         <div class="option-row">
-          <el-checkbox v-model="installStore.installOptions.all.installPnpm" :disabled="installStore.isInstalled('pnpm')">
+          <el-checkbox
+            :model-value="!installStore.isInstalled('pnpm') && installStore.installOptions.all.installPnpm"
+            :disabled="installStore.isInstalled('pnpm')"
+            @update:model-value="installStore.installOptions.all.installPnpm = $event"
+          >
             <span class="software-label">
               <SoftwareIcon software="nodejs" :size="18" />
               <span>pnpm</span>
@@ -140,6 +162,24 @@ async function handleCancel() {
         </div>
       </div>
 
+      <!-- Claude Code -->
+      <div class="option-group">
+        <div class="option-row">
+          <el-checkbox :model-value="needInstallClaudeCode" disabled>
+            <span class="software-label">
+              <SoftwareIcon software="claudeCode" :size="18" />
+              <span>Claude Code</span>
+            </span>
+            <el-tag v-if="installStore.isInstalled('claudeCode')" type="success" size="small" style="margin-left: 8px">
+              {{ t('common.installed') }} v{{ installStore.getInstalledVersion('claudeCode') }}
+            </el-tag>
+          </el-checkbox>
+          <span v-if="needInstallClaudeCode" class="option-hint">
+            {{ t('claudeCode.requiresNodejsGit') }}
+          </span>
+        </div>
+      </div>
+
       <!-- VS Code -->
       <div class="option-group">
         <div class="option-row">
@@ -149,7 +189,7 @@ async function handleCancel() {
               <span>VS Code</span>
             </span>
             <el-tag v-if="installStore.isInstalled('vscode')" type="success" size="small" style="margin-left: 8px">
-              {{ t('common.installed') }}
+              {{ t('common.installed') }} v{{ installStore.getInstalledVersion('vscode') }}
             </el-tag>
           </el-checkbox>
           <div v-if="needInstallVscode" class="option-details">
@@ -175,6 +215,28 @@ async function handleCancel() {
         </div>
       </div>
 
+      <!-- Claude Code for VS Code 扩展 -->
+      <div class="option-group">
+        <div class="option-row">
+          <el-checkbox
+            :model-value="!claudeCodeExtInstalled && installStore.installOptions.all.installClaudeCodeExt"
+            :disabled="claudeCodeExtInstalled"
+            @update:model-value="installStore.installOptions.all.installClaudeCodeExt = $event"
+          >
+            <span class="software-label">
+              <SoftwareIcon software="vscode" :size="18" />
+              <span>{{ t('software.vscode.claudeCodeExt') }}</span>
+            </span>
+            <el-tag v-if="claudeCodeExtInstalled" type="success" size="small" style="margin-left: 8px">
+              {{ t('common.installed') }}
+            </el-tag>
+          </el-checkbox>
+          <span v-if="needInstallClaudeCodeExt && !installStore.isInstalled('vscode')" class="option-hint">
+            {{ t('software.vscode.installVscodeFirst') }}
+          </span>
+        </div>
+      </div>
+
       <!-- Git -->
       <div class="option-group">
         <div class="option-row">
@@ -184,7 +246,7 @@ async function handleCancel() {
               <span>Git</span>
             </span>
             <el-tag v-if="installStore.isInstalled('git')" type="success" size="small" style="margin-left: 8px">
-              {{ t('common.installed') }}
+              {{ t('common.installed') }} v{{ installStore.getInstalledVersion('git') }}
             </el-tag>
           </el-checkbox>
           <div v-if="needInstallGit" class="option-details">
@@ -209,24 +271,6 @@ async function handleCancel() {
           />
         </div>
       </div>
-
-      <!-- Claude Code -->
-      <div class="option-group">
-        <div class="option-row">
-          <el-checkbox :model-value="needInstallClaudeCode" disabled>
-            <span class="software-label">
-              <SoftwareIcon software="claudeCode" :size="18" />
-              <span>Claude Code</span>
-            </span>
-            <el-tag v-if="installStore.isInstalled('claudeCode')" type="success" size="small" style="margin-left: 8px">
-              {{ t('common.installed') }}
-            </el-tag>
-          </el-checkbox>
-          <span v-if="needInstallClaudeCode" class="option-hint">
-            {{ t('claudeCode.requiresNodejsGit') }}
-          </span>
-        </div>
-      </div>
     </div>
 
     <div class="button-group">

+ 1 - 1
ApqInstaller/src/views/NodejsView.vue

@@ -74,7 +74,7 @@ async function handleInstallPnpm() {
     pnpmError.value = (error as Error).message
   } finally {
     pnpmInstalling.value = false
-    await installStore.checkInstallStatus('pnpm')
+    await installStore.checkInstalledSoftware()
   }
 }
 </script>