diff --git a/packages/kilo-docs/pages/automate/agent-manager.md b/packages/kilo-docs/pages/automate/agent-manager.md index 3cd9b2790cf..9b346f23e9a 100644 --- a/packages/kilo-docs/pages/automate/agent-manager.md +++ b/packages/kilo-docs/pages/automate/agent-manager.md @@ -300,14 +300,14 @@ Parallel Mode runs the agent in an isolated Git worktree branch, keeping your ma ### Worktree Location -Worktrees are created in `.kilocode/worktrees/` within your project directory. This folder is automatically excluded from git via `.git/info/exclude` (a local-only ignore file that doesn't require a commit). +Worktrees are created in `.kilo/worktrees/` within your project directory. This folder is automatically excluded from git via `.git/info/exclude` (a local-only ignore file that doesn't require a commit). ``` your-project/ ├── .git/ │ └── info/ -│ └── exclude # local ignore rules (includes .kilocode/worktrees/) -├── .kilocode/ +│ └── exclude # local ignore rules (includes .kilo/worktrees/) +├── .kilo/ │ └── worktrees/ │ └── feature-branch-1234567890/ # isolated working directory └── ... diff --git a/packages/kilo-docs/pages/automate/extending/auto-launch.md b/packages/kilo-docs/pages/automate/extending/auto-launch.md index a0f21a49d8c..321fbb7a49b 100644 --- a/packages/kilo-docs/pages/automate/extending/auto-launch.md +++ b/packages/kilo-docs/pages/automate/extending/auto-launch.md @@ -25,8 +25,8 @@ This happens seamlessly in the background, requiring no manual intervention. ### Basic Setup -1. Create a `.kilocode` directory in your workspace root (if it doesn't exist) -2. Create a `launchConfig.json` file inside the `.kilocode` directory +1. Create a `.kilo` directory in your workspace root (if it doesn't exist) +2. Create a `launchConfig.json` file inside the `.kilo` directory 3. Configure your launch settings using the JSON format below ### Configuration Format @@ -120,7 +120,7 @@ The configuration file must be located at: ``` your-workspace/ -└── .kilocode/ +└── .kilo/ └── launchConfig.json ``` @@ -138,7 +138,7 @@ This file should be at the root of your workspace (the same level as your main p ### Configuration Not Loading -1. Verify file location: `.kilocode/launchConfig.json` in workspace root +1. Verify file location: `.kilo/launchConfig.json` in workspace root 2. Check JSON syntax with a JSON validator 3. Ensure `prompt` field is present and not empty 4. Check VS Code Developer Console for error messages diff --git a/packages/kilo-docs/pages/automate/mcp/using-in-kilo-code.md b/packages/kilo-docs/pages/automate/mcp/using-in-kilo-code.md index 18629f8bdf1..be07c82dcd6 100644 --- a/packages/kilo-docs/pages/automate/mcp/using-in-kilo-code.md +++ b/packages/kilo-docs/pages/automate/mcp/using-in-kilo-code.md @@ -89,7 +89,7 @@ MCP server configurations can be managed at two levels: **global** (applies acro | Scope | Path | Description | | ----------- | -------------------- | --------------------------------------------------------------- | | **Global** | `mcp_settings.json` | Accessible via VS Code settings. Applies across all workspaces. | -| **Project** | `.kilocode/mcp.json` | In your project root. Auto-detected by Kilo Code. | +| **Project** | `.kilo/mcp.json` | In your project root. Auto-detected by Kilo Code. | Project-level configs can be committed to version control to share with your team. @@ -397,7 +397,7 @@ You can edit both global and project-level MCP configuration files directly from 3. Select the `MCP Servers` sub-tab 4. Click the appropriate button: - **`Edit Global MCP`**: Opens the global `mcp_settings.json` file. - - **`Edit Project MCP`**: Opens the project-specific `.kilocode/mcp.json` file. If this file doesn't exist, Kilo Code will create it for you. + - **`Edit Project MCP`**: Opens the project-specific `.kilo/mcp.json` file. If this file doesn't exist, Kilo Code will create it for you. {% image src="/docs/img/using-mcp-in-kilo-code/mcp-installed-config.png" alt="Edit Global MCP and Edit Project MCP buttons" width="600" caption="Edit Global MCP and Edit Project MCP buttons" /%} @@ -692,7 +692,7 @@ Example: "Analyze the performance of my API" might use an MCP tool that tests AP {% tab label="VSCode (Legacy)" %} - **Server Not Responding:** Check if the server process is running and verify network connectivity -- **Permission Errors:** Ensure proper API keys and credentials are configured in your `mcp_settings.json` (for global settings) or `.kilocode/mcp.json` (for project settings). +- **Permission Errors:** Ensure proper API keys and credentials are configured in your `mcp_settings.json` (for global settings) or `.kilo/mcp.json` (for project settings). - **Tool Not Available:** Confirm the server is properly implementing the tool and it's not disabled in settings - **Slow Performance:** Try adjusting the network timeout value for the specific MCP server diff --git a/packages/kilo-docs/pages/automate/tools/use-mcp-tool.md b/packages/kilo-docs/pages/automate/tools/use-mcp-tool.md index 3fb498f0182..6d7d9a9b768 100644 --- a/packages/kilo-docs/pages/automate/tools/use-mcp-tool.md +++ b/packages/kilo-docs/pages/automate/tools/use-mcp-tool.md @@ -49,10 +49,10 @@ This tool allows Kilo Code to access specialized functionality provided by exter MCP servers can be configured globally or at the project level: - **Global Configuration**: Managed through the Kilo Code extension settings in VS Code. These apply across all projects unless overridden. -- **Project-level Configuration**: Defined in a `.kilocode/mcp.json` file within your project's root directory. +- **Project-level Configuration**: Defined in a `.kilo/mcp.json` file within your project's root directory. - This allows project-specific server setups. - Project-level servers take precedence over global servers if they share the same name. -- Since `.kilocode/mcp.json` can be committed to version control, it simplifies sharing configurations with your team. +- Since `.kilo/mcp.json` can be committed to version control, it simplifies sharing configurations with your team. ## How It Works diff --git a/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md b/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md index 4e0f2a18bb3..43be3e3e5a1 100644 --- a/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md +++ b/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md @@ -85,21 +85,21 @@ You can customize each Cloud Agent session by also defining env vars and startup - Bootstrapping tooling - Running setup scripts -### Setup Commands vs `.kilocode/setup-script` +### Setup Commands vs `.kilo/setup-script` - Cloud Agent executes **Setup Commands** configured in the Cloud UI/profile. -- Cloud Agent does **not** automatically discover or run `.kilocode/setup-script`. -- If you want to use `.kilocode/setup-script` in Cloud Agent, call it explicitly from Setup Commands, for example: `bash .kilocode/setup-script`. +- Cloud Agent does **not** automatically discover or run `.kilo/setup-script`. +- If you want to use `.kilo/setup-script` in Cloud Agent, call it explicitly from Setup Commands, for example: `bash .kilo/setup-script`. - If both are present, execution order is: 1. Setup Commands (in the order you define them) - 2. Anything those commands invoke (such as `.kilocode/setup-script`) + 2. Anything those commands invoke (such as `.kilo/setup-script`) ## Skills -Cloud Agents support project-level [skills](/docs/code-with-ai/platforms/cli#skills) stored in your repository. When your repo is cloned, any skills in `.kilocode/skills/` are automatically available. +Cloud Agents support project-level [skills](/docs/code-with-ai/platforms/cli#skills) stored in your repository. When your repo is cloned, any skills in `.kilo/skills/` are automatically available. {% callout type="note" %} -Global skills (`~/.kilocode/skills/`) are not available in Cloud Agents since there is no persistent user home directory. +Global skills (`~/.kilo/skills/`) are not available in Cloud Agents since there is no persistent user home directory. {% /callout %} ## Remote Connections diff --git a/packages/kilo-docs/pages/collaborate/enterprise/migration.md b/packages/kilo-docs/pages/collaborate/enterprise/migration.md index 3719ad05e44..ef388218012 100644 --- a/packages/kilo-docs/pages/collaborate/enterprise/migration.md +++ b/packages/kilo-docs/pages/collaborate/enterprise/migration.md @@ -193,12 +193,12 @@ Kilo Code uses a compatible rules system that supports Cursor and Windsurf patte **Quick Overview:** -- **Project rules**: `.cursor/rules/*.mdc` → `.kilocode/rules/*.md` (remove YAML frontmatter, keep Markdown content) -- **Legacy rules**: `.cursorrules` → `.kilocode/rules/legacy-rules.md` +- **Project rules**: `.cursor/rules/*.mdc` → `.kilo/rules/*.md` (remove YAML frontmatter, keep Markdown content) +- **Legacy rules**: `.cursorrules` → `.kilo/rules/legacy-rules.md` - **AGENTS.md**: Works identically in Kilo Code (no conversion needed) -- **Global rules**: Recreate in `~/.kilocode/rules/*.md` directory +- **Global rules**: Recreate in `~/.kilo/rules/*.md` directory -Kilo Code also supports mode-specific rules (`.kilocode/rules-{mode}/`), which Cursor and Windsurf don't have. This allows different rules for different workflows (e.g., Code mode vs Debug mode). +Kilo Code also supports mode-specific rules (`.kilo/rules-{mode}/`), which Cursor and Windsurf don't have. This allows different rules for different workflows (e.g., Code mode vs Debug mode). **👉 For detailed step-by-step instructions, format conversion examples, troubleshooting, and advanced migration scenarios, see our [Technical Migration Guide](/docs/getting-started/migrating).** diff --git a/packages/kilo-docs/pages/collaborate/teams/analytics.md b/packages/kilo-docs/pages/collaborate/teams/analytics.md index 17ca4565d4f..7c89d27da04 100644 --- a/packages/kilo-docs/pages/collaborate/teams/analytics.md +++ b/packages/kilo-docs/pages/collaborate/teams/analytics.md @@ -88,9 +88,9 @@ For example, if the following were in your `.git/config`: The project name would be `example-repo`. -You can also manually override the project name in the `.kilocode/config.json` file in your project. +You can also manually override the project name in the `.kilo/config.json` file in your project. -To set the project identifier to `my-project`, create a `.kilocode/config.json` file with the following contents: +To set the project identifier to `my-project`, create a `.kilo/config.json` file with the following contents: ```json { diff --git a/packages/kilo-docs/pages/customize/custom-rules.md b/packages/kilo-docs/pages/customize/custom-rules.md index eb3c7fea120..9b8374b36cf 100644 --- a/packages/kilo-docs/pages/customize/custom-rules.md +++ b/packages/kilo-docs/pages/customize/custom-rules.md @@ -105,11 +105,11 @@ The CLI is backward compatible with `.kilocode/rules/` directories. Existing rul ### Project Rules -Custom rules are primarily loaded from the **`.kilocode/rules/` directory**. This is the recommended approach for organizing your project-specific rules. Each rule is typically placed in its own Markdown file with a descriptive name: +Custom rules are primarily loaded from the **`.kilo/rules/` directory**. This is the recommended approach for organizing your project-specific rules. Each rule is typically placed in its own Markdown file with a descriptive name: ``` project/ -├── .kilocode/ +├── .kilo/ │ ├── rules/ │ │ ├── formatting.md │ │ ├── restricted_files.md @@ -123,7 +123,7 @@ project/ Global rules are stored in your home directory and apply to all projects: ``` -~/.kilocode/ +~/.kilo/ ├── rules/ │ ├── coding_standards.md │ ├── security_guidelines.md @@ -178,7 +178,7 @@ Rules are managed by editing the `instructions` array in your `kilo.jsonc` confi {% /tab %} {% tab label="VSCode (Legacy)" %} -Kilo Code provides a built-in interface for managing your custom rules without manually editing files in the `.kilocode/rules/` directories. To access the UI, click on the icon in the **bottom right corner** of the Kilo Code window. +Kilo Code provides a built-in interface for managing your custom rules without manually editing files in the `.kilo/rules/` directories. To access the UI, click on the icon in the **bottom right corner** of the Kilo Code window. You can access the rules management UI to: @@ -231,8 +231,8 @@ If `.kilocode/rules/` directories exist in your project, their contents are auto Rules are loaded in the following priority order: -1. **Global rules** from `~/.kilocode/rules/` directory -2. **Project rules** from `.kilocode/rules/` directory +1. **Global rules** from `~/.kilo/rules/` directory +2. **Project rules** from `.kilo/rules/` directory 3. **Legacy fallback files** (for backward compatibility): - `.roorules` - `.clinerules` @@ -241,14 +241,14 @@ Rules are loaded in the following priority order: When both global and project rules exist, they are combined with project rules taking precedence over global rules for conflicting directives. {% callout type="note" %} -We strongly recommend keeping your rules in the `.kilocode/rules/` folder as it provides better organization and is the preferred approach for future versions. The legacy file-based approach is maintained for backward compatibility but may be subject to change in future releases. +We strongly recommend keeping your rules in the `.kilo/rules/` folder as it provides better organization and is the preferred approach for future versions. The legacy file-based approach is maintained for backward compatibility but may be subject to change in future releases. {% /callout %} ### Mode-Specific Rules The system also supports mode-specific rules with their own priority order: -1. First, it checks for `.kilocode/rules-${mode}/` directory +1. First, it checks for `.kilo/rules-${mode}/` directory 2. If that doesn't exist or is empty, it falls back to `.kilocoderules-${mode}` file (deprecated) Mode-specific rules are only supported at the project level. When both generic and mode-specific rules exist, mode-specific rules take priority. @@ -316,14 +316,14 @@ To create rules manually: **For Project Rules:** -1. Create the `.kilocode/rules/` directory if it doesn't already exist +1. Create the `.kilo/rules/` directory if it doesn't already exist 2. Create a new Markdown file with a descriptive name in this directory 3. Write your rule using Markdown formatting 4. Save the file **For Global Rules:** -1. Create the `~/.kilocode/rules/` directory if it doesn't already exist +1. Create the `~/.kilo/rules/` directory if it doesn't already exist 2. Create a new Markdown file with a descriptive name in this directory 3. Write your rule using Markdown formatting 4. Save the file @@ -430,8 +430,8 @@ If your custom rules aren't being properly followed: 3. **Check rule locations**: - **Check rule status in the UI**: Use the rules management interface to verify that your rules are active and properly loaded - Ensure rules are in supported locations: - - Global rules: `~/.kilocode/rules/` directory - - Project rules: `.kilocode/rules/` directory + - Global rules: `~/.kilo/rules/` directory + - Project rules: `.kilo/rules/` directory - Legacy files: `.kilocoderules`, `.roorules`, or `.clinerules` - **Restart VS Code** to ensure the rules are properly loaded diff --git a/packages/kilo-docs/pages/customize/skills.md b/packages/kilo-docs/pages/customize/skills.md index 3f7c85dc107..26b593c6ec6 100644 --- a/packages/kilo-docs/pages/customize/skills.md +++ b/packages/kilo-docs/pages/customize/skills.md @@ -158,13 +158,13 @@ The `skills.paths` key accepts absolute paths, `~/` home-relative paths, or path ### Global Skills (User-Level) -Global skills are located in the `.kilocode` directory within your Home directory. +Global skills are located in the `.kilo` directory within your Home directory. -- Mac and Linux: `~/.kilocode/skills/` -- Windows: `\Users\\.kilocode\` +- Mac and Linux: `~/.kilo/skills/` +- Windows: `\Users\\.kilo\` ``` -~/.kilocode/ +~/.kilo/ ├── skills/ # Generic skills (all modes) │ ├── my-skill/ │ │ └── SKILL.md @@ -180,11 +180,11 @@ Global skills are located in the `.kilocode` directory within your Home director ### Project Skills (Workspace-Level) -Located in `.kilocode/skills/` within your project: +Located in `.kilo/skills/` within your project: ``` your-project/ -└── .kilocode/ +└── .kilo/ ├── skills/ # Generic skills for this project │ └── project-conventions/ │ └── SKILL.md @@ -219,10 +219,10 @@ To create a skill that only appears in a specific mode, place it in a `skills-{m ```bash # For Code mode only -mkdir -p ~/.kilocode/skills-code/typescript-patterns +mkdir -p ~/.kilo/skills-code/typescript-patterns # For Architect mode only -mkdir -p ~/.kilocode/skills-architect/microservices +mkdir -p ~/.kilo/skills-architect/microservices ``` The directory naming pattern is `skills-{mode-slug}` where `{mode-slug}` matches the mode's identifier (e.g., `code`, `architect`, `ask`, `debug`). @@ -419,7 +419,7 @@ These additional files can be referenced from your skill's instructions, allowin 1. Create the skill directory: ```bash - mkdir -p ~/.kilocode/skills/api-design + mkdir -p ~/.kilo/skills/api-design ``` 2. Create `SKILL.md` (see content below) diff --git a/packages/kilo-docs/pages/index.tsx b/packages/kilo-docs/pages/index.tsx index b3f89322e91..533973ed563 100644 --- a/packages/kilo-docs/pages/index.tsx +++ b/packages/kilo-docs/pages/index.tsx @@ -50,7 +50,7 @@ const terminalContent = { <> # Create a custom rules file in your project {"\n"} - $ touch .kilocode/rules.md + $ touch .kilo/rules.md {"\n"} {"\n"} # Or use the CLI to add rules diff --git a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts index 788248d17db..eeab6644bd5 100644 --- a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts +++ b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts @@ -241,17 +241,9 @@ export class AgentManagerProvider implements Disposable { return } - const migration = await state.load() + await state.load() manager.cleanupOrphanedTempDirs() - // When the .kilocode → .kilo migration rewrote git worktree refs, nudge - // VS Code's git extension to re-discover them. Without this, worktrees - // won't appear in Source Control until the next VS Code restart. - if (migration.refsFixed > 0) { - this.log(`Migration fixed ${migration.refsFixed} git worktree ref(s), refreshing git`) - this.host.refreshGit() - } - for (const wt of state.getWorktrees()) { for (const s of state.getSessions(wt.id)) { this.panel?.sessions.setSessionDirectory(s.id, wt.path) diff --git a/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts b/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts index 5d6c92edf9a..54c8517293d 100644 --- a/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts +++ b/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts @@ -81,7 +81,7 @@ function stripRemotePrefix(ref: string): { branch: string; remote?: string } { return { branch: ref } } -import { KILO_DIR, LEGACY_DIR, migrateAgentManagerData } from "./constants" +import { KILO_DIR } from "./constants" const SESSION_ID_FILE = "session-id" const METADATA_FILE = "metadata.json" @@ -92,7 +92,6 @@ export class WorktreeManager { private readonly git: SimpleGit private readonly ops: GitOps | undefined private readonly log: (msg: string) => void - private migrated = false constructor(root: string, log: (msg: string) => void, ops?: GitOps) { this.root = root @@ -102,13 +101,6 @@ export class WorktreeManager { this.log = log } - /** Run once before first read/write to migrate Agent Manager data from .kilocode → .kilo. */ - private async ensureMigrated(): Promise { - if (this.migrated) return - this.migrated = true - await migrateAgentManagerData(this.root, this.log) - } - // --------------------------------------------------------------------------- // Per-project git operation mutex // --------------------------------------------------------------------------- @@ -147,7 +139,6 @@ export class WorktreeManager { branchName?: string onProgress?: (step: WorktreeProgressStep, message: string, detail?: string) => void }): Promise { - await this.ensureMigrated() return this.withGitLock(() => this.createWorktreeImpl(params)) } @@ -422,7 +413,6 @@ export class WorktreeManager { } async discoverWorktrees(): Promise { - await this.ensureMigrated() if (!fs.existsSync(this.dir)) return [] const entries = await fs.promises.readdir(this.dir, { withFileTypes: true }) @@ -454,12 +444,7 @@ export class WorktreeManager { async readMetadata( worktreePath: string, ): Promise<{ sessionId: string; parentBranch?: string; remote?: string } | undefined> { - // Check .kilo/ first, then legacy .kilocode/ - for (const dirName of [KILO_DIR, LEGACY_DIR]) { - const result = await this.readMetadataFrom(worktreePath, dirName) - if (result) return result - } - return undefined + return this.readMetadataFrom(worktreePath, KILO_DIR) } private async readMetadataFrom( @@ -510,13 +495,6 @@ export class WorktreeManager { [".kilo/setup-script.ps1", "Kilo Code worktree setup script"], [".kilo/setup-script.cmd", "Kilo Code worktree setup script"], [".kilo/setup-script.bat", "Kilo Code worktree setup script"], - [".kilocode/worktrees/", "Kilo Code legacy agent worktrees"], - [".kilocode/agent-manager.json", "Kilo Agent Manager legacy state"], - [".kilocode/setup-script", "Kilo Code legacy worktree setup script"], - [".kilocode/setup-script.sh", "Kilo Code legacy worktree setup script"], - [".kilocode/setup-script.ps1", "Kilo Code legacy worktree setup script"], - [".kilocode/setup-script.cmd", "Kilo Code legacy worktree setup script"], - [".kilocode/setup-script.bat", "Kilo Code legacy worktree setup script"], ] as const for (const [entry, comment] of items) { diff --git a/packages/kilo-vscode/src/agent-manager/WorktreeStateManager.ts b/packages/kilo-vscode/src/agent-manager/WorktreeStateManager.ts index cb38552128f..fff48170ac9 100644 --- a/packages/kilo-vscode/src/agent-manager/WorktreeStateManager.ts +++ b/packages/kilo-vscode/src/agent-manager/WorktreeStateManager.ts @@ -75,7 +75,7 @@ interface StateFile { defaultBaseBranch?: string } -import { KILO_DIR, migrateAgentManagerData, type MigrationResult } from "./constants" +import { KILO_DIR } from "./constants" const STATE_FILE = "agent-manager.json" @@ -100,8 +100,6 @@ export class WorktreeStateManager { private pendingSave = false private readonly root: string - private migrated = false - constructor(root: string, log: (msg: string) => void) { this.root = root this.file = path.join(root, KILO_DIR, STATE_FILE) @@ -506,13 +504,7 @@ export class WorktreeStateManager { // Persistence // --------------------------------------------------------------------------- - async load(): Promise { - // Migrate Agent Manager data from .kilocode → .kilo before first read - let migration: MigrationResult = { refsFixed: 0 } - if (!this.migrated) { - this.migrated = true - migration = await migrateAgentManagerData(this.root, this.log) - } + async load(): Promise { try { const content = await fs.promises.readFile(this.file, "utf-8") const data = JSON.parse(content) as StateFile @@ -524,12 +516,7 @@ export class WorktreeStateManager { this.reviewDiffStyle = "unified" for (const [id, wt] of Object.entries(data.worktrees ?? {})) { - // Rewrite stale .kilocode paths while preserving the separator style already stored. - const fixed = - wt.path?.replace(/([/\\])\.kilocode([/\\])/g, (_match, leadingSep, trailingSep) => { - return `${leadingSep}.kilo${trailingSep}` - }) ?? wt.path - this.worktrees.set(id, { id, ...wt, path: fixed }) + this.worktrees.set(id, { id, ...wt }) } let pruned = 0 for (const [id, s] of Object.entries(data.sessions ?? {})) { @@ -571,7 +558,6 @@ export class WorktreeStateManager { this.log(`Failed to load state: ${error}`) } } - return migration } /** Remove worktrees whose directories no longer exist on disk and prune orphaned sessions. */ diff --git a/packages/kilo-vscode/src/agent-manager/constants.ts b/packages/kilo-vscode/src/agent-manager/constants.ts index 771ce4172f2..6c223c67334 100644 --- a/packages/kilo-vscode/src/agent-manager/constants.ts +++ b/packages/kilo-vscode/src/agent-manager/constants.ts @@ -1,9 +1,3 @@ -import * as fs from "node:fs" -import * as path from "node:path" - -// TODO: Remove the legacy .kilocode -> .kilo migration helpers below after the -// GA release cleanup tracked in https://github.com/Kilo-Org/kilocode/issues/6986. - /** * Maximum number of parallel worktree versions for multi-version mode. * Keep in sync with MAX_MULTI_VERSIONS in webview-ui/src/types/messages.ts. @@ -15,179 +9,3 @@ export const PLATFORM = "agent-manager" as const /** Kilo config directory name (project-level and inside worktrees). */ export const KILO_DIR = ".kilo" - -/** Legacy config directory name for backward compatibility reads. */ -export const LEGACY_DIR = ".kilocode" - -/** Agent Manager files that should be migrated from .kilocode/ to .kilo/. */ -const AGENT_MANAGER_ITEMS = [ - "agent-manager.json", - "worktrees", - "setup-script", - "setup-script.sh", - "setup-script.ps1", - "setup-script.cmd", - "setup-script.bat", -] - -/** Result of the migration so callers can react (e.g. refresh VS Code git). */ -export interface MigrationResult { - /** Number of git worktree refs that were rewritten from .kilocode → .kilo. */ - refsFixed: number -} - -/** - * Migrate Agent Manager data from .kilocode/ to .kilo/. - * - * Moves individual Agent Manager files/directories (worktrees, state, - * setup scripts) from the legacy .kilocode/ into .kilo/. Skips items - * that already exist in .kilo/ (the new location wins). This is safe - * because Agent Manager exclusively owns these files. - * - * Fixes git worktree internal references (.git/worktrees/{name}/gitdir) - * whenever .kilo/worktrees/ exists so partially migrated repos recover too. - * - * Idempotent: safe to call on every startup. - */ -export async function migrateAgentManagerData(root: string, log: (msg: string) => void): Promise { - const legacy = path.join(root, LEGACY_DIR) - const target = path.join(root, KILO_DIR) - - if (await isDirectory(legacy)) { - // Ensure .kilo/ exists - try { - await fs.promises.mkdir(target, { recursive: true }) - } catch { - // already exists - } - - for (const item of AGENT_MANAGER_ITEMS) { - const src = path.join(legacy, item) - const dst = path.join(target, item) - - if (!(await exists(src))) continue - - if (await exists(dst)) { - log(`Skipping ${item}: already exists in ${KILO_DIR}`) - continue - } - - try { - await fs.promises.rename(src, dst) - log(`Migrated ${item} from ${LEGACY_DIR} to ${KILO_DIR}`) - } catch (err) { - // On Windows, rename can fail with EPERM/EBUSY if files are held open. - // Will succeed on next startup. - log(`Warning: failed to migrate ${item}: ${err}`) - } - } - } - - let refsFixed = 0 - if (await isDirectory(path.join(target, "worktrees"))) { - refsFixed = await fixGitWorktreeRefs(root, log) - } - - return { refsFixed } -} - -async function exists(filepath: string): Promise { - try { - await fs.promises.stat(filepath) - return true - } catch { - return false - } -} - -async function isDirectory(filepath: string): Promise { - try { - const stat = await fs.promises.stat(filepath) - return stat.isDirectory() - } catch { - return false - } -} - -/** - * Resolve the real git directory for a repository root. - * When root/.git is a directory, returns it directly. - * When root/.git is a file (worktree), follows the gitdir pointer - * up two levels to reach the shared git directory. - */ -async function resolveGitDir(root: string): Promise { - const gitPath = path.join(root, ".git") - try { - const stat = await fs.promises.stat(gitPath) - if (stat.isDirectory()) return gitPath - - const content = await fs.promises.readFile(gitPath, "utf-8") - const match = content.match(/^gitdir:\s*(.+)$/m) - if (!match?.[1]) return undefined - // gitdir points to e.g. /repo/.git/worktrees/foo — go up two levels to /repo/.git - return path.resolve(path.dirname(gitPath), match[1].trim(), "..", "..") - } catch { - return undefined - } -} - -/** - * After moving worktrees from .kilocode/ to .kilo/, fix git internal refs. - * - * Git stores absolute paths in .git/worktrees/{name}/gitdir. When the - * worktree directory moves, those paths become stale. This rewrites any - * gitdir files that reference the old .kilocode path. - * - * Returns the number of refs that were successfully fixed so callers can - * tell whether a VS Code git refresh is warranted. - */ -async function fixGitWorktreeRefs(root: string, log: (msg: string) => void): Promise { - const gitDir = await resolveGitDir(root) - if (!gitDir) { - log("fixGitWorktreeRefs: could not resolve git directory") - return 0 - } - - const gitWorktreesDir = path.join(gitDir, "worktrees") - try { - const stat = await fs.promises.stat(gitWorktreesDir) - if (!stat.isDirectory()) return 0 - } catch (err) { - log(`fixGitWorktreeRefs: ${gitWorktreesDir} not accessible: ${err}`) - return 0 - } - - const oldSegment = path.join(root, LEGACY_DIR) + path.sep - const newSegment = path.join(root, KILO_DIR) + path.sep - let fixed = 0 - - try { - const entries = await fs.promises.readdir(gitWorktreesDir, { withFileTypes: true }) - for (const entry of entries) { - if (!entry.isDirectory()) continue - const gitdirFile = path.join(gitWorktreesDir, entry.name, "gitdir") - try { - const content = await fs.promises.readFile(gitdirFile, "utf-8") - if (!content.includes(oldSegment)) continue - - const updated = content.replaceAll(oldSegment, newSegment) - await fs.promises.writeFile(gitdirFile, updated) - - // Verify the write persisted — catch silent FS failures (e.g. read-only mount) - const verify = await fs.promises.readFile(gitdirFile, "utf-8") - if (verify === updated) { - fixed++ - log(`Fixed git worktree ref: ${entry.name}`) - } else { - log(`Warning: git worktree ref write did not persist for ${entry.name}`) - } - } catch (err) { - log(`Warning: could not fix git worktree ref ${entry.name}: ${err}`) - } - } - } catch (err) { - log(`Warning: could not read ${gitWorktreesDir}: ${err}`) - } - - return fixed -}