mirror of
https://github.com/cline/cline.git
synced 2026-09-21 13:21:23 +08:00
* style(docs): update background color scheme to neutral tones Update documentation background colors from purple-tinted theme to neutral gray tones. Changed light mode from lavender (#F0E6FF) to off-white (#fafaf9) and dark mode from pure black (#000000) to dark gray (#0f0f0f) for improved visual consistency. * refactor(docs): remove gradient decoration from theme config Remove the "decoration": "gradient" property from the documentation theme configuration. This simplifies the theme settings by removing the gradient decoration option from the color configuration object. * docs: change documentation font family to Geist Mono Replace Roboto with Geist Mono as the default font family in the documentation configuration. This updates the visual styling of the documentation to use a monospace font, which may improve readability for code-heavy content. * docs: update branding and restructure navigation - Replace robot panel logos with new Cline brand logos - Add icons to navbar links (Docs, GitHub, Discord) - Restructure navigation from groups to tabs format - Add icons to navigation items for improved UX - Include new Docs link in navbar with book icon This update modernizes the documentation appearance and improves navigation hierarchy for better user experience. * docs: restructure navigation with hierarchical groups and pages Restructured documentation navigation from flat menu to organized groups: - Removed redundant "Docs" link from navbar - Migrated from "menu" to "groups/pages" structure - Added comprehensive page organization with nested groups: * Introduction, Getting Started, Features * Prompting Skills, Cline's Tools, Enterprise Solutions * MCP Servers, Provider Configuration - Organized features into logical subgroups (@ Mentions, Commands, Customization, Slash Commands) - Improved documentation discoverability and hierarchy This change provides better content organization and easier navigation for users exploring different aspects of Cline documentation. * docs: remove contextual options from documentation config Remove the contextual configuration section containing the "copy" option from docs.json. This simplifies the documentation configuration by removing unused contextual menu options. * docs(multiroot): improve workspace documentation with limitations and technical details - Add important note about experimental limitations affecting Cline rules and checkpoints - Add "How it works" section explaining automatic workspace detection and tracking - Reorganize technical behavior section with detailed subsections for workspace detection, path resolution, and command execution - Document workspace hint syntax for explicit file references (@workspaceName:path) - Standardize heading capitalization to sentence case for consistency - Improve overall content organization and clarity for better user understanding This update provides users with clearer information about the multiroot feature's current state, its limitations, and how to effectively use workspace hints when working with multiple project folders. * docs: restructure overview page with enhanced visual layout - Convert plain markdown sections to CardGroup and Card components with icons - Add tabbed interface for Plan & Act Mode explanation - Update description from "development assistant" to "coding agent" - Reorganize content for improved readability and visual hierarchy - Enhance feature presentations with icon-based cards Improves user experience by transforming the overview documentation into a more visually appealing and scannable format using modern documentation components. * docs: improve installation guide with enhanced structure and UX Restructure the Cline installation documentation to improve readability and user experience: - Add prominent note highlighting 2-minute installation time - Convert prerequisites into visual card components for better clarity - Transform installation steps into structured Step components for easier following - Add manual installation instructions for JetBrains IDEs - Include feature compatibility accordion for JetBrains users - Enhance visual hierarchy with improved component usage (CardGroup, Steps, Accordion) - Simplify language and improve descriptions throughout This makes the installation process clearer for new users and reduces friction during onboarding. * style(docs): remove text opacity reduction for better readability * docs: refactor model selection guide with visual step-by-step instructions - Replace tab-based layout with linear step-by-step flow - Add screenshots for each configuration step (config, provider, API, model) - Reorganize content structure for improved clarity and user experience - Add quickstart options and streamlined provider recommendations - Improve navigation with visual aids to help users configure Cline faster * docs: add installation screenshots and context management guide * docs: flatten provider config structure in documentation Remove the "Alternative Providers" grouping and move all provider configuration pages (OpenRouter, Cerebras, DeepSeek, Groq, xAI Grok, Mistral AI, Doubao, Fireworks, and ZAI) to the main provider configuration list. This simplifies the documentation navigation by treating all providers equally rather than categorizing some as alternatives. * docs: restructure context management docs and improve content clarity **Changes:** - Reorganized documentation structure by moving context management from `/best-practices` to `/prompting` section for better categorization - Added URL redirect to maintain backward compatibility for old links - Updated navigation references in welcome page to point to new location - Improved readability of context management explanations with more narrative, conversational prose - Enhanced context window documentation by adding cache tokens indicator and using emoji-based formatting for better visual clarity - Streamlined Cline Memory Bank setup instructions from 4 to 3 steps - Updated context bar screenshot to use newer image asset **Why:** Better documentation organization and improved user experience through clearer explanations of how Cline builds and manages context during tasks. * docs(context-management): convert Quick Reference to Info component Replace blockquote formatting with Info component for the Quick Reference section in the context management documentation. This improves visual presentation and maintains consistency with documentation standards. Also removes trailing whitespace at the end of the file for cleaner formatting. * docs: add Cline Enterprise overview and restructure enterprise section - Add comprehensive enterprise overview documentation covering security, governance, observability, and developer experience features - Rename "Enterprise & Security" navigation group to "Enterprise" - Consolidate enterprise documentation by replacing 4 pages with 2: new overview page and security concerns - Document BYOI (Bring Your Own Inference), SSO authentication, and role-based access control capabilities This restructuring provides a clearer entry point for enterprise users and consolidates previously scattered enterprise information into a cohesive overview document. * docs(enterprise): streamline enterprise overview and update font - Change documentation font from Geist Mono to Geist Sans - Add enterprise website link card for detailed information - Remove Developer Experience, Proven at Scale, and Pricing sections - Consolidate Flexible Inference section content - Simplify enterprise overview to focus on core capabilities These changes reduce redundancy by directing users to the enterprise website for pricing and detailed features while keeping the docs focused on technical implementation and core capabilities. * clean-images * Update docs/getting-started/installing-cline.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs/styles.css Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * docs(cline-cli): add platform availability warning to overview Add a prominent warning callout indicating that Cline CLI is currently in preview and only supports macOS and Linux, with Windows support coming soon. This sets clear expectations for users about platform compatibility. Also remove redundant introductory text in the "What you can build with this" section to improve content clarity. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
700 lines
21 KiB
JavaScript
Executable File
700 lines
21 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import archiver from "archiver"
|
|
import { execSync } from "child_process"
|
|
import fs from "fs"
|
|
import { cp } from "fs/promises"
|
|
import { glob } from "glob"
|
|
import minimatch from "minimatch"
|
|
import os from "os"
|
|
import path from "path"
|
|
import { rmrf } from "./file-utils.mjs"
|
|
|
|
const BUILD_DIR = "dist-standalone"
|
|
const BINARIES_DIR = `${BUILD_DIR}/binaries`
|
|
const RUNTIME_DEPS_DIR = "standalone/runtime-files"
|
|
const RIPGREP_BINARIES_DIR = `${BUILD_DIR}/ripgrep-binaries`
|
|
const CLI_BINARIES_DIR = "cli/bin"
|
|
const IS_DEBUG_BUILD = process.env.IS_DEBUG_BUILD === "true"
|
|
|
|
// This should match the node version packaged with the JetBrains plugin.
|
|
const TARGET_NODE_VERSION = "22.15.0"
|
|
const TARGET_PLATFORMS = [
|
|
{ platform: "win32", arch: "x64", targetDir: "win-x64" },
|
|
{ platform: "darwin", arch: "x64", targetDir: "darwin-x64" },
|
|
{ platform: "darwin", arch: "arm64", targetDir: "darwin-arm64" },
|
|
{ platform: "linux", arch: "x64", targetDir: "linux-x64" },
|
|
]
|
|
const SUPPORTED_BINARY_MODULES = ["better-sqlite3"]
|
|
|
|
const UNIVERSAL_BUILD = !process.argv.includes("-s")
|
|
const IS_VERBOSE = process.argv.includes("-v") || process.argv.includes("--verbose")
|
|
|
|
// Parse --target flag (e.g., --target=npm)
|
|
// Default behavior is JetBrains build (no binaries)
|
|
// Use --target=npm for npm package build (CLI binaries but no Node.js)
|
|
const targetArg = process.argv.find((arg) => arg.startsWith("--target="))
|
|
const BUILD_TARGET = targetArg ? targetArg.split("=")[1] : "jetbrains"
|
|
const IS_NPM_BUILD = BUILD_TARGET === "npm"
|
|
|
|
// Detect current platform
|
|
function getCurrentPlatform() {
|
|
const platform = os.platform()
|
|
const arch = os.arch()
|
|
|
|
if (platform === "darwin") {
|
|
return arch === "arm64" ? "darwin-arm64" : "darwin-x64"
|
|
} else if (platform === "linux") {
|
|
return "linux-x64"
|
|
} else if (platform === "win32") {
|
|
return "win-x64"
|
|
}
|
|
throw new Error(`Unsupported platform: ${platform}-${arch}`)
|
|
}
|
|
|
|
async function main() {
|
|
const buildType = IS_NPM_BUILD ? "NPM Package" : "JetBrains"
|
|
console.log(`🚀 Building Cline ${buildType} Package\n`)
|
|
|
|
await installNodeDependencies()
|
|
|
|
if (IS_NPM_BUILD) {
|
|
await copyCliBinaries()
|
|
await copyRipgrepBinary()
|
|
await copyProtoDescriptors()
|
|
await createNpmPackageFiles()
|
|
await createFakeNodeModules()
|
|
await createNpmIgnoreFile()
|
|
await createPostinstallScript()
|
|
}
|
|
|
|
if (UNIVERSAL_BUILD && !IS_NPM_BUILD) {
|
|
console.log("\nBuilding universal package for all platforms...")
|
|
await packageAllBinaryDeps()
|
|
} else if (IS_NPM_BUILD) {
|
|
console.log("\nNPM build: Keeping native modules in node_modules for npm to handle...")
|
|
} else {
|
|
console.log(`\nBuilding package for ${os.platform()}-${os.arch()}...`)
|
|
}
|
|
|
|
if (!IS_NPM_BUILD) {
|
|
console.log("\n📦 Creating final package...")
|
|
await zipDistribution()
|
|
}
|
|
|
|
console.log("\n✅ Build complete!")
|
|
if (IS_NPM_BUILD) {
|
|
console.log(`\n📦 NPM package ready in ${BUILD_DIR}/`)
|
|
console.log(`To publish: cd ${BUILD_DIR} && npm publish`)
|
|
}
|
|
}
|
|
|
|
async function installNodeDependencies() {
|
|
// Clean modules from any previous builds
|
|
await rmrf(path.join(BUILD_DIR, "node_modules"))
|
|
await rmrf(path.join(BINARIES_DIR))
|
|
|
|
await cpr(RUNTIME_DEPS_DIR, BUILD_DIR)
|
|
|
|
console.log("Running npm install in distribution directory...")
|
|
execSync("npm install", { stdio: "inherit", cwd: BUILD_DIR })
|
|
|
|
// Move the vscode directory into node_modules.
|
|
// It can't be installed using npm because it will create a symlink which cannot be unzipped correctly on windows.
|
|
fs.renameSync(`${BUILD_DIR}/vscode`, `${BUILD_DIR}/node_modules/vscode`)
|
|
}
|
|
|
|
/**
|
|
* Copy CLI binaries (cline and cline-host) for all platforms
|
|
* The Go binaries are cross-compiled for darwin/linux arm64/amd64
|
|
*/
|
|
async function copyCliBinaries() {
|
|
console.log("Copying CLI binaries for all platforms...")
|
|
|
|
const platforms = [
|
|
{ os: "darwin", arch: "arm64" },
|
|
{ os: "darwin", arch: "amd64" },
|
|
{ os: "linux", arch: "amd64" },
|
|
{ os: "linux", arch: "arm64" },
|
|
]
|
|
|
|
const binDir = path.join(BUILD_DIR, "bin")
|
|
|
|
// Create bin directory
|
|
fs.mkdirSync(binDir, { recursive: true })
|
|
|
|
// Copy all platform-specific binaries
|
|
for (const { os, arch } of platforms) {
|
|
const platformSuffix = `${os}-${arch}`
|
|
|
|
// Copy cline binary
|
|
const clineSource = path.join(CLI_BINARIES_DIR, `cline-${platformSuffix}`)
|
|
const clineDest = path.join(binDir, `cline-${platformSuffix}`)
|
|
|
|
if (!fs.existsSync(clineSource)) {
|
|
console.error(`Error: CLI binary not found at ${clineSource}`)
|
|
console.error(`Please run: npm run compile-cli`)
|
|
process.exit(1)
|
|
}
|
|
|
|
await cpr(clineSource, clineDest)
|
|
fs.chmodSync(clineDest, 0o755)
|
|
console.log(`✓ cline-${platformSuffix} copied`)
|
|
|
|
// Copy cline-host binary
|
|
const hostSource = path.join(CLI_BINARIES_DIR, `cline-host-${platformSuffix}`)
|
|
const hostDest = path.join(binDir, `cline-host-${platformSuffix}`)
|
|
|
|
if (!fs.existsSync(hostSource)) {
|
|
console.error(`Error: CLI binary not found at ${hostSource}`)
|
|
console.error(`Please run: npm run compile-cli`)
|
|
process.exit(1)
|
|
}
|
|
|
|
await cpr(hostSource, hostDest)
|
|
fs.chmodSync(hostDest, 0o755)
|
|
console.log(`✓ cline-host-${platformSuffix} copied`)
|
|
}
|
|
|
|
console.log(`✓ All platform binaries copied to ${binDir}`)
|
|
}
|
|
|
|
/**
|
|
* Copy proto descriptors directory
|
|
* The proto/descriptor_set.pb file is needed by cline-core for gRPC reflection
|
|
*/
|
|
async function copyProtoDescriptors() {
|
|
console.log("Copying proto descriptors...")
|
|
|
|
const protoSource = "proto"
|
|
const protoDest = path.join(BUILD_DIR, "proto")
|
|
|
|
// Check if proto directory exists
|
|
if (!fs.existsSync(protoSource)) {
|
|
console.error(`Error: proto directory not found at ${protoSource}`)
|
|
console.error(`Please ensure the proto files have been generated`)
|
|
process.exit(1)
|
|
}
|
|
|
|
// Check if descriptor_set.pb exists
|
|
const descriptorPath = path.join(protoSource, "descriptor_set.pb")
|
|
if (!fs.existsSync(descriptorPath)) {
|
|
console.error(`Error: proto/descriptor_set.pb not found at ${descriptorPath}`)
|
|
console.error(`Please run: npm run protos`)
|
|
process.exit(1)
|
|
}
|
|
|
|
// Copy the entire proto directory
|
|
await cpr(protoSource, protoDest)
|
|
|
|
console.log(`✓ Proto descriptors copied to ${protoDest}`)
|
|
}
|
|
|
|
/**
|
|
* Copy ripgrep binary for the current platform
|
|
* Ripgrep is needed by cline-core for file searching
|
|
*/
|
|
async function copyRipgrepBinary() {
|
|
const currentPlatform = getCurrentPlatform()
|
|
const binaryName = currentPlatform.startsWith("win") ? "rg.exe" : "rg"
|
|
const ripgrepBinarySource = path.join(RIPGREP_BINARIES_DIR, currentPlatform, binaryName)
|
|
const ripgrepBinaryDest = path.join(BUILD_DIR, binaryName)
|
|
|
|
console.log(`Copying ripgrep binary for ${currentPlatform}...`)
|
|
|
|
// Check if ripgrep binaries exist, download if missing
|
|
if (!fs.existsSync(ripgrepBinarySource)) {
|
|
console.log(`Ripgrep binary not found, downloading...`)
|
|
try {
|
|
execSync("npm run download-ripgrep", { stdio: "inherit" })
|
|
} catch (error) {
|
|
console.error(`Error downloading ripgrep: ${error.message}`)
|
|
console.error(`Please run: npm run download-ripgrep`)
|
|
process.exit(1)
|
|
}
|
|
|
|
// Check again after download
|
|
if (!fs.existsSync(ripgrepBinarySource)) {
|
|
console.error(`Error: Ripgrep binary still not found at ${ripgrepBinarySource}`)
|
|
console.error(`Download may have failed. Please run: npm run download-ripgrep`)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
// Copy ripgrep binary to the root of dist-standalone (where cline-core.js is)
|
|
await cpr(ripgrepBinarySource, ripgrepBinaryDest)
|
|
|
|
// Make it executable (Unix only)
|
|
if (!currentPlatform.startsWith("win")) {
|
|
fs.chmodSync(ripgrepBinaryDest, 0o755)
|
|
}
|
|
|
|
console.log(`✓ Ripgrep binary copied to ${ripgrepBinaryDest}`)
|
|
}
|
|
|
|
/**
|
|
* Create a VERSION file with build metadata
|
|
*/
|
|
async function createVersionFile() {
|
|
const packageJson = JSON.parse(fs.readFileSync("package.json", "utf8"))
|
|
const version = packageJson.version
|
|
const platform = getCurrentPlatform()
|
|
const buildDate = new Date().toISOString()
|
|
|
|
const versionInfo = {
|
|
version,
|
|
platform,
|
|
buildDate,
|
|
nodeVersion: TARGET_NODE_VERSION,
|
|
}
|
|
|
|
const versionPath = path.join(BUILD_DIR, "VERSION.txt")
|
|
fs.writeFileSync(versionPath, JSON.stringify(versionInfo, null, 2))
|
|
|
|
console.log(`✓ VERSION file created: ${version} (${platform})`)
|
|
}
|
|
|
|
/**
|
|
* Copy NPM package files (package.json, README.md, and man page) from cli/ directory
|
|
*/
|
|
async function createNpmPackageFiles() {
|
|
console.log("Copying NPM package files...")
|
|
|
|
// Copy package.json from cli/ directory
|
|
const packageJsonSource = path.join("cli", "package.json")
|
|
const packageJsonDest = path.join(BUILD_DIR, "package.json")
|
|
|
|
if (!fs.existsSync(packageJsonSource)) {
|
|
console.error(`Error: NPM package.json not found at ${packageJsonSource}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
await cpr(packageJsonSource, packageJsonDest)
|
|
console.log(`✓ package.json copied from ${packageJsonSource}`)
|
|
|
|
// Copy README.md from cli/ directory
|
|
const readmeSource = path.join("cli", "README.md")
|
|
const readmeDest = path.join(BUILD_DIR, "README.md")
|
|
|
|
if (!fs.existsSync(readmeSource)) {
|
|
console.error(`Error: NPM README.md not found at ${readmeSource}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
await cpr(readmeSource, readmeDest)
|
|
console.log(`✓ README.md copied from ${readmeSource}`)
|
|
|
|
// Copy man page from cli/man/ directory
|
|
const manPageSource = path.join("cli", "man", "cline.1")
|
|
const manDir = path.join(BUILD_DIR, "man")
|
|
const manPageDest = path.join(manDir, "cline.1")
|
|
|
|
if (!fs.existsSync(manPageSource)) {
|
|
console.error(`Error: Man page not found at ${manPageSource}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
// Create man directory if it doesn't exist
|
|
fs.mkdirSync(manDir, { recursive: true })
|
|
|
|
await cpr(manPageSource, manPageDest)
|
|
console.log(`✓ Man page copied from ${manPageSource}`)
|
|
}
|
|
|
|
/**
|
|
* Create fake_node_modules directory with vscode stub
|
|
* This directory will be added to NODE_PATH so Node.js can find the vscode module
|
|
* without npm interfering with the real node_modules directory
|
|
*/
|
|
async function createFakeNodeModules() {
|
|
console.log("Creating fake_node_modules with vscode stub...")
|
|
|
|
const vscodeSource = path.join(BUILD_DIR, "node_modules", "vscode")
|
|
const fakeNodeModulesDir = path.join(BUILD_DIR, "fake_node_modules")
|
|
const vscodeDest = path.join(fakeNodeModulesDir, "vscode")
|
|
|
|
if (!fs.existsSync(vscodeSource)) {
|
|
console.error(`Error: vscode stub module not found at ${vscodeSource}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
// Create fake_node_modules directory
|
|
fs.mkdirSync(fakeNodeModulesDir, { recursive: true })
|
|
|
|
// Copy vscode stub into fake_node_modules
|
|
await cpr(vscodeSource, vscodeDest)
|
|
|
|
console.log(`✓ fake_node_modules/vscode created at ${vscodeDest}`)
|
|
}
|
|
|
|
/**
|
|
* Create .npmignore file to ensure necessary files are included
|
|
*/
|
|
async function createNpmIgnoreFile() {
|
|
console.log("Creating .npmignore file...")
|
|
|
|
// Create .npmignore that excludes build artifacts
|
|
// Note: proto/ directory is NOT excluded because proto/descriptor_set.pb is needed at runtime
|
|
const npmignoreContent = `# Exclude build artifacts and unnecessary files
|
|
binaries/
|
|
ripgrep-binaries/
|
|
standalone.zip
|
|
cline-core.js.map
|
|
package-lock.json
|
|
tree-sitter*.wasm
|
|
node_modules/vscode
|
|
`
|
|
|
|
const npmignorePath = path.join(BUILD_DIR, ".npmignore")
|
|
fs.writeFileSync(npmignorePath, npmignoreContent)
|
|
|
|
console.log(`✓ .npmignore created`)
|
|
}
|
|
|
|
/**
|
|
* Create postinstall script for NPM package
|
|
* This script selects the correct platform-specific binary and creates symlinks
|
|
*/
|
|
async function createPostinstallScript() {
|
|
console.log("Creating postinstall script...")
|
|
|
|
const postinstallScript = `#!/usr/bin/env node
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const os = require('os');
|
|
|
|
// Detect current platform and architecture
|
|
function getPlatformInfo() {
|
|
const platform = os.platform();
|
|
const arch = os.arch();
|
|
|
|
// Map Node.js arch names to Go arch names
|
|
let goArch = arch;
|
|
if (arch === 'x64') {
|
|
goArch = 'amd64';
|
|
}
|
|
|
|
let goPlatform = platform;
|
|
|
|
return { platform: goPlatform, arch: goArch };
|
|
}
|
|
|
|
// Setup platform-specific binaries
|
|
function setupBinaries() {
|
|
const { platform, arch } = getPlatformInfo();
|
|
const platformSuffix = \`\${platform}-\${arch}\`;
|
|
|
|
console.log(\`Setting up Cline CLI for \${platformSuffix}...\`);
|
|
|
|
const binDir = path.join(__dirname, 'bin');
|
|
|
|
// Check if platform-specific binaries exist
|
|
const clineSource = path.join(binDir, \`cline-\${platformSuffix}\`);
|
|
const clineHostSource = path.join(binDir, \`cline-host-\${platformSuffix}\`);
|
|
|
|
if (!fs.existsSync(clineSource)) {
|
|
console.error(\`Error: Binary not found for platform \${platformSuffix}\`);
|
|
console.error(\`Expected: \${clineSource}\`);
|
|
console.error(\`Supported platforms: darwin-arm64, darwin-amd64, linux-amd64, linux-arm64\`);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!fs.existsSync(clineHostSource)) {
|
|
console.error(\`Error: Binary not found for platform \${platformSuffix}\`);
|
|
console.error(\`Expected: \${clineHostSource}\`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Create symlinks or copies to the generic names
|
|
const clineTarget = path.join(binDir, 'cline');
|
|
const clineHostTarget = path.join(binDir, 'cline-host');
|
|
|
|
// Remove existing files if they exist
|
|
[clineTarget, clineHostTarget].forEach(target => {
|
|
if (fs.existsSync(target)) {
|
|
try {
|
|
fs.unlinkSync(target);
|
|
} catch (e) {
|
|
console.warn(\`Warning: Could not remove existing file \${target}: \${e.message}\`);
|
|
}
|
|
}
|
|
});
|
|
|
|
// On Unix, create symlinks; on Windows, copy files
|
|
if (platform === 'win32') {
|
|
// Windows: copy files
|
|
fs.copyFileSync(clineSource, clineTarget);
|
|
fs.copyFileSync(clineHostSource, clineHostTarget);
|
|
console.log('✓ Copied platform-specific binaries');
|
|
} else {
|
|
// Unix: create symlinks
|
|
fs.symlinkSync(path.basename(clineSource), clineTarget);
|
|
fs.symlinkSync(path.basename(clineHostSource), clineHostTarget);
|
|
console.log('✓ Created symlinks to platform-specific binaries');
|
|
|
|
// Make binaries executable
|
|
try {
|
|
fs.chmodSync(clineSource, 0o755);
|
|
fs.chmodSync(clineHostSource, 0o755);
|
|
fs.chmodSync(clineTarget, 0o755);
|
|
fs.chmodSync(clineHostTarget, 0o755);
|
|
} catch (error) {
|
|
console.warn(\`Warning: Could not set executable permissions: \${error.message}\`);
|
|
}
|
|
}
|
|
|
|
// Check ripgrep binary
|
|
const rgBinary = platform === 'win32' ? 'rg.exe' : 'rg';
|
|
const rgPath = path.join(__dirname, rgBinary);
|
|
|
|
if (!fs.existsSync(rgPath)) {
|
|
console.error(\`Error: ripgrep binary not found at \${rgPath}\`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Make ripgrep executable (Unix only)
|
|
if (platform !== 'win32') {
|
|
try {
|
|
fs.chmodSync(rgPath, 0o755);
|
|
} catch (error) {
|
|
console.warn(\`Warning: Could not set ripgrep executable permissions: \${error.message}\`);
|
|
}
|
|
}
|
|
|
|
console.log('✓ Cline CLI installation complete');
|
|
console.log('');
|
|
console.log('Usage:');
|
|
console.log(' cline - Start Cline CLI');
|
|
console.log(' cline-host - Start Cline host service');
|
|
console.log('');
|
|
console.log('Documentation: https://docs.cline.bot');
|
|
}
|
|
|
|
try {
|
|
setupBinaries();
|
|
} catch (error) {
|
|
console.error(\`Installation failed: \${error.message}\`);
|
|
console.error('Please report this issue at: https://github.com/cline/cline/issues');
|
|
process.exit(1);
|
|
}
|
|
`
|
|
|
|
const postinstallPath = path.join(BUILD_DIR, "postinstall.js")
|
|
fs.writeFileSync(postinstallPath, postinstallScript)
|
|
fs.chmodSync(postinstallPath, 0o755)
|
|
|
|
console.log(`✓ postinstall.js created`)
|
|
}
|
|
|
|
/**
|
|
* Downloads prebuilt binaries for each platform for the modules that include binaries. It uses `npx prebuild-install`
|
|
* to download the binary.
|
|
*
|
|
* The modules are downloaded to dist-standalone/binaries/{os}-{platform}/.
|
|
* When cline-core is installed, the installer should use the correct module for the current platform.
|
|
*/
|
|
async function packageAllBinaryDeps() {
|
|
// Check for native .node modules.
|
|
const allNativeModules = await glob("**/*.node", { cwd: path.join(BUILD_DIR, "node_modules"), nodir: true })
|
|
const isAllowed = (path) => SUPPORTED_BINARY_MODULES.some((allowed) => path.includes(allowed))
|
|
const blocked = allNativeModules.filter((x) => !isAllowed(x))
|
|
|
|
if (blocked.length > 0) {
|
|
console.error(`Error: Native node modules cannot be included in the standalone distribution:\n\n${blocked.join("\n")}`)
|
|
console.error(
|
|
"\nThese modules must support prebuilt-install and be added to the supported list in scripts/package-standalone.mjs",
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
for (const module of SUPPORTED_BINARY_MODULES) {
|
|
console.log(`Installing binaries for ${module}...`)
|
|
const src = path.join(BUILD_DIR, "node_modules", module)
|
|
if (!fs.existsSync(src)) {
|
|
console.warn(`Warning: Trying to install binaries for the module '${module}', but it is not being used by cline.`)
|
|
continue
|
|
}
|
|
|
|
for (const { platform, arch, targetDir } of TARGET_PLATFORMS) {
|
|
const binaryDir = `${BINARIES_DIR}/${targetDir}/node_modules`
|
|
fs.mkdirSync(binaryDir, { recursive: true })
|
|
|
|
// Copy the module from the build dir
|
|
const dest = path.join(binaryDir, module)
|
|
await cpr(src, dest)
|
|
|
|
// Download the binary libs
|
|
const v = IS_VERBOSE ? "--verbose" : ""
|
|
const cmd = `npx prebuild-install --platform=${platform} --arch=${arch} --target=${TARGET_NODE_VERSION} ${v}`
|
|
log_verbose(`${module}: ${cmd}`)
|
|
execSync(cmd, { cwd: dest, stdio: "inherit" })
|
|
log_verbose("")
|
|
}
|
|
// Remove the original module with the host platform binaries installed directly into node_modules.
|
|
log_verbose(`Cleaning up host version of ${module}`)
|
|
await rmrf(src)
|
|
log_verbose("")
|
|
}
|
|
}
|
|
|
|
async function zipDistribution() {
|
|
// Default JetBrains build
|
|
const zipFilename = "standalone.zip"
|
|
const zipPath = path.join(BUILD_DIR, zipFilename)
|
|
const output = fs.createWriteStream(zipPath)
|
|
const startTime = Date.now()
|
|
const archive = archiver("zip", { zlib: { level: 6 } })
|
|
|
|
output.on("close", () => {
|
|
const endTime = Date.now()
|
|
const duration = (endTime - startTime) / 1000
|
|
console.log(`Created ${zipPath} (${(archive.pointer() / 1024 / 1024).toFixed(1)} MB) in ${duration.toFixed(2)} seconds`)
|
|
})
|
|
archive.on("warning", (err) => {
|
|
console.warn(`Warning: ${err}`)
|
|
})
|
|
archive.on("error", (err) => {
|
|
throw err
|
|
})
|
|
|
|
archive.pipe(output)
|
|
|
|
// Build ignore lists for build directory and extension directory
|
|
const ignorePatterns = ["standalone.zip", "standalone-cli.zip"]
|
|
const extensionIgnores = ["dist/**"]
|
|
|
|
// For JetBrains builds, exclude binaries from both directories
|
|
// JetBrains provides their own Node.js, so exclude all binaries
|
|
ignorePatterns.push(
|
|
"bin/**", // Exclude entire bin directory
|
|
"node-binaries/**", // Exclude all platform-specific Node.js binaries
|
|
)
|
|
extensionIgnores.push(
|
|
"cli/bin/**", // Exclude CLI binaries from extension
|
|
"node-binaries/**", // Exclude node-binaries from extension
|
|
)
|
|
console.log("JetBrains build: Excluding Node.js and CLI binaries (JetBrains provides its own Node.js)")
|
|
|
|
// Add all the files from the standalone build dir.
|
|
archive.glob("**/*", {
|
|
cwd: BUILD_DIR,
|
|
ignore: ignorePatterns,
|
|
})
|
|
|
|
// Exclude the same files as the VCE vscode extension packager.
|
|
const isIgnored = createIsIgnored(extensionIgnores)
|
|
|
|
// Add the whole cline directory under "extension", except the for the ignored files.
|
|
archive.directory(process.cwd(), "extension", (entry) => {
|
|
if (isIgnored(entry.name)) {
|
|
//log_verbose("Ignoring", entry.name)
|
|
return false
|
|
}
|
|
return entry
|
|
})
|
|
|
|
console.log("Zipping package...")
|
|
await archive.finalize()
|
|
}
|
|
|
|
/**
|
|
* This is based on https://github.com/microsoft/vscode-vsce/blob/fafad8a63e9cf31179f918eb7a4eeb376834c904/src/package.ts#L1695
|
|
* because the .vscodeignore format is not compatible with the `ignore` npm module.
|
|
*/
|
|
function createIsIgnored(standaloneIgnores) {
|
|
const MinimatchOptions = { dot: true }
|
|
const defaultIgnore = [
|
|
".vscodeignore",
|
|
"package-lock.json",
|
|
"npm-debug.log",
|
|
"yarn.lock",
|
|
"yarn-error.log",
|
|
"npm-shrinkwrap.json",
|
|
".editorconfig",
|
|
".npmrc",
|
|
".yarnrc",
|
|
".gitattributes",
|
|
"*.todo",
|
|
"tslint.yaml",
|
|
".eslintrc*",
|
|
".babelrc*",
|
|
".prettierrc*",
|
|
"biome.json*",
|
|
".cz-config.js",
|
|
".commitlintrc*",
|
|
"webpack.config.js",
|
|
"ISSUE_TEMPLATE.md",
|
|
"CONTRIBUTING.md",
|
|
"PULL_REQUEST_TEMPLATE.md",
|
|
"CODE_OF_CONDUCT.md",
|
|
".github",
|
|
".travis.yml",
|
|
"appveyor.yml",
|
|
"**/.git",
|
|
"**/.git/**",
|
|
"**/*.vsix",
|
|
"**/.DS_Store",
|
|
"**/*.vsixmanifest",
|
|
"**/.vscode-test/**",
|
|
"**/.vscode-test-web/**",
|
|
]
|
|
|
|
const rawIgnore = fs.readFileSync(".vscodeignore", "utf8")
|
|
|
|
// Parse raw ignore by splitting output into lines and filtering out empty lines and comments
|
|
const parsedIgnore = rawIgnore
|
|
.split(/[\n\r]/)
|
|
.map((s) => s.trim())
|
|
.filter((s) => !!s)
|
|
.filter((i) => !/^\s*#/.test(i))
|
|
|
|
// Add '/**' to possible folder names
|
|
const expandedIgnore = [
|
|
...parsedIgnore,
|
|
...parsedIgnore.filter((i) => !/(^|\/)[^/]*\*[^/]*$/.test(i)).map((i) => (/\/$/.test(i) ? `${i}**` : `${i}/**`)),
|
|
]
|
|
|
|
// Combine with default ignore list
|
|
// Also ignore the dist directory- the build directory for the extension.
|
|
let allIgnore = [...defaultIgnore, ...expandedIgnore, ...standaloneIgnores]
|
|
|
|
// Map files need to be included in the debug build. Remove .map ignores when IS_DEBUG_BUILD is set
|
|
if (IS_DEBUG_BUILD) {
|
|
allIgnore = allIgnore.filter((pattern) => !pattern.endsWith(".map"))
|
|
console.log("Debug build: Including .map files in package")
|
|
}
|
|
|
|
// Split into ignore and negate list
|
|
const [ignore, negate] = allIgnore.reduce(
|
|
(r, e) => (!/^\s*!/.test(e) ? [[...r[0], e], r[1]] : [r[0], [...r[1], e]]),
|
|
[[], []],
|
|
)
|
|
|
|
function isIgnored(f) {
|
|
return (
|
|
ignore.some((i) => minimatch(f, i, MinimatchOptions)) &&
|
|
!negate.some((i) => minimatch(f, i.substr(1), MinimatchOptions))
|
|
)
|
|
}
|
|
return isIgnored
|
|
}
|
|
|
|
/* cp -r */
|
|
async function cpr(source, dest) {
|
|
log_verbose(`Copying ${source} -> ${dest}`)
|
|
await cp(source, dest, {
|
|
recursive: true,
|
|
preserveTimestamps: true,
|
|
dereference: false, // preserve symlinks instead of following them
|
|
})
|
|
}
|
|
|
|
function log_verbose(...args) {
|
|
if (IS_VERBOSE) {
|
|
console.log(...args)
|
|
}
|
|
}
|
|
|
|
await main()
|