diff --git a/src/cli/doctor/checks/model-resolution-details.ts b/src/cli/doctor/checks/model-resolution-details.ts index 7489a2c2..e9665547 100644 --- a/src/cli/doctor/checks/model-resolution-details.ts +++ b/src/cli/doctor/checks/model-resolution-details.ts @@ -1,3 +1,6 @@ +import { join } from "node:path" + +import { getOpenCodeCacheDir } from "../../../shared" import type { AvailableModelsInfo, ModelResolutionInfo, OmoConfig } from "./model-resolution-types" import { formatModelWithVariant, getCategoryEffectiveVariant, getEffectiveVariant } from "./model-resolution-variant" @@ -7,6 +10,7 @@ export function buildModelResolutionDetails(options: { config: OmoConfig }): string[] { const details: string[] = [] + const cacheFile = join(getOpenCodeCacheDir(), "models.json") details.push("═══ Available Models (from cache) ═══") details.push("") @@ -16,7 +20,7 @@ export function buildModelResolutionDetails(options: { ` Sample: ${options.available.providers.slice(0, 6).join(", ")}${options.available.providers.length > 6 ? "..." : ""}` ) details.push(` Total models: ${options.available.modelCount}`) - details.push(` Cache: ~/.cache/opencode/models.json`) + details.push(` Cache: ${cacheFile}`) details.push(` ℹ Runtime: only connected providers used`) details.push(` Refresh: opencode models --refresh`) } else { diff --git a/src/features/background-agent/message-dir.ts b/src/features/background-agent/message-dir.ts index 3e8f56a4..138f5dab 100644 --- a/src/features/background-agent/message-dir.ts +++ b/src/features/background-agent/message-dir.ts @@ -1,18 +1 @@ -import { existsSync, readdirSync } from "node:fs" -import { join } from "node:path" - -import { MESSAGE_STORAGE } from "../hook-message-injector" - -export function getMessageDir(sessionID: string): string | null { - if (!existsSync(MESSAGE_STORAGE)) return null - - const directPath = join(MESSAGE_STORAGE, sessionID) - if (existsSync(directPath)) return directPath - - for (const dir of readdirSync(MESSAGE_STORAGE)) { - const sessionPath = join(MESSAGE_STORAGE, dir, sessionID) - if (existsSync(sessionPath)) return sessionPath - } - - return null -} +export { getMessageDir } from "./message-storage-locator" diff --git a/src/shared/git-worktree/collect-git-diff-stats.test.ts b/src/shared/git-worktree/collect-git-diff-stats.test.ts index 678d2f67..5aab6e25 100644 --- a/src/shared/git-worktree/collect-git-diff-stats.test.ts +++ b/src/shared/git-worktree/collect-git-diff-stats.test.ts @@ -15,7 +15,11 @@ const execFileSyncMock = mock((file: string, args: string[], _opts: { cwd?: stri } if (subcommand === "status") { - return " M file.ts\n" + return " M file.ts\n?? new-file.ts\n" + } + + if (subcommand === "ls-files") { + return "new-file.ts\n" } throw new Error(`unexpected args: ${args.join(" ")}`) @@ -38,7 +42,7 @@ describe("collectGitDiffStats", () => { //#then expect(execSyncMock).not.toHaveBeenCalled() - expect(execFileSyncMock).toHaveBeenCalledTimes(2) + expect(execFileSyncMock).toHaveBeenCalledTimes(3) const [firstCallFile, firstCallArgs, firstCallOpts] = execFileSyncMock.mock .calls[0]! as unknown as [string, string[], { cwd?: string }] @@ -54,6 +58,13 @@ describe("collectGitDiffStats", () => { expect(secondCallOpts.cwd).toBe(directory) expect(secondCallArgs.join(" ")).not.toContain(directory) + const [thirdCallFile, thirdCallArgs, thirdCallOpts] = execFileSyncMock.mock + .calls[2]! as unknown as [string, string[], { cwd?: string }] + expect(thirdCallFile).toBe("git") + expect(thirdCallArgs).toEqual(["ls-files", "--others", "--exclude-standard"]) + expect(thirdCallOpts.cwd).toBe(directory) + expect(thirdCallArgs.join(" ")).not.toContain(directory) + expect(result).toEqual([ { path: "file.ts", @@ -61,6 +72,12 @@ describe("collectGitDiffStats", () => { removed: 2, status: "modified", }, + { + path: "new-file.ts", + added: 0, + removed: 0, + status: "added", + }, ]) }) }) diff --git a/src/shared/git-worktree/collect-git-diff-stats.ts b/src/shared/git-worktree/collect-git-diff-stats.ts index 49a98fe2..546e8bfa 100644 --- a/src/shared/git-worktree/collect-git-diff-stats.ts +++ b/src/shared/git-worktree/collect-git-diff-stats.ts @@ -12,8 +12,6 @@ export function collectGitDiffStats(directory: string): GitFileStat[] { stdio: ["pipe", "pipe", "pipe"], }).trim() - if (!diffOutput) return [] - const statusOutput = execFileSync("git", ["status", "--porcelain"], { cwd: directory, encoding: "utf-8", @@ -21,8 +19,27 @@ export function collectGitDiffStats(directory: string): GitFileStat[] { stdio: ["pipe", "pipe", "pipe"], }).trim() + const untrackedOutput = execFileSync("git", ["ls-files", "--others", "--exclude-standard"], { + cwd: directory, + encoding: "utf-8", + timeout: 5000, + stdio: ["pipe", "pipe", "pipe"], + }).trim() + + const untrackedNumstat = untrackedOutput + ? untrackedOutput + .split("\n") + .filter(Boolean) + .map((filePath) => `0\t0\t${filePath}`) + .join("\n") + : "" + + const combinedNumstat = [diffOutput, untrackedNumstat].filter(Boolean).join("\n").trim() + + if (!combinedNumstat) return [] + const statusMap = parseGitStatusPorcelain(statusOutput) - return parseGitDiffNumstat(diffOutput, statusMap) + return parseGitDiffNumstat(combinedNumstat, statusMap) } catch { return [] }