mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-01 15:32:11 +08:00
chore: remove stale desktop package references
This commit is contained in:
@@ -46,7 +46,6 @@ bun run merge.ts --version v1.1.50 --base-branch catrielmuller/kilo-opencode-v1.
|
||||
| `transforms/skip-files.ts` | Skip/remove files that shouldn't exist in Kilo |
|
||||
| `transforms/transform-i18n.ts` | Transform i18n files with Kilo branding |
|
||||
| `transforms/transform-take-theirs.ts` | Take upstream + apply Kilo branding for branding-only files |
|
||||
| `transforms/transform-tauri.ts` | Transform Tauri/Desktop config files |
|
||||
| `transforms/transform-package-json.ts` | Enhanced package.json with Kilo dependency injection |
|
||||
| `transforms/transform-scripts.ts` | Transform script files with GitHub API references |
|
||||
| `transforms/transform-extensions.ts` | Transform extension files (Zed, etc.) |
|
||||
@@ -82,7 +81,6 @@ The merge automation follows this process, applying **all transformations BEFORE
|
||||
- Preserve Kilo's versions
|
||||
- Transform i18n files with Kilo branding
|
||||
- Transform branding-only files (UI components, configs)
|
||||
- Transform Tauri/Desktop config files
|
||||
- Transform package.json files (names, deps, Kilo injections)
|
||||
- Transform script files (GitHub API references)
|
||||
- Transform extension files (Zed, etc.)
|
||||
@@ -132,19 +130,10 @@ Configuration is defined in `utils/config.ts`:
|
||||
|
||||
// Files to take upstream + apply Kilo branding transforms
|
||||
takeTheirsAndTransform: [
|
||||
"packages/app/src/components/**/*.tsx",
|
||||
"packages/app/src/context/**/*.tsx",
|
||||
"packages/ui/src/**/*.tsx",
|
||||
// ...
|
||||
],
|
||||
|
||||
// Tauri/Desktop config files
|
||||
tauriFiles: [
|
||||
"packages/desktop/src-tauri/*.json",
|
||||
"packages/desktop/src-tauri/src/*.rs",
|
||||
// ...
|
||||
],
|
||||
|
||||
// Kilo-specific directories (preserved)
|
||||
kiloDirectories: [
|
||||
"packages/opencode/src/kilocode",
|
||||
@@ -168,11 +157,10 @@ The following transforms are applied to the opencode branch before merging:
|
||||
3. **Versions** - Preserve Kilo's version numbers
|
||||
4. **i18n files** - OpenCode -> Kilo in user-visible strings
|
||||
5. **Branding files** - UI components, configs with branding only
|
||||
6. **Tauri configs** - Desktop app identifiers, names
|
||||
7. **package.json** - Names, dependencies, Kilo injections
|
||||
8. **Scripts** - GitHub API references
|
||||
9. **Extensions** - Zed, etc.
|
||||
10. **Web/docs** - Documentation files
|
||||
6. **package.json** - Names, dependencies, Kilo injections
|
||||
7. **Scripts** - GitHub API references
|
||||
8. **Extensions** - Zed, etc.
|
||||
9. **Web/docs** - Documentation files
|
||||
|
||||
### Post-Merge Strategies
|
||||
|
||||
@@ -181,8 +169,7 @@ After merging, any remaining conflicts are handled based on file type:
|
||||
| File Type | Strategy | Description |
|
||||
|---|---|---|
|
||||
| i18n files | `i18n-transform` | Take upstream, apply Kilo branding |
|
||||
| App components | `take-theirs-transform` | Take upstream, apply branding (no logic changes) |
|
||||
| Tauri configs | `tauri-transform` | Take upstream, transform identifiers/names |
|
||||
| UI components | `take-theirs-transform` | Take upstream, apply branding (no logic changes) |
|
||||
| package.json | `package-transform` | Take upstream, transform names, inject Kilo deps |
|
||||
| Script files | `script-transform` | Take upstream, transform GitHub references |
|
||||
| Extensions | `extension-transform` | Take upstream, apply branding |
|
||||
|
||||
@@ -18,7 +18,6 @@ import { error, header, info, success, warn } from "./utils/logger"
|
||||
import { transformI18nContent } from "./transforms/transform-i18n"
|
||||
import { applyBrandingTransforms } from "./transforms/transform-take-theirs"
|
||||
import { applyScriptTransforms } from "./transforms/transform-scripts"
|
||||
import { applyTauriTransforms } from "./transforms/transform-tauri"
|
||||
import { applyExtensionTransforms } from "./transforms/transform-extensions"
|
||||
import { applyWebTransforms } from "./transforms/transform-web"
|
||||
import { applyPackageNameTransforms } from "./transforms/package-names"
|
||||
@@ -149,8 +148,7 @@ async function translate(file: string, text: string) {
|
||||
const script = applyScriptTransforms(names).result
|
||||
const branded = applyBrandingTransforms(script).result
|
||||
const i18n = transformI18nContent(branded).result
|
||||
const tauri = applyTauriTransforms(i18n, file).result
|
||||
const ext = applyExtensionTransforms(tauri, file).result
|
||||
const ext = applyExtensionTransforms(i18n, file).result
|
||||
const web = applyWebTransforms(ext).result
|
||||
|
||||
return workflow(file, web)
|
||||
|
||||
@@ -35,14 +35,6 @@ export {
|
||||
matchesPattern,
|
||||
} from "./transforms/transform-take-theirs"
|
||||
|
||||
export {
|
||||
transformConflictedTauri,
|
||||
transformTauriFile,
|
||||
transformAllTauri,
|
||||
isTauriFile,
|
||||
applyTauriTransforms,
|
||||
} from "./transforms/transform-tauri"
|
||||
|
||||
export {
|
||||
transformConflictedPackageJson,
|
||||
transformPackageJson,
|
||||
|
||||
@@ -25,31 +25,18 @@ import * as logger from "./utils/logger"
|
||||
import * as version from "./utils/version"
|
||||
import * as report from "./utils/report"
|
||||
import * as worktree from "./utils/worktree"
|
||||
import { defaultConfig, loadConfig, type MergeConfig } from "./utils/config"
|
||||
import { loadConfig } from "./utils/config"
|
||||
import { transformAll as transformPackageNames } from "./transforms/package-names"
|
||||
import { preserveAllVersions } from "./transforms/preserve-versions"
|
||||
import { keepOursFiles, resetToOurs } from "./transforms/keep-ours"
|
||||
import { skipFiles, skipSpecificFiles } from "./transforms/skip-files"
|
||||
import { skipFiles } from "./transforms/skip-files"
|
||||
import { transformConflictedI18n, transformAllI18n } from "./transforms/transform-i18n"
|
||||
// New transforms for auto-resolving more conflict types
|
||||
import {
|
||||
transformConflictedTakeTheirs,
|
||||
shouldTakeTheirs,
|
||||
transformAllTakeTheirs,
|
||||
} from "./transforms/transform-take-theirs"
|
||||
import { transformConflictedTauri, isTauriFile, transformAllTauri } from "./transforms/transform-tauri"
|
||||
import {
|
||||
transformConflictedPackageJson,
|
||||
isPackageJson,
|
||||
transformAllPackageJson,
|
||||
} from "./transforms/transform-package-json"
|
||||
import { transformConflictedScripts, isScriptFile, transformAllScripts } from "./transforms/transform-scripts"
|
||||
import {
|
||||
transformConflictedExtensions,
|
||||
isExtensionFile,
|
||||
transformAllExtensions,
|
||||
} from "./transforms/transform-extensions"
|
||||
import { transformConflictedWeb, isWebFile, transformAllWeb } from "./transforms/transform-web"
|
||||
import { transformConflictedTakeTheirs, transformAllTakeTheirs } from "./transforms/transform-take-theirs"
|
||||
import { transformConflictedPackageJson, transformAllPackageJson } from "./transforms/transform-package-json"
|
||||
import { transformConflictedScripts, transformAllScripts } from "./transforms/transform-scripts"
|
||||
import { transformConflictedExtensions, transformAllExtensions } from "./transforms/transform-extensions"
|
||||
import { transformConflictedWeb, transformAllWeb } from "./transforms/transform-web"
|
||||
import { resolveLockFileConflicts, regenerateLockFiles } from "./transforms/lock-files"
|
||||
|
||||
interface MergeOptions {
|
||||
@@ -470,14 +457,6 @@ async function main() {
|
||||
logger.success(`Transformed ${brandingCount} files with Kilo branding`)
|
||||
}
|
||||
|
||||
// 6e. Transform Tauri/Desktop config files
|
||||
logger.info("Transforming Tauri/Desktop config files...")
|
||||
const tauriPreResults = await transformAllTauri({ dryRun: false, verbose: options.verbose })
|
||||
const tauriPreCount = tauriPreResults.filter((r) => r.action === "transformed" && r.replacements > 0).length
|
||||
if (tauriPreCount > 0) {
|
||||
logger.success(`Transformed ${tauriPreCount} Tauri config files`)
|
||||
}
|
||||
|
||||
// 6f. Transform package.json files (names, deps, Kilo injections)
|
||||
logger.info("Transforming package.json files...")
|
||||
const pkgPreResults = await transformAllPackageJson({ dryRun: false, verbose: options.verbose })
|
||||
@@ -629,26 +608,6 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Transform Tauri files
|
||||
conflictedFiles = await git.getConflictedFiles()
|
||||
if (conflictedFiles.length > 0) {
|
||||
const tauriResults = await transformConflictedTauri(conflictedFiles, {
|
||||
dryRun: false,
|
||||
verbose: options.verbose,
|
||||
})
|
||||
const tauriCount = tauriResults.filter((r) => r.action === "transformed").length
|
||||
if (tauriCount > 0) {
|
||||
logger.success(`Auto-resolved ${tauriCount} Tauri conflicts`)
|
||||
}
|
||||
const tauriFlagged = tauriResults.filter((r) => r.action === "flagged").map((r) => r.file)
|
||||
if (tauriFlagged.length > 0) {
|
||||
logger.warn(
|
||||
`${tauriFlagged.length} Tauri file(s) have kilocode_change markers — flagged for manual resolution`,
|
||||
)
|
||||
flaggedFiles.push(...tauriFlagged)
|
||||
}
|
||||
}
|
||||
|
||||
// Transform package.json files
|
||||
conflictedFiles = await git.getConflictedFiles()
|
||||
if (conflictedFiles.length > 0) {
|
||||
|
||||
@@ -121,28 +121,6 @@ export async function regenerateLockFiles(options: LockFileOptions = {}): Promis
|
||||
}
|
||||
}
|
||||
|
||||
// Check for Cargo.lock in Tauri package
|
||||
const cargoLockPath = "packages/desktop/src-tauri/Cargo.lock"
|
||||
const hasCargoLock = await Bun.file(cargoLockPath).exists()
|
||||
|
||||
if (hasCargoLock) {
|
||||
if (options.dryRun) {
|
||||
info("[DRY-RUN] Would regenerate Cargo.lock via 'cargo generate-lockfile'")
|
||||
results.push({ file: cargoLockPath, action: "regenerated", dryRun: true })
|
||||
} else {
|
||||
info("Regenerating Cargo.lock...")
|
||||
const result = await $`cargo generate-lockfile`.cwd("packages/desktop/src-tauri").quiet().nothrow()
|
||||
if (result.exitCode === 0) {
|
||||
success("Regenerated Cargo.lock")
|
||||
results.push({ file: cargoLockPath, action: "regenerated", dryRun: false })
|
||||
} else {
|
||||
// Cargo might not be installed, just warn
|
||||
warn(`Could not regenerate Cargo.lock (cargo may not be installed): ${result.stderr.toString()}`)
|
||||
results.push({ file: cargoLockPath, action: "skipped", dryRun: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note about nix/hashes.json - regenerated by CI, not locally
|
||||
const nixHashesPath = "nix/hashes.json"
|
||||
const hasNixHashes = await Bun.file(nixHashesPath).exists()
|
||||
|
||||
@@ -7,8 +7,8 @@ test("matches hosted package glob paths", () => {
|
||||
expect(shouldSkip("packages/console/app/package.json", ["packages/console/**"])).toBe(true)
|
||||
})
|
||||
|
||||
test("does not match sibling package glob paths", () => {
|
||||
expect(shouldSkip("packages/app/package.json", ["packages/web/**"])).toBe(false)
|
||||
test("matches removed app package glob paths", () => {
|
||||
expect(shouldSkip("packages/app/package.json", ["packages/app/**"])).toBe(true)
|
||||
})
|
||||
|
||||
test("matches extension glob paths", () => {
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
* String replacement rules:
|
||||
* - opencode.ai -> kilo.ai (domain)
|
||||
* - app.opencode.ai -> app.kilo.ai (app domain)
|
||||
* - OpenCode Desktop -> Kilo Desktop (desktop app name)
|
||||
* - OpenCode -> Kilo (product name in user-visible text)
|
||||
* - opencode upgrade -> kilo upgrade (CLI commands)
|
||||
* - npx opencode -> npx kilo (CLI invocation)
|
||||
@@ -74,13 +73,6 @@ const I18N_REPLACEMENTS: StringReplacement[] = [
|
||||
description: "Main domain (excluding zen)",
|
||||
},
|
||||
|
||||
// Product name (specific phrases first)
|
||||
{
|
||||
pattern: /OpenCode Desktop/g,
|
||||
replacement: "Kilo Desktop",
|
||||
description: "Desktop app name",
|
||||
},
|
||||
|
||||
// CLI commands (be careful with order)
|
||||
{
|
||||
pattern: /npx opencode(?!\w)/g,
|
||||
|
||||
@@ -186,10 +186,6 @@ const KILO_DEPENDENCIES: Record<string, Record<string, string>> = {
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
"@kilocode/kilo-telemetry": "workspace:*",
|
||||
},
|
||||
// packages/app/package.json needs these
|
||||
"packages/app/package.json": {
|
||||
"@kilocode/kilo-i18n": "workspace:*",
|
||||
},
|
||||
}
|
||||
|
||||
// Kilo-specific bin entries to set on specific packages
|
||||
|
||||
@@ -61,13 +61,6 @@ const BRANDING_REPLACEMENTS: BrandingReplacement[] = [
|
||||
description: "Main domain (excluding zen)",
|
||||
},
|
||||
|
||||
// Product name (specific phrases first)
|
||||
{
|
||||
pattern: /OpenCode Desktop/g,
|
||||
replacement: "Kilo Desktop",
|
||||
description: "Desktop app name",
|
||||
},
|
||||
|
||||
// CLI commands
|
||||
{
|
||||
pattern: /npx opencode(?!\w)/g,
|
||||
@@ -133,16 +126,6 @@ const BRANDING_REPLACEMENTS: BrandingReplacement[] = [
|
||||
},
|
||||
]
|
||||
|
||||
// Patterns that should NOT be replaced (preserved as-is)
|
||||
const PRESERVE_PATTERNS = [
|
||||
/opencode\.json/g, // Config filename
|
||||
/\.opencode\//g, // Directory name
|
||||
/\.opencode`/g, // Directory name in template strings
|
||||
/"\.opencode"/g, // Directory name in quotes
|
||||
/'\.opencode'/g, // Directory name in single quotes
|
||||
/\/\/\s*kilocode_change/g, // Already has marker
|
||||
]
|
||||
|
||||
/**
|
||||
* Check if a file matches any of the patterns
|
||||
*/
|
||||
@@ -169,16 +152,6 @@ export function applyBrandingTransforms(content: string, verbose = false): { res
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if line has preserve patterns
|
||||
let hasPreserve = false
|
||||
for (const pattern of PRESERVE_PATTERNS) {
|
||||
pattern.lastIndex = 0
|
||||
if (pattern.test(line)) {
|
||||
hasPreserve = true
|
||||
pattern.lastIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
let result = line
|
||||
let count = 0
|
||||
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* Transform Tauri/Desktop config files with Kilo branding
|
||||
*
|
||||
* This script handles Tauri configuration files (JSON, TOML, Rust) by:
|
||||
* 1. Taking upstream's version as the base
|
||||
* 2. Applying predictable Kilo branding transforms
|
||||
*
|
||||
* Handles:
|
||||
* - tauri.conf.json / tauri.prod.conf.json
|
||||
* - Cargo.toml / Cargo.lock
|
||||
* - Rust source files (*.rs)
|
||||
*/
|
||||
|
||||
import { $ } from "bun"
|
||||
import { info, success, warn, debug } from "../utils/logger"
|
||||
import { defaultConfig } from "../utils/config"
|
||||
import { oursHasKilocodeChanges } from "../utils/git"
|
||||
|
||||
export interface TauriTransformResult {
|
||||
file: string
|
||||
action: "transformed" | "skipped" | "failed" | "flagged"
|
||||
replacements: number
|
||||
dryRun: boolean
|
||||
}
|
||||
|
||||
export interface TauriTransformOptions {
|
||||
dryRun?: boolean
|
||||
verbose?: boolean
|
||||
}
|
||||
|
||||
interface TauriReplacement {
|
||||
pattern: RegExp
|
||||
replacement: string
|
||||
description: string
|
||||
fileTypes?: string[] // Only apply to these file extensions
|
||||
}
|
||||
|
||||
// Tauri-specific replacements
|
||||
const TAURI_REPLACEMENTS: TauriReplacement[] = [
|
||||
// JSON config - product names
|
||||
{
|
||||
pattern: /"productName":\s*"OpenCode[^"]*"/g,
|
||||
replacement: '"productName": "Kilo"',
|
||||
description: "Product name in JSON",
|
||||
fileTypes: [".json"],
|
||||
},
|
||||
{
|
||||
pattern: /"title":\s*"OpenCode[^"]*"/g,
|
||||
replacement: '"title": "Kilo"',
|
||||
description: "Title in JSON",
|
||||
fileTypes: [".json"],
|
||||
},
|
||||
|
||||
// JSON config - identifiers
|
||||
{
|
||||
pattern: /ai\.opencode\.desktop\.dev/g,
|
||||
replacement: "ai.kilo.desktop.dev",
|
||||
description: "Dev identifier",
|
||||
},
|
||||
{
|
||||
pattern: /ai\.opencode\.desktop/g,
|
||||
replacement: "ai.kilo.desktop",
|
||||
description: "Prod identifier",
|
||||
},
|
||||
|
||||
// Binary names
|
||||
{
|
||||
pattern: /opencode-cli/g,
|
||||
replacement: "kilo-cli",
|
||||
description: "CLI binary name",
|
||||
},
|
||||
{
|
||||
pattern: /"mainBinaryName":\s*"[Oo]pen[Cc]ode"/g,
|
||||
replacement: '"mainBinaryName": "Kilo"',
|
||||
description: "Main binary name",
|
||||
fileTypes: [".json"],
|
||||
},
|
||||
|
||||
// GitHub references
|
||||
{
|
||||
pattern: /github\.com\/anomalyco\/opencode/g,
|
||||
replacement: "github.com/Kilo-Org/kilocode",
|
||||
description: "GitHub URL",
|
||||
},
|
||||
{
|
||||
pattern: /anomalyco\/opencode/g,
|
||||
replacement: "Kilo-Org/kilocode",
|
||||
description: "GitHub repo",
|
||||
},
|
||||
|
||||
// Cargo.toml specific
|
||||
{
|
||||
pattern: /name\s*=\s*"opencode-desktop"/g,
|
||||
replacement: 'name = "kilo-desktop"',
|
||||
description: "Cargo package name",
|
||||
fileTypes: [".toml"],
|
||||
},
|
||||
{
|
||||
pattern: /authors\s*=\s*\["OpenCode"\]/g,
|
||||
replacement: 'authors = ["Kilo"]',
|
||||
description: "Cargo authors",
|
||||
fileTypes: [".toml"],
|
||||
},
|
||||
{
|
||||
pattern: /name\s*=\s*"opencode_lib"/g,
|
||||
replacement: 'name = "kilo_lib"',
|
||||
description: "Cargo lib name",
|
||||
fileTypes: [".toml"],
|
||||
},
|
||||
|
||||
// Rust source specific
|
||||
{
|
||||
pattern: /opencode\.db/g,
|
||||
replacement: "kilo.db",
|
||||
description: "Database filename",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
{
|
||||
pattern: /opencode\.settings\.dat/g,
|
||||
replacement: "kilo.settings.dat",
|
||||
description: "Settings file name",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
{
|
||||
pattern: /"\.opencode\/bin"/g,
|
||||
replacement: '".kilo/bin"',
|
||||
description: "CLI install dir",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
{
|
||||
pattern: /CLI_BINARY_NAME\s*=\s*"opencode"/g,
|
||||
replacement: 'CLI_BINARY_NAME = "kilo"',
|
||||
description: "CLI binary constant",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
{
|
||||
pattern: /opencode_lib::run/g,
|
||||
replacement: "kilo_lib::run",
|
||||
description: "Lib run call",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
{
|
||||
pattern: /killall opencode-cli/g,
|
||||
replacement: "killall kilo-cli",
|
||||
description: "Killall command",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
|
||||
// Domain
|
||||
{
|
||||
pattern: /opencode\.ai/g,
|
||||
replacement: "kilo.ai",
|
||||
description: "Domain",
|
||||
},
|
||||
|
||||
// Environment variables (exclude OPENCODE_API_KEY)
|
||||
{
|
||||
pattern: /OPENCODE_(?!API_KEY)([A-Z_]+)/g,
|
||||
replacement: "KILO_$1",
|
||||
description: "Env variable",
|
||||
fileTypes: [".rs"],
|
||||
},
|
||||
{
|
||||
pattern: /__OPENCODE__/g,
|
||||
replacement: "__KILO__",
|
||||
description: "Window global",
|
||||
fileTypes: [".rs", ".tsx"],
|
||||
},
|
||||
{
|
||||
pattern: /OPENCODE_PORT/g,
|
||||
replacement: "KILO_PORT",
|
||||
description: "Port env var",
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* Check if a file is a Tauri config file
|
||||
*/
|
||||
export function isTauriFile(file: string): boolean {
|
||||
const patterns = defaultConfig.tauriFiles
|
||||
|
||||
return patterns.some((pattern) => {
|
||||
const regex = new RegExp("^" + pattern.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*") + "$")
|
||||
return regex.test(file)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file extension
|
||||
*/
|
||||
function getExtension(file: string): string {
|
||||
const match = file.match(/\.[^.]+$/)
|
||||
return match ? match[0] : ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply Tauri-specific transforms to content
|
||||
*/
|
||||
export function applyTauriTransforms(
|
||||
content: string,
|
||||
file: string,
|
||||
verbose = false,
|
||||
): { result: string; replacements: number } {
|
||||
const ext = getExtension(file)
|
||||
let result = content
|
||||
let total = 0
|
||||
|
||||
for (const { pattern, replacement, description, fileTypes } of TAURI_REPLACEMENTS) {
|
||||
// Skip if this replacement is for specific file types and doesn't match
|
||||
if (fileTypes && !fileTypes.includes(ext)) {
|
||||
continue
|
||||
}
|
||||
|
||||
pattern.lastIndex = 0
|
||||
|
||||
if (pattern.test(result)) {
|
||||
pattern.lastIndex = 0
|
||||
const before = result
|
||||
result = result.replace(pattern, replacement)
|
||||
|
||||
if (before !== result) {
|
||||
total++
|
||||
if (verbose) debug(` ${description}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { result, replacements: total }
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a single Tauri file
|
||||
*/
|
||||
export async function transformTauriFile(
|
||||
file: string,
|
||||
options: TauriTransformOptions = {},
|
||||
): Promise<TauriTransformResult> {
|
||||
if (options.dryRun) {
|
||||
info(`[DRY-RUN] Would transform Tauri file: ${file}`)
|
||||
return { file, action: "transformed", replacements: 0, dryRun: true }
|
||||
}
|
||||
|
||||
// If our version has kilocode_change markers, flag for manual resolution
|
||||
if (await oursHasKilocodeChanges(file)) {
|
||||
warn(`${file} has kilocode_change markers — skipping auto-transform, needs manual resolution`)
|
||||
return { file, action: "flagged", replacements: 0, dryRun: false }
|
||||
}
|
||||
|
||||
try {
|
||||
// Take upstream's version first
|
||||
await $`git checkout --theirs ${file}`.quiet().nothrow()
|
||||
await $`git add ${file}`.quiet().nothrow()
|
||||
|
||||
// Read content
|
||||
const content = await Bun.file(file).text()
|
||||
|
||||
// Apply transforms
|
||||
const { result, replacements } = applyTauriTransforms(content, file, options.verbose)
|
||||
|
||||
// Write back if changed
|
||||
if (replacements > 0) {
|
||||
await Bun.write(file, result)
|
||||
await $`git add ${file}`.quiet().nothrow()
|
||||
}
|
||||
|
||||
success(`Transformed Tauri file ${file}: ${replacements} replacements`)
|
||||
return { file, action: "transformed", replacements, dryRun: false }
|
||||
} catch (err) {
|
||||
warn(`Failed to transform Tauri file ${file}: ${err}`)
|
||||
return { file, action: "failed", replacements: 0, dryRun: false }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform conflicted Tauri files
|
||||
*/
|
||||
export async function transformConflictedTauri(
|
||||
files: string[],
|
||||
options: TauriTransformOptions = {},
|
||||
): Promise<TauriTransformResult[]> {
|
||||
const results: TauriTransformResult[] = []
|
||||
|
||||
for (const file of files) {
|
||||
if (!isTauriFile(file)) {
|
||||
debug(`Skipping ${file} - not a Tauri file`)
|
||||
results.push({ file, action: "skipped", replacements: 0, dryRun: options.dryRun ?? false })
|
||||
continue
|
||||
}
|
||||
|
||||
const result = await transformTauriFile(file, options)
|
||||
results.push(result)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform all Tauri files (pre-merge, on opencode branch)
|
||||
*/
|
||||
export async function transformAllTauri(options: TauriTransformOptions = {}): Promise<TauriTransformResult[]> {
|
||||
const { Glob } = await import("bun")
|
||||
const results: TauriTransformResult[] = []
|
||||
const patterns = defaultConfig.tauriFiles
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const glob = new Glob(pattern)
|
||||
|
||||
for await (const path of glob.scan({ absolute: false })) {
|
||||
const file = Bun.file(path)
|
||||
if (!(await file.exists())) continue
|
||||
|
||||
try {
|
||||
const content = await file.text()
|
||||
const { result, replacements } = applyTauriTransforms(content, path, options.verbose)
|
||||
|
||||
if (replacements > 0 && !options.dryRun) {
|
||||
await Bun.write(path, result)
|
||||
success(`Transformed Tauri ${path}: ${replacements} replacements`)
|
||||
} else if (options.dryRun && replacements > 0) {
|
||||
info(`[DRY-RUN] Would transform Tauri ${path}: ${replacements} replacements`)
|
||||
}
|
||||
|
||||
results.push({ file: path, action: "transformed", replacements, dryRun: options.dryRun ?? false })
|
||||
} catch (err) {
|
||||
warn(`Failed to transform Tauri ${path}: ${err}`)
|
||||
results.push({ file: path, action: "failed", replacements: 0, dryRun: options.dryRun ?? false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// CLI entry point
|
||||
if (import.meta.main) {
|
||||
const args = process.argv.slice(2)
|
||||
const dryRun = args.includes("--dry-run")
|
||||
const verbose = args.includes("--verbose")
|
||||
|
||||
const files = args.filter((a) => !a.startsWith("--"))
|
||||
|
||||
if (files.length === 0) {
|
||||
info("Usage: transform-tauri.ts [--dry-run] [--verbose] <file1> <file2> ...")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
info("Running in dry-run mode")
|
||||
}
|
||||
|
||||
const results = await transformConflictedTauri(files, { dryRun, verbose })
|
||||
|
||||
const transformed = results.filter((r) => r.action === "transformed")
|
||||
const total = results.reduce((sum, r) => sum + r.replacements, 0)
|
||||
|
||||
console.log()
|
||||
success(`Transformed ${transformed.length} Tauri files with ${total} replacements`)
|
||||
|
||||
if (dryRun) {
|
||||
info("Run without --dry-run to apply changes")
|
||||
}
|
||||
}
|
||||
@@ -56,11 +56,6 @@ const WEB_REPLACEMENTS: WebReplacement[] = [
|
||||
},
|
||||
|
||||
// Product names
|
||||
{
|
||||
pattern: /OpenCode Desktop/g,
|
||||
replacement: "Kilo Desktop",
|
||||
description: "Desktop name",
|
||||
},
|
||||
{
|
||||
pattern: /\bOpenCode\b(?!\.json|\/| Zen)/g,
|
||||
replacement: "Kilo",
|
||||
|
||||
@@ -21,9 +21,6 @@ export interface MergeConfig {
|
||||
/** Files that should take upstream version and apply Kilo branding transforms */
|
||||
takeTheirsAndTransform: string[]
|
||||
|
||||
/** Tauri/Desktop config files with predictable branding patterns */
|
||||
tauriFiles: string[]
|
||||
|
||||
/** Script files with GitHub API references */
|
||||
scriptFiles: string[]
|
||||
|
||||
@@ -142,6 +139,9 @@ export const defaultConfig: MergeConfig = {
|
||||
"packages/function/**",
|
||||
"packages/docs/**",
|
||||
"packages/identity/**",
|
||||
"packages/app/**",
|
||||
"packages/desktop/**",
|
||||
"packages/desktop-electron/**",
|
||||
// GitHub Action - Kilo version is fully ported and complete
|
||||
"github/index.ts",
|
||||
"github/package.json",
|
||||
@@ -153,27 +153,9 @@ export const defaultConfig: MergeConfig = {
|
||||
// Files that should take upstream version and apply Kilo branding transforms
|
||||
// These are files with only branding differences, no logic changes
|
||||
takeTheirsAndTransform: [
|
||||
// App components with branding only
|
||||
"packages/app/src/components/**/*.tsx",
|
||||
"packages/app/src/context/**/*.tsx",
|
||||
"packages/app/src/pages/**/*.tsx",
|
||||
// UI components
|
||||
"packages/ui/src/components/**/*.tsx",
|
||||
"packages/ui/src/context/**/*.tsx",
|
||||
// Desktop TypeScript files (not Rust)
|
||||
"packages/desktop/src/**/*.ts",
|
||||
// E2E and test fixtures
|
||||
"packages/app/e2e/**/*.ts",
|
||||
"packages/app/script/**/*.ts",
|
||||
],
|
||||
|
||||
// Tauri/Desktop config files with predictable branding patterns
|
||||
tauriFiles: [
|
||||
"packages/desktop/src-tauri/tauri.conf.json",
|
||||
"packages/desktop/src-tauri/tauri.prod.conf.json",
|
||||
"packages/desktop/src-tauri/Cargo.toml",
|
||||
"packages/desktop/src-tauri/Cargo.lock",
|
||||
"packages/desktop/src-tauri/src/*.rs",
|
||||
],
|
||||
|
||||
// Script files with GitHub API references
|
||||
@@ -228,7 +210,7 @@ export const defaultConfig: MergeConfig = {
|
||||
originRemote: "origin",
|
||||
|
||||
// i18n translation files that need Kilo branding transforms
|
||||
i18nPatterns: ["packages/*/src/i18n/*.ts", "packages/desktop/src/i18n/*.ts"],
|
||||
i18nPatterns: ["packages/*/src/i18n/*.ts"],
|
||||
}
|
||||
|
||||
export function loadConfig(overrides?: Partial<MergeConfig>): MergeConfig {
|
||||
|
||||
@@ -11,7 +11,7 @@ test("recommends skip for hosted package globs", () => {
|
||||
})
|
||||
|
||||
test("does not recommend skip for unrelated packages", () => {
|
||||
expect(getRecommendation("packages/app/package.json", [], ["packages/web/**"]).recommendation).toBe(
|
||||
expect(getRecommendation("packages/ui/package.json", [], ["packages/web/**"]).recommendation).toBe(
|
||||
"package-transform",
|
||||
)
|
||||
})
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface ConflictReport {
|
||||
|
||||
export interface ConflictFile {
|
||||
path: string
|
||||
type: "markdown" | "package" | "code" | "config" | "i18n" | "tauri" | "script" | "extension" | "web" | "other"
|
||||
type: "markdown" | "package" | "code" | "config" | "i18n" | "script" | "extension" | "web" | "other"
|
||||
recommendation:
|
||||
| "keep-ours"
|
||||
| "keep-theirs"
|
||||
@@ -29,7 +29,6 @@ export interface ConflictFile {
|
||||
| "skip"
|
||||
| "i18n-transform"
|
||||
| "take-theirs-transform"
|
||||
| "tauri-transform"
|
||||
| "package-transform"
|
||||
| "script-transform"
|
||||
| "extension-transform"
|
||||
@@ -45,16 +44,6 @@ function isI18nFile(path: string): boolean {
|
||||
return /packages\/[^/]+\/src\/i18n\/[^/]+\.ts$/.test(path) && !path.endsWith("/index.ts")
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is a Tauri/Desktop config file
|
||||
*/
|
||||
function isTauriFile(path: string): boolean {
|
||||
return (
|
||||
path.includes("packages/desktop/src-tauri/") &&
|
||||
(path.endsWith(".json") || path.endsWith(".toml") || path.endsWith(".rs") || path.endsWith(".lock"))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is a script file
|
||||
*/
|
||||
@@ -80,17 +69,7 @@ function isWebFile(path: string): boolean {
|
||||
* Check if a file should use take-theirs + transform strategy
|
||||
*/
|
||||
function shouldTakeTheirsTransform(path: string): boolean {
|
||||
const patterns = [
|
||||
/^packages\/app\/src\/components\/.*\.tsx$/,
|
||||
/^packages\/app\/src\/context\/.*\.tsx$/,
|
||||
/^packages\/app\/src\/pages\/.*\.tsx$/,
|
||||
/^packages\/ui\/src\/.*\.tsx$/,
|
||||
/^packages\/desktop\/src\/.*\.ts$/,
|
||||
/^packages\/app\/e2e\/.*\.ts$/,
|
||||
/^packages\/app\/script\/.*\.ts$/,
|
||||
/^github\/index\.ts$/,
|
||||
/^packages\/slack\/src\/.*\.ts$/,
|
||||
]
|
||||
const patterns = [/^packages\/ui\/src\/.*\.tsx$/, /^github\/index\.ts$/, /^packages\/slack\/src\/.*\.ts$/]
|
||||
return patterns.some((p) => p.test(path))
|
||||
}
|
||||
|
||||
@@ -99,7 +78,6 @@ function shouldTakeTheirsTransform(path: string): boolean {
|
||||
*/
|
||||
export function classifyFile(path: string): ConflictFile["type"] {
|
||||
if (isI18nFile(path)) return "i18n"
|
||||
if (isTauriFile(path)) return "tauri"
|
||||
if (isScriptFile(path)) return "script"
|
||||
if (isExtensionFile(path)) return "extension"
|
||||
if (isWebFile(path)) return "web"
|
||||
@@ -194,17 +172,6 @@ export function getRecommendation(
|
||||
recommendation: "i18n-transform",
|
||||
reason: "i18n file: take upstream translations and apply Kilo branding",
|
||||
}
|
||||
case "tauri":
|
||||
if (currentContent?.includes("kilocode_change")) {
|
||||
return {
|
||||
recommendation: "manual",
|
||||
reason: "Tauri config has kilocode_change markers — auto-transform skipped, needs manual review",
|
||||
}
|
||||
}
|
||||
return {
|
||||
recommendation: "tauri-transform",
|
||||
reason: "Tauri config: take upstream and apply Kilo branding transforms",
|
||||
}
|
||||
case "script":
|
||||
if (currentContent?.includes("kilocode_change")) {
|
||||
return {
|
||||
@@ -348,7 +315,6 @@ export function generateMarkdownReport(report: ConflictReport): string {
|
||||
"skip",
|
||||
"i18n-transform",
|
||||
"take-theirs-transform",
|
||||
"tauri-transform",
|
||||
"package-transform",
|
||||
"script-transform",
|
||||
"extension-transform",
|
||||
@@ -367,7 +333,6 @@ export function generateMarkdownReport(report: ConflictReport): string {
|
||||
skip: "Skip (Auto-Remove)",
|
||||
"i18n-transform": "i18n Transform (Auto-Apply Kilo Branding)",
|
||||
"take-theirs-transform": "Take Upstream + Kilo Branding (Auto)",
|
||||
"tauri-transform": "Tauri Config Transform (Auto)",
|
||||
"package-transform": "Package.json Transform (Auto)",
|
||||
"script-transform": "Script Transform (Auto)",
|
||||
"extension-transform": "Extension Transform (Auto)",
|
||||
|
||||
Reference in New Issue
Block a user