Merge branch 'fix/perf-q02' into fix/perf-omo-in-tree

This commit is contained in:
Sisyphus
2026-04-18 14:43:37 +09:00
2 changed files with 61 additions and 14 deletions
+43 -11
View File
@@ -1,15 +1,10 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test" import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
import { mkdirSync, realpathSync, rmSync } from "node:fs" import { mkdirSync, realpathSync, rmSync } from "node:fs"
import { tmpdir } from "node:os" import { tmpdir } from "node:os"
import { join } from "node:path" import { join } from "node:path"
import {
findProjectAgentsSkillDirs,
findProjectClaudeSkillDirs,
findProjectOpencodeCommandDirs,
findProjectOpencodeSkillDirs,
} from "./project-discovery-dirs"
const TEST_DIR = join(tmpdir(), `project-discovery-dirs-${Date.now()}`) const TEST_DIR = join(tmpdir(), `project-discovery-dirs-${Date.now()}`)
let worktreeSpawnCount = 0
function canonicalPath(path: string): string { function canonicalPath(path: string): string {
return realpathSync(path) return realpathSync(path)
@@ -24,7 +19,35 @@ describe("project-discovery-dirs", () => {
rmSync(TEST_DIR, { recursive: true, force: true }) rmSync(TEST_DIR, { recursive: true, force: true })
}) })
it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", () => { it("#given repeated worktree detection #when detecting twice #then reuses the cached result", async () => {
// given
worktreeSpawnCount = 0
mock.module("node:child_process", () => ({
execFileSync: () => {
worktreeSpawnCount += 1
return TEST_DIR
},
}))
const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs")
clearWorktreeCache()
// when
const firstPath = detectWorktreePath("/some/dir")
const secondPath = detectWorktreePath("/some/dir")
clearWorktreeCache()
const thirdPath = detectWorktreePath("/some/dir")
// then
expect(firstPath).toBe(TEST_DIR)
expect(secondPath).toBe(TEST_DIR)
expect(thirdPath).toBe(TEST_DIR)
expect(worktreeSpawnCount).toBe(2)
})
it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", async () => {
// given // given
const projectDir = join(TEST_DIR, "project") const projectDir = join(TEST_DIR, "project")
const childDir = join(projectDir, "apps", "cli") const childDir = join(projectDir, "apps", "cli")
@@ -32,6 +55,8 @@ describe("project-discovery-dirs", () => {
mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true })
mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true })
const { findProjectOpencodeSkillDirs } = await import("./project-discovery-dirs")
// when // when
const directories = findProjectOpencodeSkillDirs(childDir) const directories = findProjectOpencodeSkillDirs(childDir)
@@ -43,13 +68,15 @@ describe("project-discovery-dirs", () => {
]) ])
}) })
it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", () => { it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", async () => {
// given // given
const projectDir = join(TEST_DIR, "project") const projectDir = join(TEST_DIR, "project")
const childDir = join(projectDir, "packages", "tool") const childDir = join(projectDir, "packages", "tool")
mkdirSync(join(projectDir, ".opencode", "commands"), { recursive: true }) mkdirSync(join(projectDir, ".opencode", "commands"), { recursive: true })
mkdirSync(join(TEST_DIR, ".opencode", "command"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "command"), { recursive: true })
const { findProjectOpencodeCommandDirs } = await import("./project-discovery-dirs")
// when // when
const directories = findProjectOpencodeCommandDirs(childDir) const directories = findProjectOpencodeCommandDirs(childDir)
@@ -60,13 +87,15 @@ describe("project-discovery-dirs", () => {
]) ])
}) })
it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", () => { it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", async () => {
// given // given
const projectDir = join(TEST_DIR, "project") const projectDir = join(TEST_DIR, "project")
const childDir = join(projectDir, "src", "nested") const childDir = join(projectDir, "src", "nested")
mkdirSync(join(projectDir, ".claude", "skills"), { recursive: true }) mkdirSync(join(projectDir, ".claude", "skills"), { recursive: true })
mkdirSync(join(TEST_DIR, ".agents", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".agents", "skills"), { recursive: true })
const { findProjectAgentsSkillDirs, findProjectClaudeSkillDirs } = await import("./project-discovery-dirs")
// when // when
const claudeDirectories = findProjectClaudeSkillDirs(childDir) const claudeDirectories = findProjectClaudeSkillDirs(childDir)
const agentsDirectories = findProjectAgentsSkillDirs(childDir) const agentsDirectories = findProjectAgentsSkillDirs(childDir)
@@ -76,17 +105,20 @@ describe("project-discovery-dirs", () => {
expect(agentsDirectories).toEqual([canonicalPath(join(TEST_DIR, ".agents", "skills"))]) expect(agentsDirectories).toEqual([canonicalPath(join(TEST_DIR, ".agents", "skills"))])
}) })
it("#given a stop directory #when finding ancestor dirs #then it does not scan beyond the stop boundary", () => { it("#given a stop directory #when finding ancestor dirs #then it does not scan beyond the stop boundary", async () => {
// given // given
const projectDir = join(TEST_DIR, "project") const projectDir = join(TEST_DIR, "project")
const childDir = join(projectDir, "apps", "cli") const childDir = join(projectDir, "apps", "cli")
mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true })
mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true })
const { findProjectOpencodeSkillDirs } = await import("./project-discovery-dirs")
// when // when
const directories = findProjectOpencodeSkillDirs(childDir, projectDir) const directories = findProjectOpencodeSkillDirs(childDir, projectDir)
// then // then
expect(directories).toEqual([canonicalPath(join(projectDir, ".opencode", "skills"))]) expect(directories).toEqual([canonicalPath(join(projectDir, ".opencode", "skills"))])
}) })
}) })
+18 -3
View File
@@ -2,6 +2,8 @@ import { execFileSync } from "node:child_process"
import { existsSync, realpathSync } from "node:fs" import { existsSync, realpathSync } from "node:fs"
import { dirname, join, resolve } from "node:path" import { dirname, join, resolve } from "node:path"
const worktreePathCache = new Map<string, string | undefined>()
function normalizePath(path: string): string { function normalizePath(path: string): string {
const resolvedPath = resolve(path) const resolvedPath = resolve(path)
if (!existsSync(resolvedPath)) { if (!existsSync(resolvedPath)) {
@@ -49,15 +51,28 @@ function findAncestorDirectories(
} }
} }
function detectWorktreePath(directory: string): string | undefined { export function clearWorktreeCache(): void {
worktreePathCache.clear()
}
export function detectWorktreePath(directory: string): string | undefined {
const resolvedDirectory = resolve(directory)
if (worktreePathCache.has(resolvedDirectory)) {
return worktreePathCache.get(resolvedDirectory)
}
try { try {
return execFileSync("git", ["rev-parse", "--show-toplevel"], { const worktreePath = execFileSync("git", ["rev-parse", "--show-toplevel"], {
cwd: directory, cwd: resolvedDirectory,
encoding: "utf-8", encoding: "utf-8",
timeout: 5000, timeout: 5000,
stdio: ["pipe", "pipe", "pipe"], stdio: ["pipe", "pipe", "pipe"],
}).trim() }).trim()
worktreePathCache.set(resolvedDirectory, worktreePath)
return worktreePath
} catch { } catch {
worktreePathCache.set(resolvedDirectory, undefined)
return undefined return undefined
} }
} }