refactor: 重构 provider、agents、status 及相关工具模块

This commit is contained in:
Ubuntu 2026-04-14 14:19:27 +00:00
parent 3c41abe5ef
commit 88e2ce1e70
34 changed files with 301 additions and 311 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
#node_modules node_modules
.DS_Store .DS_Store
dist dist
coverage coverage

View File

@ -1,2 +0,0 @@
{"t":0,"agent":"a9f2b75","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"}
{"t":0,"agent":"a9f2b75","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":268224}

View File

@ -1,5 +1,5 @@
{ {
"name": "@costrict/csc-beta", "name": "@costrict/csc",
"version": "4.0.4", "version": "4.0.4",
"description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal", "description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal",

View File

@ -2,27 +2,27 @@ import { feature } from 'bun:bundle'
import { getIsNonInteractiveSession } from 'src/bootstrap/state.js' import { getIsNonInteractiveSession } from 'src/bootstrap/state.js'
import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js'
import { isEnvTruthy } from 'src/utils/envUtils.js' import { isEnvTruthy } from 'src/utils/envUtils.js'
import { DESIGN_AGENT } from '../../costrict/agents/designAgent.js' import { DESIGN_AGENT } from 'src/costrict/agents/designAgent.js'
import { QUICK_EXPLORE_AGENT } from '../../costrict/agents/quickExplore.js' import { QUICK_EXPLORE_AGENT } from 'src/costrict/agents/quickExplore.js'
import { REQUIREMENT_AGENT } from '../../costrict/agents/requirement.js' import { REQUIREMENT_AGENT } from 'src/costrict/agents/requirement.js'
import { STRICT_PLAN_AGENT } from '../../costrict/agents/strictPlan.js' import { STRICT_PLAN_AGENT } from 'src/costrict/agents/strictPlan.js'
// import { STRICT_SPEC_AGENT } from '../../costrict/agents/strictSpec.js' // import { STRICT_SPEC_AGENT } from 'src/costrict/agents/strictSpec.js'
import { SUB_CODING_AGENT } from '../../costrict/agents/subCoding.js' import { SUB_CODING_AGENT } from 'src/costrict/agents/subCoding.js'
import { TASK_CHECK_AGENT } from '../../costrict/agents/taskCheck.js' import { TASK_CHECK_AGENT } from 'src/costrict/agents/taskCheck.js'
import { TASK_PLAN_AGENT } from '../../costrict/agents/taskPlan.js' import { TASK_PLAN_AGENT } from 'src/costrict/agents/taskPlan.js'
import { CLAUDE_CODE_GUIDE_AGENT } from './built-in/claudeCodeGuideAgent.js' import { CLAUDE_CODE_GUIDE_AGENT } from './built-in/claudeCodeGuideAgent.js'
import { EXPLORE_AGENT } from './built-in/exploreAgent.js' import { EXPLORE_AGENT } from './built-in/exploreAgent.js'
import { GENERAL_PURPOSE_AGENT } from './built-in/generalPurposeAgent.js' import { GENERAL_PURPOSE_AGENT } from './built-in/generalPurposeAgent.js'
import { PLAN_AGENT } from './built-in/planAgent.js' import { PLAN_AGENT } from './built-in/planAgent.js'
import { WIKI_PROJECT_ANALYZE_AGENT } from '../../costrict/agents/wikiProjectAnalyze.js' import { WIKI_PROJECT_ANALYZE_AGENT } from 'src/costrict/agents/wikiProjectAnalyze.js'
import { WIKI_CATALOGUE_DESIGN_AGENT } from '../../costrict/agents/wikiCatalogueDesign.js' import { WIKI_CATALOGUE_DESIGN_AGENT } from 'src/costrict/agents/wikiCatalogueDesign.js'
import { WIKI_DOCUMENT_GENERATE_AGENT } from '../../costrict/agents/wikiDocumentGenerate.js' import { WIKI_DOCUMENT_GENERATE_AGENT } from 'src/costrict/agents/wikiDocumentGenerate.js'
import { WIKI_INDEX_GENERATION_AGENT } from '../../costrict/agents/wikiIndexGeneration.js' import { WIKI_INDEX_GENERATION_AGENT } from 'src/costrict/agents/wikiIndexGeneration.js'
import { TDD_RUN_AND_FIX_AGENT } from '../../costrict/agents/tddRunAndFix.js' import { TDD_RUN_AND_FIX_AGENT } from 'src/costrict/agents/tddRunAndFix.js'
import { TDD_TEST_AND_FIX_AGENT } from '../../costrict/agents/tddTestAndFix.js' import { TDD_TEST_AND_FIX_AGENT } from 'src/costrict/agents/tddTestAndFix.js'
import { TDD_TEST_DESIGN_AGENT } from '../../costrict/agents/tddTestDesign.js' import { TDD_TEST_DESIGN_AGENT } from 'src/costrict/agents/tddTestDesign.js'
import { TDD_TEST_PREPARE_AGENT } from '../../costrict/agents/tddTestPrepare.js' import { TDD_TEST_PREPARE_AGENT } from 'src/costrict/agents/tddTestPrepare.js'
import { TDD_AGENT } from '../../costrict/backup/tdd.js' import { TDD_AGENT } from 'src/costrict/backup/tdd.js'
import { STATUSLINE_SETUP_AGENT } from './built-in/statuslineSetup.js' import { STATUSLINE_SETUP_AGENT } from './built-in/statuslineSetup.js'
import { VERIFICATION_AGENT } from './built-in/verificationAgent.js' import { VERIFICATION_AGENT } from './built-in/verificationAgent.js'
import type { AgentDefinition } from './loadAgentsDir.js' import type { AgentDefinition } from './loadAgentsDir.js'

View File

@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { Theme } from '@anthropic/ink';
import { import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent, logEvent,
@ -1251,7 +1252,7 @@ function OAuthStatusMessage({
<Box flexDirection="column" gap={1}> <Box flexDirection="column" gap={1}>
<Text>Opening browser for CoStrict login. If it does not open automatically, copy and paste this URL:</Text> <Text>Opening browser for CoStrict login. If it does not open automatically, copy and paste this URL:</Text>
<Box marginY={1}> <Box marginY={1}>
<Text color="cyan">{oauthStatus.url}</Text> <Text color={'cyan' as keyof Theme}>{oauthStatus.url}</Text>
</Box> </Box>
<Text dimColor>Waiting for authentication...</Text> <Text dimColor>Waiting for authentication...</Text>
</Box> </Box>

View File

@ -1,5 +1,5 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getDesignAgentSystemPrompt(): string { function getDesignAgentSystemPrompt(): string {
return `你是 DesignAgent一名专业软件开发团队中的资深软件架构师。 return `你是 DesignAgent一名专业软件开发团队中的资深软件架构师。

View File

@ -1,9 +1,9 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js'
import { FILE_WRITE_TOOL_NAME } from 'src/tools/FileWriteTool/prompt.js' import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getQuickExploreSystemPrompt(): string { function getQuickExploreSystemPrompt(): string {

View File

@ -1,5 +1,5 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getRequirementSystemPrompt(): string { function getRequirementSystemPrompt(): string {
return `# 角色 return `# 角色

View File

@ -1,5 +1,5 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getStrictPlanSystemPrompt(): string { function getStrictPlanSystemPrompt(): string {

View File

@ -1,5 +1,5 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getStrictSpecSystemPrompt(): string { function getStrictSpecSystemPrompt(): string {
return `你是工作流编排专家负责将用户需求按照标准阶段分配到对应工作流Agent执行。 return `你是工作流编排专家负责将用户需求按照标准阶段分配到对应工作流Agent执行。

View File

@ -1,7 +1,7 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getSubCodingSystemPrompt(): string { function getSubCodingSystemPrompt(): string {
return `你是SubCodingAgent一名专业软件开发团队中的开发人员。 return `你是SubCodingAgent一名专业软件开发团队中的开发人员。

View File

@ -1,7 +1,7 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTaskCheckSystemPrompt(): string { function getTaskCheckSystemPrompt(): string {
return `你是 TaskCheckAgent一名专业的软件开发任务质量检查与修复专家。 return `你是 TaskCheckAgent一名专业的软件开发任务质量检查与修复专家。

View File

@ -1,5 +1,5 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTaskPlanSystemPrompt(): string { function getTaskPlanSystemPrompt(): string {
return `# 核心职责 return `# 核心职责

View File

@ -1,5 +1,5 @@
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTddRunAndFixSystemPrompt(): string { function getTddRunAndFixSystemPrompt(): string {
return `<role>你是 RunAndFixAgent一名可运行性验证与代码修复专家擅长诊断和解决编译构建问题。</role> return `<role>你是 RunAndFixAgent一名可运行性验证与代码修复专家擅长诊断和解决编译构建问题。</role>

View File

@ -1,4 +1,4 @@
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTddTestAndFixSystemPrompt(): string { function getTddTestAndFixSystemPrompt(): string {
return `<role>你是 TestAndFixAgent一名测试执行与自动修复专家擅长诊断和解决测试失败问题。</role> return `<role>你是 TestAndFixAgent一名测试执行与自动修复专家擅长诊断和解决测试失败问题。</role>

View File

@ -1,5 +1,5 @@
import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTddTestDesignSystemPrompt(): string { function getTddTestDesignSystemPrompt(): string {
return `<role>你是 TestDesignAgent一名测试点设计与测试用例规划专家精通测试自动化。</role> return `<role>你是 TestDesignAgent一名测试点设计与测试用例规划专家精通测试自动化。</role>

View File

@ -1,6 +1,6 @@
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTddTestPrepareSystemPrompt(): string { function getTddTestPrepareSystemPrompt(): string {
return `<role>你是 TestPrepareAgent一名测试配置检查与文档准备专家专注于项目的测试执行和管理方法识别。</role> return `<role>你是 TestPrepareAgent一名测试配置检查与文档准备专家专注于项目的测试执行和管理方法识别。</role>

View File

@ -1,9 +1,9 @@
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import { EXIT_PLAN_MODE_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from '../../tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { SKILL_TOOL_NAME } from '../../tools/SkillTool/constants.js' import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js'
import { WEB_FETCH_TOOL_NAME } from '../../tools/WebFetchTool/prompt.js' import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getWikiCatalogueDesignSystemPrompt(): string { function getWikiCatalogueDesignSystemPrompt(): string {
return `# 技术文档结构设计 return `# 技术文档结构设计

View File

@ -1,9 +1,9 @@
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import { EXIT_PLAN_MODE_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from '../../tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { SKILL_TOOL_NAME } from '../../tools/SkillTool/constants.js' import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js'
import { WEB_FETCH_TOOL_NAME } from '../../tools/WebFetchTool/prompt.js' import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getWikiDocumentGenerateSystemPrompt(): string { function getWikiDocumentGenerateSystemPrompt(): string {
return `# 技术文档生成 return `# 技术文档生成

View File

@ -1,9 +1,9 @@
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import { EXIT_PLAN_MODE_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from '../../tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { SKILL_TOOL_NAME } from '../../tools/SkillTool/constants.js' import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js'
import { WEB_FETCH_TOOL_NAME } from '../../tools/WebFetchTool/prompt.js' import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getWikiIndexGenerationSystemPrompt(): string { function getWikiIndexGenerationSystemPrompt(): string {
return `# 索引文档生成 return `# 索引文档生成

View File

@ -1,9 +1,9 @@
import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js'
import { EXIT_PLAN_MODE_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from '../../tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import { SKILL_TOOL_NAME } from '../../tools/SkillTool/constants.js' import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js'
import { WEB_FETCH_TOOL_NAME } from '../../tools/WebFetchTool/prompt.js' import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js'
import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getWikiProjectAnalyzeSystemPrompt(): string { function getWikiProjectAnalyzeSystemPrompt(): string {
return `# 项目基本分析 return `# 项目基本分析

View File

@ -1,6 +1,6 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getPlanApplySystemPrompt(): string { function getPlanApplySystemPrompt(): string {
return `你是 CodingAgent软件开发团队的项目管理者和技术架构师。 return `你是 CodingAgent软件开发团队的项目管理者和技术架构师。

View File

@ -1,6 +1,6 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getReviewAndFixSystemPrompt(): string { function getReviewAndFixSystemPrompt(): string {
return `你是ReviewAndFix Agent一名专业软件开发团队中的代码审查与修复专家。 return `你是ReviewAndFix Agent一名专业软件开发团队中的代码审查与修复专家。

View File

@ -1,4 +1,5 @@
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getSpecPlanSystemPrompt(): string { function getSpecPlanSystemPrompt(): string {
return `你是 SpecPlan软件开发团队的全流程实施协调者。 return `你是 SpecPlan软件开发团队的全流程实施协调者。

View File

@ -1,5 +1,5 @@
import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js'
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getStrictPlanSystemPrompt(): string { function getStrictPlanSystemPrompt(): string {

View File

@ -1,4 +1,4 @@
import type { BuiltInAgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
function getTddSystemPrompt(): string { function getTddSystemPrompt(): string {
return `<role>你是 TestDrivenDevelopment Agent负责执行全面的测试工作流程以确保代码质量。</role> return `<role>你是 TestDrivenDevelopment Agent负责执行全面的测试工作流程以确保代码质量。</role>

View File

@ -19,7 +19,9 @@ import { createRequire } from 'module'
function getVersion(): string { function getVersion(): string {
try { try {
if (typeof MACRO !== 'undefined' && MACRO.VERSION) return MACRO.VERSION if (typeof MACRO !== 'undefined' && MACRO.VERSION) return MACRO.VERSION
} catch { /* ignore */ } } catch {
/* ignore */
}
try { try {
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url)
// eslint-disable-next-line @typescript-eslint/no-require-imports // eslint-disable-next-line @typescript-eslint/no-require-imports
@ -41,8 +43,11 @@ const VERSION = getVersion()
* 3. Authorization CoStrict headers * 3. Authorization CoStrict headers
* 4. 401 * 4. 401
*/ */
export function createCoStrictFetch(): typeof fetch { export function createCoStrictFetch() {
return async (input: RequestInfo | URL, init?: RequestInit) => { const costrictFetch = async (
input: RequestInfo | URL,
init?: RequestInit,
) => {
// ========== 步骤 1: 动态读取凭证 ========== // ========== 步骤 1: 动态读取凭证 ==========
let creds = await loadCoStrictCredentials() let creds = await loadCoStrictCredentials()
@ -119,4 +124,6 @@ export function createCoStrictFetch(): typeof fetch {
return response return response
} }
costrictFetch.preconnect = fetch.preconnect.bind(fetch)
return costrictFetch
} }

View File

@ -4,6 +4,7 @@
*/ */
import type { BetaToolUnion } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs' import type { BetaToolUnion } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
import type { SDKAssistantMessageError } from '../../entrypoints/agentSdkTypes.js'
import type { SystemPrompt } from '../../utils/systemPromptType.js' import type { SystemPrompt } from '../../utils/systemPromptType.js'
import type { import type {
Message, Message,
@ -46,7 +47,10 @@ export async function* queryModelCoStrict(
tools: Tools, tools: Tools,
signal: AbortSignal, signal: AbortSignal,
options: Options, options: Options,
): AsyncGenerator<StreamEvent | AssistantMessage | SystemAPIErrorMessage, void> { ): AsyncGenerator<
StreamEvent | AssistantMessage | SystemAPIErrorMessage,
void
> {
try { try {
// 1. 解析模型名 // 1. 解析模型名
const costrictModel = resolveCoStrictModel(options.model) const costrictModel = resolveCoStrictModel(options.model)
@ -73,7 +77,7 @@ export async function* queryModelCoStrict(
) )
const standardTools = toolSchemas.filter( const standardTools = toolSchemas.filter(
(t): t is BetaToolUnion & { type: string } => { (t): t is BetaToolUnion & { type: string } => {
const anyT = t as Record<string, unknown> const anyT = t as unknown as Record<string, unknown>
return ( return (
anyT.type !== 'advisor_20260301' && anyT.type !== 'computer_20250124' anyT.type !== 'advisor_20260301' && anyT.type !== 'computer_20250124'
) )
@ -81,7 +85,11 @@ export async function* queryModelCoStrict(
) )
// 5. 转换为 OpenAI 格式 // 5. 转换为 OpenAI 格式
const openaiMessages = anthropicMessagesToOpenAI(messagesForAPI, systemPrompt, { enableThinking: true }) const openaiMessages = anthropicMessagesToOpenAI(
messagesForAPI,
systemPrompt,
{ enableThinking: true },
)
const openaiTools = anthropicToolsToOpenAI(standardTools) const openaiTools = anthropicToolsToOpenAI(standardTools)
const openaiToolChoice = anthropicToolChoiceToOpenAI(options.toolChoice) const openaiToolChoice = anthropicToolChoiceToOpenAI(options.toolChoice)
@ -93,7 +101,9 @@ export async function* queryModelCoStrict(
maxRetries: 0, maxRetries: 0,
timeout: parseInt(process.env.API_TIMEOUT_MS || String(600 * 1000), 10), timeout: parseInt(process.env.API_TIMEOUT_MS || String(600 * 1000), 10),
dangerouslyAllowBrowser: true, dangerouslyAllowBrowser: true,
fetchOptions: getProxyFetchOptions({ forAnthropicAPI: false }) as RequestInit, fetchOptions: getProxyFetchOptions({
forAnthropicAPI: false,
}) as any,
fetch: costrictFetch as any, fetch: costrictFetch as any,
}) })
@ -108,7 +118,10 @@ export async function* queryModelCoStrict(
messages: openaiMessages, messages: openaiMessages,
...(openaiTools.length > 0 && { ...(openaiTools.length > 0 && {
tools: openaiTools, tools: openaiTools,
...(openaiToolChoice && { tool_choice: openaiToolChoice }), ...(openaiToolChoice && {
tool_choice:
openaiToolChoice as OpenAI.Chat.Completions.ChatCompletionToolChoiceOption,
}),
}), }),
stream: true, stream: true,
stream_options: { include_usage: true }, stream_options: { include_usage: true },
@ -123,7 +136,7 @@ export async function* queryModelCoStrict(
const adaptedStream = adaptOpenAIStreamToAnthropic(stream, costrictModel) const adaptedStream = adaptOpenAIStreamToAnthropic(stream, costrictModel)
const contentBlocks: Record<number, any> = {} const contentBlocks: Record<number, any> = {}
let partialMessage: any = undefined let partialMessage: any
let usage = { let usage = {
input_tokens: 0, input_tokens: 0,
output_tokens: 0, output_tokens: 0,
@ -139,7 +152,7 @@ export async function* queryModelCoStrict(
partialMessage = (event as any).message partialMessage = (event as any).message
ttftMs = Date.now() - start ttftMs = Date.now() - start
if ((event as any).message?.usage) { if ((event as any).message?.usage) {
usage = { ...usage, ...((event as any).message.usage) } usage = { ...usage, ...(event as any).message.usage }
} }
break break
} }
@ -219,7 +232,10 @@ export async function* queryModelCoStrict(
yield createAssistantAPIErrorMessage({ yield createAssistantAPIErrorMessage({
content: `CoStrict API Error: ${errorMsg}`, content: `CoStrict API Error: ${errorMsg}`,
apiError: 'api_error', apiError: 'api_error',
error: error instanceof Error ? error : new Error(String(error)), error:
error instanceof Error
? (error as unknown as SDKAssistantMessageError)
: undefined,
}) })
} }
} }

View File

@ -1,4 +1,4 @@
import { registerBundledSkill } from '../../skills/bundledSkills.js' import { registerBundledSkill } from 'src/skills/bundledSkills.js'
import { BUNDLED_SKILLS } from './builtin.js' import { BUNDLED_SKILLS } from './builtin.js'
export function registerCodeReviewSecuritySkill(): void { export function registerCodeReviewSecuritySkill(): void {

View File

@ -1,5 +1,5 @@
import { getProjectRoot } from '../../bootstrap/state.js' import { getProjectRoot } from '../../bootstrap/state.js'
import { registerBundledSkill } from '../../skills/bundledSkills.js' import { registerBundledSkill } from 'src/skills/bundledSkills.js'
// Orchestrator prompt for the /project-wiki skill. // Orchestrator prompt for the /project-wiki skill.
// Uses `Agent` tool (CSC equivalent of opencode's `task` tool) to delegate // Uses `Agent` tool (CSC equivalent of opencode's `task` tool) to delegate

View File

@ -1,4 +1,4 @@
import { registerBundledSkill } from '../../skills/bundledSkills.js' import { registerBundledSkill } from 'src/skills/bundledSkills.js'
export function registerStrictPlanSkill(): void { export function registerStrictPlanSkill(): void {
registerBundledSkill({ registerBundledSkill({

View File

@ -1,4 +1,4 @@
import { registerBundledSkill } from '../../skills/bundledSkills.js' import { registerBundledSkill } from 'src/skills/bundledSkills.js'
const TDD_PROMPT = `You are executing a comprehensive testing workflow to ensure code quality. const TDD_PROMPT = `You are executing a comprehensive testing workflow to ensure code quality.

View File

@ -27,6 +27,8 @@ import { getModelBetas, modelSupportsStructuredOutputs } from './betas.js'
import { computeFingerprint } from './fingerprint.js' import { computeFingerprint } from './fingerprint.js'
import { normalizeModelStringForAPI } from './model/model.js' import { normalizeModelStringForAPI } from './model/model.js'
import { getAPIProvider } from './model/providers.js' import { getAPIProvider } from './model/providers.js'
import { asSystemPrompt } from './systemPromptType.js'
import type { UserMessage, AssistantMessage } from '../types/message.js'
type MessageParam = Anthropic.MessageParam type MessageParam = Anthropic.MessageParam
type TextBlockParam = Anthropic.TextBlockParam type TextBlockParam = Anthropic.TextBlockParam
@ -257,7 +259,9 @@ async function sideQueryCoStrict(opts: SideQueryOptions): Promise<BetaMessage> {
// Build system prompt // Build system prompt
const systemContent = skipSystemPromptPrefix const systemContent = skipSystemPromptPrefix
? (typeof system === 'string' ? system : '') ? typeof system === 'string'
? system
: ''
: `${getCLISyspromptPrefix({ isNonInteractive: false, hasAppendSystemPrompt: false })} : `${getCLISyspromptPrefix({ isNonInteractive: false, hasAppendSystemPrompt: false })}
${typeof system === 'string' ? system : ''}` ${typeof system === 'string' ? system : ''}`
@ -275,18 +279,15 @@ ${typeof system === 'string' ? system : ''}`
maxRetries: 0, maxRetries: 0,
timeout: parseInt(process.env.API_TIMEOUT_MS || String(600 * 1000), 10), timeout: parseInt(process.env.API_TIMEOUT_MS || String(600 * 1000), 10),
dangerouslyAllowBrowser: true, dangerouslyAllowBrowser: true,
fetchOptions: getProxyFetchOptions({ forAnthropicAPI: false }) as RequestInit, fetchOptions: getProxyFetchOptions({ forAnthropicAPI: false }) as any,
fetch: costrictFetch as any, fetch: costrictFetch as any,
}) })
// Convert messages to OpenAI format // Convert messages to OpenAI format
const openaiMessages = anthropicMessagesToOpenAI( const openaiMessages = anthropicMessagesToOpenAI(
messages.map(m => ({ messages as unknown as (UserMessage | AssistantMessage)[],
...m, asSystemPrompt([systemContent]),
content: typeof m.content === 'string' ? m.content : m.content, { enableThinking: false },
})),
systemContent,
{ enableThinking: false }
) )
// Build request // Build request
@ -299,7 +300,7 @@ ${typeof system === 'string' ? system : ''}`
// Add response_format for JSON schema if specified // Add response_format for JSON schema if specified
if (output_format?.type === 'json_schema') { if (output_format?.type === 'json_schema') {
(requestBody as any).response_format = { ;(requestBody as any).response_format = {
type: 'json_schema', type: 'json_schema',
json_schema: { json_schema: {
name: 'response', name: 'response',
@ -333,15 +334,19 @@ ${typeof system === 'string' ? system : ''}`
const now = Date.now() const now = Date.now()
const lastCompletion = getLastApiCompletionTimestamp() const lastCompletion = getLastApiCompletionTimestamp()
logEvent('tengu_api_success', { logEvent('tengu_api_success', {
requestId: response.id as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, requestId:
querySource: opts.querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, response.id as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
model: costrictModel as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, querySource:
opts.querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
model:
costrictModel as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
inputTokens: response.usage?.prompt_tokens || 0, inputTokens: response.usage?.prompt_tokens || 0,
outputTokens: response.usage?.completion_tokens || 0, outputTokens: response.usage?.completion_tokens || 0,
cachedInputTokens: 0, cachedInputTokens: 0,
uncachedInputTokens: 0, uncachedInputTokens: 0,
durationMsIncludingRetries: now - start, durationMsIncludingRetries: now - start,
timeSinceLastApiCallMs: lastCompletion !== null ? now - lastCompletion : undefined, timeSinceLastApiCallMs:
lastCompletion !== null ? now - lastCompletion : undefined,
}) })
setLastApiCompletionTimestamp(now) setLastApiCompletionTimestamp(now)
@ -365,7 +370,9 @@ async function sideQueryOpenAI(opts: SideQueryOptions): Promise<BetaMessage> {
// Build system prompt // Build system prompt
const systemContent = skipSystemPromptPrefix const systemContent = skipSystemPromptPrefix
? (typeof system === 'string' ? system : '') ? typeof system === 'string'
? system
: ''
: `${getCLISyspromptPrefix({ isNonInteractive: false, hasAppendSystemPrompt: false })} : `${getCLISyspromptPrefix({ isNonInteractive: false, hasAppendSystemPrompt: false })}
${typeof system === 'string' ? system : ''}` ${typeof system === 'string' ? system : ''}`
@ -377,12 +384,9 @@ ${typeof system === 'string' ? system : ''}`
// Convert messages to OpenAI format // Convert messages to OpenAI format
const openaiMessages = anthropicMessagesToOpenAI( const openaiMessages = anthropicMessagesToOpenAI(
messages.map(m => ({ messages as unknown as (UserMessage | AssistantMessage)[],
...m, asSystemPrompt([systemContent]),
content: typeof m.content === 'string' ? m.content : m.content, { enableThinking: false },
})),
systemContent,
{ enableThinking: false }
) )
// Build request // Build request
@ -395,7 +399,7 @@ ${typeof system === 'string' ? system : ''}`
// Add response_format for JSON schema if specified // Add response_format for JSON schema if specified
if (output_format?.type === 'json_schema') { if (output_format?.type === 'json_schema') {
(requestBody as any).response_format = { ;(requestBody as any).response_format = {
type: 'json_schema', type: 'json_schema',
json_schema: { json_schema: {
name: 'response', name: 'response',
@ -429,15 +433,19 @@ ${typeof system === 'string' ? system : ''}`
const now = Date.now() const now = Date.now()
const lastCompletion = getLastApiCompletionTimestamp() const lastCompletion = getLastApiCompletionTimestamp()
logEvent('tengu_api_success', { logEvent('tengu_api_success', {
requestId: response.id as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, requestId:
querySource: opts.querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, response.id as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
model: openaiModel as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, querySource:
opts.querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
model:
openaiModel as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
inputTokens: response.usage?.prompt_tokens || 0, inputTokens: response.usage?.prompt_tokens || 0,
outputTokens: response.usage?.completion_tokens || 0, outputTokens: response.usage?.completion_tokens || 0,
cachedInputTokens: 0, cachedInputTokens: 0,
uncachedInputTokens: 0, uncachedInputTokens: 0,
durationMsIncludingRetries: now - start, durationMsIncludingRetries: now - start,
timeSinceLastApiCallMs: lastCompletion !== null ? now - lastCompletion : undefined, timeSinceLastApiCallMs:
lastCompletion !== null ? now - lastCompletion : undefined,
}) })
setLastApiCompletionTimestamp(now) setLastApiCompletionTimestamp(now)

View File

@ -1,69 +1,46 @@
import chalk from 'chalk' import chalk from 'chalk';
import figures from 'figures' import figures from 'figures';
import * as React from 'react' import * as React from 'react';
import { color, Text } from '@anthropic/ink' import { color, Text } from '@anthropic/ink';
import type { MCPServerConnection } from '../services/mcp/types.js' import type { MCPServerConnection } from '../services/mcp/types.js';
import { getAccountInformation, isClaudeAISubscriber } from './auth.js' import { getAccountInformation, isClaudeAISubscriber } from './auth.js';
import { import { getLargeMemoryFiles, getMemoryFiles, MAX_MEMORY_CHARACTER_COUNT } from './claudemd.js';
getLargeMemoryFiles, import { getDoctorDiagnostic } from './doctorDiagnostic.js';
getMemoryFiles, import { getAWSRegion, getDefaultVertexRegion, isEnvTruthy } from './envUtils.js';
MAX_MEMORY_CHARACTER_COUNT, import { getDisplayPath } from './file.js';
} from './claudemd.js' import { formatNumber } from './format.js';
import { getDoctorDiagnostic } from './doctorDiagnostic.js' import { getIdeClientName, type IDEExtensionInstallationStatus, isJetBrainsIde, toIDEDisplayName } from './ide.js';
import { import { getClaudeAiUserDefaultModelDescription, modelDisplayString } from './model/model.js';
getAWSRegion, import { getAPIProvider } from './model/providers.js';
getDefaultVertexRegion, import { getMTLSConfig } from './mtls.js';
isEnvTruthy, import { checkInstall } from './nativeInstaller/index.js';
} from './envUtils.js' import { getProxyUrl } from './proxy.js';
import { getDisplayPath } from './file.js' import { SandboxManager } from './sandbox/sandbox-adapter.js';
import { formatNumber } from './format.js' import { getSettingsWithAllErrors } from './settings/allErrors.js';
import { import { getEnabledSettingSources, getSettingSourceDisplayNameCapitalized } from './settings/constants.js';
getIdeClientName, import { getManagedFileSettingsPresence, getPolicySettingsOrigin, getSettingsForSource } from './settings/settings.js';
type IDEExtensionInstallationStatus, import type { ThemeName } from './theme.js';
isJetBrainsIde,
toIDEDisplayName,
} from './ide.js'
import {
getClaudeAiUserDefaultModelDescription,
modelDisplayString,
} from './model/model.js'
import { getAPIProvider } from './model/providers.js'
import { getMTLSConfig } from './mtls.js'
import { checkInstall } from './nativeInstaller/index.js'
import { getProxyUrl } from './proxy.js'
import { SandboxManager } from './sandbox/sandbox-adapter.js'
import { getSettingsWithAllErrors } from './settings/allErrors.js'
import {
getEnabledSettingSources,
getSettingSourceDisplayNameCapitalized,
} from './settings/constants.js'
import {
getManagedFileSettingsPresence,
getPolicySettingsOrigin,
getSettingsForSource,
} from './settings/settings.js'
import type { ThemeName } from './theme.js'
export type Property = { export type Property = {
label?: string label?: string;
value: React.ReactNode | Array<string> value: React.ReactNode | Array<string>;
} };
export type Diagnostic = React.ReactNode export type Diagnostic = React.ReactNode;
export function buildSandboxProperties(): Property[] { export function buildSandboxProperties(): Property[] {
if (process.env.USER_TYPE !== 'ant') { if (process.env.USER_TYPE !== 'ant') {
return [] return [];
} }
const isSandboxed = SandboxManager.isSandboxingEnabled() const isSandboxed = SandboxManager.isSandboxingEnabled();
return [ return [
{ {
label: 'Bash Sandbox', label: 'Bash Sandbox',
value: isSandboxed ? 'Enabled' : 'Disabled', value: isSandboxed ? 'Enabled' : 'Disabled',
}, },
] ];
} }
export function buildIDEProperties( export function buildIDEProperties(
@ -71,13 +48,11 @@ export function buildIDEProperties(
ideInstallationStatus: IDEExtensionInstallationStatus | null = null, ideInstallationStatus: IDEExtensionInstallationStatus | null = null,
theme: ThemeName, theme: ThemeName,
): Property[] { ): Property[] {
const ideClient = mcpClients?.find(client => client.name === 'ide') const ideClient = mcpClients?.find(client => client.name === 'ide');
if (ideInstallationStatus) { if (ideInstallationStatus) {
const ideName = toIDEDisplayName(ideInstallationStatus.ideType) const ideName = toIDEDisplayName(ideInstallationStatus.ideType);
const pluginOrExtension = isJetBrainsIde(ideInstallationStatus.ideType) const pluginOrExtension = isJetBrainsIde(ideInstallationStatus.ideType) ? 'plugin' : 'extension';
? 'plugin'
: 'extension'
if (ideInstallationStatus.error) { if (ideInstallationStatus.error) {
return [ return [
@ -85,34 +60,31 @@ export function buildIDEProperties(
label: 'IDE', label: 'IDE',
value: ( value: (
<Text> <Text>
{color('error', theme)(figures.cross)} Error installing {ideName}{' '} {color('error', theme)(figures.cross)} Error installing {ideName} {pluginOrExtension}:{' '}
{pluginOrExtension}: {ideInstallationStatus.error} {ideInstallationStatus.error}
{'\n'}Please restart your IDE and try again. {'\n'}Please restart your IDE and try again.
</Text> </Text>
), ),
}, },
] ];
} }
if (ideInstallationStatus.installed) { if (ideInstallationStatus.installed) {
if (ideClient && ideClient.type === 'connected') { if (ideClient && ideClient.type === 'connected') {
if ( if (ideInstallationStatus.installedVersion !== ideClient.serverInfo?.version) {
ideInstallationStatus.installedVersion !==
ideClient.serverInfo?.version
) {
return [ return [
{ {
label: 'IDE', label: 'IDE',
value: `Connected to ${ideName} ${pluginOrExtension} version ${ideInstallationStatus.installedVersion} (server version: ${ideClient.serverInfo?.version})`, value: `Connected to ${ideName} ${pluginOrExtension} version ${ideInstallationStatus.installedVersion} (server version: ${ideClient.serverInfo?.version})`,
}, },
] ];
} else { } else {
return [ return [
{ {
label: 'IDE', label: 'IDE',
value: `Connected to ${ideName} ${pluginOrExtension} version ${ideInstallationStatus.installedVersion}`, value: `Connected to ${ideName} ${pluginOrExtension} version ${ideInstallationStatus.installedVersion}`,
}, },
] ];
} }
} else { } else {
return [ return [
@ -120,196 +92,183 @@ export function buildIDEProperties(
label: 'IDE', label: 'IDE',
value: `Installed ${ideName} ${pluginOrExtension}`, value: `Installed ${ideName} ${pluginOrExtension}`,
}, },
] ];
} }
} }
} else if (ideClient) { } else if (ideClient) {
const ideName = getIdeClientName(ideClient) ?? 'IDE' const ideName = getIdeClientName(ideClient) ?? 'IDE';
if (ideClient.type === 'connected') { if (ideClient.type === 'connected') {
return [ return [
{ {
label: 'IDE', label: 'IDE',
value: `Connected to ${ideName} extension`, value: `Connected to ${ideName} extension`,
}, },
] ];
} else { } else {
return [ return [
{ {
label: 'IDE', label: 'IDE',
value: `${color('error', theme)(figures.cross)} Not connected to ${ideName}`, value: `${color('error', theme)(figures.cross)} Not connected to ${ideName}`,
}, },
] ];
} }
} }
return [] return [];
} }
export function buildMcpProperties( export function buildMcpProperties(clients: MCPServerConnection[] = [], theme: ThemeName): Property[] {
clients: MCPServerConnection[] = [], const servers = clients.filter(client => client.name !== 'ide');
theme: ThemeName,
): Property[] {
const servers = clients.filter(client => client.name !== 'ide')
if (!servers.length) { if (!servers.length) {
return [] return [];
} }
// Summary instead of a full server list — 20+ servers wrapped onto many // Summary instead of a full server list — 20+ servers wrapped onto many
// rows, dominating the Status pane. Show counts by state + /mcp hint. // rows, dominating the Status pane. Show counts by state + /mcp hint.
const byState = { connected: 0, pending: 0, needsAuth: 0, failed: 0 } const byState = { connected: 0, pending: 0, needsAuth: 0, failed: 0 };
for (const s of servers) { for (const s of servers) {
if (s.type === 'connected') byState.connected++ if (s.type === 'connected') byState.connected++;
else if (s.type === 'pending') byState.pending++ else if (s.type === 'pending') byState.pending++;
else if (s.type === 'needs-auth') byState.needsAuth++ else if (s.type === 'needs-auth') byState.needsAuth++;
else byState.failed++ else byState.failed++;
} }
const parts: string[] = [] const parts: string[] = [];
if (byState.connected) if (byState.connected) parts.push(color('success', theme)(`${byState.connected} connected`));
parts.push(color('success', theme)(`${byState.connected} connected`)) if (byState.needsAuth) parts.push(color('warning', theme)(`${byState.needsAuth} need auth`));
if (byState.needsAuth) if (byState.pending) parts.push(color('inactive', theme)(`${byState.pending} pending`));
parts.push(color('warning', theme)(`${byState.needsAuth} need auth`)) if (byState.failed) parts.push(color('error', theme)(`${byState.failed} failed`));
if (byState.pending)
parts.push(color('inactive', theme)(`${byState.pending} pending`))
if (byState.failed)
parts.push(color('error', theme)(`${byState.failed} failed`))
return [ return [
{ {
label: 'MCP servers', label: 'MCP servers',
value: `${parts.join(', ')} ${color('inactive', theme)('· /mcp')}`, value: `${parts.join(', ')} ${color('inactive', theme)('· /mcp')}`,
}, },
] ];
} }
export async function buildMemoryDiagnostics(): Promise<Diagnostic[]> { export async function buildMemoryDiagnostics(): Promise<Diagnostic[]> {
const files = await getMemoryFiles() const files = await getMemoryFiles();
const largeFiles = getLargeMemoryFiles(files) const largeFiles = getLargeMemoryFiles(files);
const diagnostics: Diagnostic[] = [] const diagnostics: Diagnostic[] = [];
largeFiles.forEach(file => { largeFiles.forEach(file => {
const displayPath = getDisplayPath(file.path) const displayPath = getDisplayPath(file.path);
diagnostics.push( diagnostics.push(
`Large ${displayPath} will impact performance (${formatNumber(file.content.length)} chars > ${formatNumber(MAX_MEMORY_CHARACTER_COUNT)})`, `Large ${displayPath} will impact performance (${formatNumber(file.content.length)} chars > ${formatNumber(MAX_MEMORY_CHARACTER_COUNT)})`,
) );
}) });
return diagnostics return diagnostics;
} }
export function buildSettingSourcesProperties(): Property[] { export function buildSettingSourcesProperties(): Property[] {
const enabledSources = getEnabledSettingSources() const enabledSources = getEnabledSettingSources();
// Filter to only sources that actually have settings loaded // Filter to only sources that actually have settings loaded
const sourcesWithSettings = enabledSources.filter(source => { const sourcesWithSettings = enabledSources.filter(source => {
const settings = getSettingsForSource(source) const settings = getSettingsForSource(source);
return settings !== null && Object.keys(settings).length > 0 return settings !== null && Object.keys(settings).length > 0;
}) });
// Map internal names to user-friendly names // Map internal names to user-friendly names
// For policySettings, distinguish between remote and local (or skip if neither exists) // For policySettings, distinguish between remote and local (or skip if neither exists)
const sourceNames = sourcesWithSettings const sourceNames = sourcesWithSettings
.map(source => { .map(source => {
if (source === 'policySettings') { if (source === 'policySettings') {
const origin = getPolicySettingsOrigin() const origin = getPolicySettingsOrigin();
if (origin === null) { if (origin === null) {
return null // Skip - no policy settings exist return null; // Skip - no policy settings exist
} }
switch (origin) { switch (origin) {
case 'remote': case 'remote':
return 'Enterprise managed settings (remote)' return 'Enterprise managed settings (remote)';
case 'plist': case 'plist':
return 'Enterprise managed settings (plist)' return 'Enterprise managed settings (plist)';
case 'hklm': case 'hklm':
return 'Enterprise managed settings (HKLM)' return 'Enterprise managed settings (HKLM)';
case 'file': { case 'file': {
const { hasBase, hasDropIns } = getManagedFileSettingsPresence() const { hasBase, hasDropIns } = getManagedFileSettingsPresence();
if (hasBase && hasDropIns) { if (hasBase && hasDropIns) {
return 'Enterprise managed settings (file + drop-ins)' return 'Enterprise managed settings (file + drop-ins)';
} }
if (hasDropIns) { if (hasDropIns) {
return 'Enterprise managed settings (drop-ins)' return 'Enterprise managed settings (drop-ins)';
} }
return 'Enterprise managed settings (file)' return 'Enterprise managed settings (file)';
} }
case 'hkcu': case 'hkcu':
return 'Enterprise managed settings (HKCU)' return 'Enterprise managed settings (HKCU)';
} }
} }
return getSettingSourceDisplayNameCapitalized(source) return getSettingSourceDisplayNameCapitalized(source);
}) })
.filter((name): name is string => name !== null) .filter((name): name is string => name !== null);
return [ return [
{ {
label: 'Setting sources', label: 'Setting sources',
value: sourceNames, value: sourceNames,
}, },
] ];
} }
export async function buildInstallationDiagnostics(): Promise<Diagnostic[]> { export async function buildInstallationDiagnostics(): Promise<Diagnostic[]> {
const installWarnings = await checkInstall() const installWarnings = await checkInstall();
return installWarnings.map(warning => warning.message) return installWarnings.map(warning => warning.message);
} }
export async function buildInstallationHealthDiagnostics(): Promise< export async function buildInstallationHealthDiagnostics(): Promise<Diagnostic[]> {
Diagnostic[] const diagnostic = await getDoctorDiagnostic();
> { const items: Diagnostic[] = [];
const diagnostic = await getDoctorDiagnostic()
const items: Diagnostic[] = []
const { errors: validationErrors } = getSettingsWithAllErrors() const { errors: validationErrors } = getSettingsWithAllErrors();
if (validationErrors.length > 0) { if (validationErrors.length > 0) {
const invalidFiles = Array.from( const invalidFiles = Array.from(new Set(validationErrors.map(error => error.file)));
new Set(validationErrors.map(error => error.file)), const fileList = invalidFiles.join(', ');
)
const fileList = invalidFiles.join(', ')
items.push( items.push(`Found invalid settings files: ${fileList}. They will be ignored.`);
`Found invalid settings files: ${fileList}. They will be ignored.`,
)
} }
// Add warnings from doctor diagnostic (includes leftover installations, config mismatches, etc.) // Add warnings from doctor diagnostic (includes leftover installations, config mismatches, etc.)
diagnostic.warnings.forEach(warning => { diagnostic.warnings.forEach(warning => {
items.push(warning.issue) items.push(warning.issue);
}) });
if (diagnostic.hasUpdatePermissions === false) { if (diagnostic.hasUpdatePermissions === false) {
items.push('No write permissions for auto-updates (requires sudo)') items.push('No write permissions for auto-updates (requires sudo)');
} }
return items return items;
} }
export function buildAccountProperties(): Property[] { export function buildAccountProperties(): Property[] {
const accountInfo = getAccountInformation() const accountInfo = getAccountInformation();
if (!accountInfo) { if (!accountInfo) {
return [] return [];
} }
const properties: Property[] = [] const properties: Property[] = [];
if (accountInfo.subscription) { if (accountInfo.subscription) {
properties.push({ properties.push({
label: 'Login method', label: 'Login method',
value: `${accountInfo.subscription} Account`, value: `${accountInfo.subscription} Account`,
}) });
} }
if (accountInfo.tokenSource) { if (accountInfo.tokenSource) {
properties.push({ properties.push({
label: 'Auth token', label: 'Auth token',
value: accountInfo.tokenSource, value: accountInfo.tokenSource,
}) });
} }
if (accountInfo.apiKeySource) { if (accountInfo.apiKeySource) {
properties.push({ properties.push({
label: 'API key', label: 'API key',
value: accountInfo.apiKeySource, value: accountInfo.apiKeySource,
}) });
} }
// Hide sensitive account info in demo mode // Hide sensitive account info in demo mode
@ -317,22 +276,22 @@ export function buildAccountProperties(): Property[] {
properties.push({ properties.push({
label: 'Organization', label: 'Organization',
value: accountInfo.organization, value: accountInfo.organization,
}) });
} }
if (accountInfo.email && !process.env.IS_DEMO) { if (accountInfo.email && !process.env.IS_DEMO) {
properties.push({ properties.push({
label: 'Email', label: 'Email',
value: accountInfo.email, value: accountInfo.email,
}) });
} }
return properties return properties;
} }
export function buildAPIProviderProperties(): Property[] { export function buildAPIProviderProperties(): Property[] {
const apiProvider = getAPIProvider() const apiProvider = getAPIProvider();
const properties: Property[] = [] const properties: Property[] = [];
if (apiProvider !== 'firstParty') { if (apiProvider !== 'firstParty') {
const providerLabel = { const providerLabel = {
@ -342,152 +301,152 @@ export function buildAPIProviderProperties(): Property[] {
gemini: 'Gemini API', gemini: 'Gemini API',
grok: 'Grok API', grok: 'Grok API',
openai: 'OpenAI API', openai: 'OpenAI API',
}[apiProvider] costrict: 'CoStrict API',
}[apiProvider];
properties.push({ properties.push({
label: 'API provider', label: 'API provider',
value: providerLabel, value: providerLabel,
}) });
} }
if (apiProvider === 'firstParty') { if (apiProvider === 'firstParty') {
const anthropicBaseUrl = process.env.ANTHROPIC_BASE_URL const anthropicBaseUrl = process.env.ANTHROPIC_BASE_URL;
if (anthropicBaseUrl) { if (anthropicBaseUrl) {
properties.push({ properties.push({
label: 'Anthropic base URL', label: 'Anthropic base URL',
value: anthropicBaseUrl, value: anthropicBaseUrl,
}) });
} }
} else if (apiProvider === 'bedrock') { } else if (apiProvider === 'bedrock') {
const bedrockBaseUrl = process.env.BEDROCK_BASE_URL const bedrockBaseUrl = process.env.BEDROCK_BASE_URL;
if (bedrockBaseUrl) { if (bedrockBaseUrl) {
properties.push({ properties.push({
label: 'Bedrock base URL', label: 'Bedrock base URL',
value: bedrockBaseUrl, value: bedrockBaseUrl,
}) });
} }
properties.push({ properties.push({
label: 'AWS region', label: 'AWS region',
value: getAWSRegion(), value: getAWSRegion(),
}) });
if (isEnvTruthy(process.env.CLAUDE_CODE_SKIP_BEDROCK_AUTH)) { if (isEnvTruthy(process.env.CLAUDE_CODE_SKIP_BEDROCK_AUTH)) {
properties.push({ properties.push({
value: 'AWS auth skipped', value: 'AWS auth skipped',
}) });
} }
} else if (apiProvider === 'vertex') { } else if (apiProvider === 'vertex') {
const vertexBaseUrl = process.env.VERTEX_BASE_URL const vertexBaseUrl = process.env.VERTEX_BASE_URL;
if (vertexBaseUrl) { if (vertexBaseUrl) {
properties.push({ properties.push({
label: 'Vertex base URL', label: 'Vertex base URL',
value: vertexBaseUrl, value: vertexBaseUrl,
}) });
} }
const gcpProject = process.env.ANTHROPIC_VERTEX_PROJECT_ID const gcpProject = process.env.ANTHROPIC_VERTEX_PROJECT_ID;
if (gcpProject) { if (gcpProject) {
properties.push({ properties.push({
label: 'GCP project', label: 'GCP project',
value: gcpProject, value: gcpProject,
}) });
} }
properties.push({ properties.push({
label: 'Default region', label: 'Default region',
value: getDefaultVertexRegion(), value: getDefaultVertexRegion(),
}) });
if (isEnvTruthy(process.env.CLAUDE_CODE_SKIP_VERTEX_AUTH)) { if (isEnvTruthy(process.env.CLAUDE_CODE_SKIP_VERTEX_AUTH)) {
properties.push({ properties.push({
value: 'GCP auth skipped', value: 'GCP auth skipped',
}) });
} }
} else if (apiProvider === 'foundry') { } else if (apiProvider === 'foundry') {
const foundryBaseUrl = process.env.ANTHROPIC_FOUNDRY_BASE_URL const foundryBaseUrl = process.env.ANTHROPIC_FOUNDRY_BASE_URL;
if (foundryBaseUrl) { if (foundryBaseUrl) {
properties.push({ properties.push({
label: 'Microsoft Foundry base URL', label: 'Microsoft Foundry base URL',
value: foundryBaseUrl, value: foundryBaseUrl,
}) });
} }
const foundryResource = process.env.ANTHROPIC_FOUNDRY_RESOURCE const foundryResource = process.env.ANTHROPIC_FOUNDRY_RESOURCE;
if (foundryResource) { if (foundryResource) {
properties.push({ properties.push({
label: 'Microsoft Foundry resource', label: 'Microsoft Foundry resource',
value: foundryResource, value: foundryResource,
}) });
} }
if (isEnvTruthy(process.env.CLAUDE_CODE_SKIP_FOUNDRY_AUTH)) { if (isEnvTruthy(process.env.CLAUDE_CODE_SKIP_FOUNDRY_AUTH)) {
properties.push({ properties.push({
value: 'Microsoft Foundry auth skipped', value: 'Microsoft Foundry auth skipped',
}) });
} }
} else if (apiProvider === 'gemini') { } else if (apiProvider === 'gemini') {
const geminiBaseUrl = const geminiBaseUrl = process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta';
process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta'
properties.push({ properties.push({
label: 'Gemini base URL', label: 'Gemini base URL',
value: geminiBaseUrl, value: geminiBaseUrl,
}) });
} else if (apiProvider === 'grok') { } else if (apiProvider === 'grok') {
const grokBaseUrl = process.env.GROK_BASE_URL const grokBaseUrl = process.env.GROK_BASE_URL;
properties.push({ properties.push({
label: 'Grok base URL', label: 'Grok base URL',
value: grokBaseUrl, value: grokBaseUrl,
}) });
} else if (apiProvider === 'openai') { } else if (apiProvider === 'openai') {
const openaiBaseUrl = process.env.OPENAI_BASE_URL const openaiBaseUrl = process.env.OPENAI_BASE_URL;
properties.push({ properties.push({
label: 'OpenAI base URL', label: 'OpenAI base URL',
value: openaiBaseUrl, value: openaiBaseUrl,
}) });
} }
const proxyUrl = getProxyUrl() const proxyUrl = getProxyUrl();
if (proxyUrl) { if (proxyUrl) {
properties.push({ properties.push({
label: 'Proxy', label: 'Proxy',
value: proxyUrl, value: proxyUrl,
}) });
} }
const mtlsConfig = getMTLSConfig() const mtlsConfig = getMTLSConfig();
if (process.env.NODE_EXTRA_CA_CERTS) { if (process.env.NODE_EXTRA_CA_CERTS) {
properties.push({ properties.push({
label: 'Additional CA cert(s)', label: 'Additional CA cert(s)',
value: process.env.NODE_EXTRA_CA_CERTS, value: process.env.NODE_EXTRA_CA_CERTS,
}) });
} }
if (mtlsConfig) { if (mtlsConfig) {
if (mtlsConfig.cert && process.env.CLAUDE_CODE_CLIENT_CERT) { if (mtlsConfig.cert && process.env.CLAUDE_CODE_CLIENT_CERT) {
properties.push({ properties.push({
label: 'mTLS client cert', label: 'mTLS client cert',
value: process.env.CLAUDE_CODE_CLIENT_CERT, value: process.env.CLAUDE_CODE_CLIENT_CERT,
}) });
} }
if (mtlsConfig.key && process.env.CLAUDE_CODE_CLIENT_KEY) { if (mtlsConfig.key && process.env.CLAUDE_CODE_CLIENT_KEY) {
properties.push({ properties.push({
label: 'mTLS client key', label: 'mTLS client key',
value: process.env.CLAUDE_CODE_CLIENT_KEY, value: process.env.CLAUDE_CODE_CLIENT_KEY,
}) });
} }
} }
return properties return properties;
} }
export function getModelDisplayLabel(mainLoopModel: string | null): string { export function getModelDisplayLabel(mainLoopModel: string | null): string {
let modelLabel = modelDisplayString(mainLoopModel) let modelLabel = modelDisplayString(mainLoopModel);
if (mainLoopModel === null && isClaudeAISubscriber()) { if (mainLoopModel === null && isClaudeAISubscriber()) {
const description = getClaudeAiUserDefaultModelDescription() const description = getClaudeAiUserDefaultModelDescription();
modelLabel = `${chalk.bold('Default')} ${description}` modelLabel = `${chalk.bold('Default')} ${description}`;
} }
return modelLabel return modelLabel;
} }