mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
refactor(cli): tighten tui-worktree, log exclude-write failures, fix event count
This commit is contained in:
@@ -5,10 +5,13 @@
|
||||
// created in.
|
||||
import path from "path"
|
||||
import type { Effect } from "effect"
|
||||
import * as Log from "@opencode-ai/core/util/log"
|
||||
import { UI } from "@/cli/ui"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
import { errorMessage } from "@/util/error"
|
||||
|
||||
const log = Log.create({ service: "kilocode.tui-worktree" })
|
||||
|
||||
// Matches packages/kilo-vscode/src/agent-manager/WorktreeManager.ts's placement
|
||||
// and its ensureGitExclude(), keeping `.kilo/worktrees/` out of `git status`.
|
||||
const KILO_WORKTREE_DIR = ".kilo/worktrees"
|
||||
@@ -19,7 +22,9 @@ export async function ensureGitExclude(root: string) {
|
||||
const current = (await Filesystem.readText(excludePath).catch(() => "")).replace(/\s+$/, "")
|
||||
if (current.includes(`${KILO_WORKTREE_DIR}/`)) return
|
||||
const prefix = current ? `${current}\n\n` : ""
|
||||
await Filesystem.write(excludePath, `${prefix}# Kilo Code agent worktrees\n${KILO_WORKTREE_DIR}/\n`).catch(() => {})
|
||||
await Filesystem.write(excludePath, `${prefix}# Kilo Code agent worktrees\n${KILO_WORKTREE_DIR}/\n`).catch((err) =>
|
||||
log.error("failed to update .git/info/exclude", { excludePath, err }),
|
||||
)
|
||||
}
|
||||
|
||||
function samePath(a: string, b: string) {
|
||||
@@ -140,13 +145,10 @@ async function resolveWorktree(name: string, root: string, timeoutMs = 10 * 60_0
|
||||
// only with `-d` (not `-D`): it refuses unless the branch is fully merged,
|
||||
// so we never silently discard unmerged work from an interrupted worktree
|
||||
// or an unrelated branch that happens to share the name.
|
||||
const branchRef = await run(
|
||||
Git.Service.use((git) =>
|
||||
git.run(["show-ref", "--verify", "--quiet", `refs/heads/${slug}`], { cwd: ctx.worktree }),
|
||||
),
|
||||
)
|
||||
const runGit = (args: string[]) => run(Git.Service.use((git) => git.run(args, { cwd: ctx.worktree })))
|
||||
const branchRef = await runGit(["show-ref", "--verify", "--quiet", `refs/heads/${slug}`])
|
||||
if (branchRef.exitCode === 0) {
|
||||
const deleted = await run(Git.Service.use((git) => git.run(["branch", "-d", slug], { cwd: ctx.worktree })))
|
||||
const deleted = await runGit(["branch", "-d", slug])
|
||||
if (deleted.exitCode !== 0) {
|
||||
const message = deleted.stderr.toString("utf8").trim() || deleted.text().trim()
|
||||
throw new Error(
|
||||
|
||||
@@ -9,7 +9,7 @@ describe("public event manifest", () => {
|
||||
expect(EventManifest.Definitions).toBe(SchemaEventManifest.Definitions)
|
||||
expect(EventManifest.Latest).toBe(SchemaEventManifest.Latest)
|
||||
expect(EventManifest.Durable).toBe(SchemaEventManifest.Durable)
|
||||
expect(EventManifest.Latest.size).toBe(89) // kilocode_change - include global.config.updated
|
||||
expect(EventManifest.Latest.size).toBe(90) // kilocode_change - include global.config.updated and worktree.setup.ready
|
||||
expect(EventManifest.Latest.get("session.next.step.ended")).toBe(SessionEvent.Step.Ended)
|
||||
expect(EventManifest.Latest.get("todo.updated")).toBe(Todo.Event.Updated)
|
||||
expect(EventManifest.Latest.has("ide.installed")).toBe(false)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import path from "path"
|
||||
import { mkdtemp, rm } from "fs/promises"
|
||||
import { tmpdir as osTmpdir } from "os"
|
||||
import { tmpdir } from "../../../fixture/fixture"
|
||||
import { ensureGitExclude, slugify } from "@/kilocode/cli/cmd/tui-worktree"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
|
||||
@@ -22,46 +21,36 @@ describe("slugify", () => {
|
||||
})
|
||||
|
||||
describe("ensureGitExclude", () => {
|
||||
async function withRepo(fn: (root: string) => Promise<void>) {
|
||||
const root = await mkdtemp(path.join(osTmpdir(), "tui-worktree-exclude-"))
|
||||
try {
|
||||
await fn(root)
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
test("appends the exclude entry when the file exists but is empty", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
const excludePath = path.join(tmp.path, ".git", "info", "exclude")
|
||||
await Filesystem.write(excludePath, "")
|
||||
await ensureGitExclude(tmp.path)
|
||||
expect(await Filesystem.readText(excludePath)).toContain(".kilo/worktrees/")
|
||||
})
|
||||
|
||||
test("appends the exclude entry when the file exists but is empty", () =>
|
||||
withRepo(async (root) => {
|
||||
const excludePath = path.join(root, ".git", "info", "exclude")
|
||||
await Filesystem.write(excludePath, "")
|
||||
await ensureGitExclude(root)
|
||||
const content = await Filesystem.readText(excludePath)
|
||||
expect(content).toContain(".kilo/worktrees/")
|
||||
}))
|
||||
test("preserves existing content and adds a newline before the new entry", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
const excludePath = path.join(tmp.path, ".git", "info", "exclude")
|
||||
await Filesystem.write(excludePath, "*.log")
|
||||
await ensureGitExclude(tmp.path)
|
||||
const content = await Filesystem.readText(excludePath)
|
||||
expect(content).toContain("*.log")
|
||||
expect(content).toContain(".kilo/worktrees/")
|
||||
})
|
||||
|
||||
test("preserves existing content and adds a newline before the new entry", () =>
|
||||
withRepo(async (root) => {
|
||||
const excludePath = path.join(root, ".git", "info", "exclude")
|
||||
await Filesystem.write(excludePath, "*.log")
|
||||
await ensureGitExclude(root)
|
||||
const content = await Filesystem.readText(excludePath)
|
||||
expect(content).toContain("*.log")
|
||||
expect(content).toContain(".kilo/worktrees/")
|
||||
}))
|
||||
test("is idempotent when the entry already exists", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
const excludePath = path.join(tmp.path, ".git", "info", "exclude")
|
||||
await Filesystem.write(excludePath, "")
|
||||
await ensureGitExclude(tmp.path)
|
||||
await ensureGitExclude(tmp.path)
|
||||
const content = await Filesystem.readText(excludePath)
|
||||
expect(content.match(/\.kilo\/worktrees\//g)?.length).toBe(1)
|
||||
})
|
||||
|
||||
test("is idempotent when the entry already exists", () =>
|
||||
withRepo(async (root) => {
|
||||
const excludePath = path.join(root, ".git", "info", "exclude")
|
||||
await Filesystem.write(excludePath, "")
|
||||
await ensureGitExclude(root)
|
||||
await ensureGitExclude(root)
|
||||
const content = await Filesystem.readText(excludePath)
|
||||
expect(content.match(/\.kilo\/worktrees\//g)?.length).toBe(1)
|
||||
}))
|
||||
|
||||
test("does not throw when .git/info is missing", () =>
|
||||
withRepo(async (root) => {
|
||||
await ensureGitExclude(root)
|
||||
}))
|
||||
test("does not throw when .git/info is missing", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
await ensureGitExclude(tmp.path)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user