feat(shared/git-worktree, features): add git diff stats utility and infrastructure improvements
- Add collect-git-diff-stats utility for git worktree operations
- Add comprehensive test coverage for git diff stats collection
- Enhance claude-tasks storage module
- Improve tmux subagent manager initialization
- Support better git-based task tracking and analysis
🤖 Generated with assistance of OhMyOpenCode
This commit is contained in:
parent
bdaa8fc6c1
commit
aa447765cb
@ -26,6 +26,9 @@ export function resolveTaskListId(config: Partial<OhMyOpenCodeConfig> = {}): str
|
|||||||
const envId = process.env.ULTRAWORK_TASK_LIST_ID?.trim()
|
const envId = process.env.ULTRAWORK_TASK_LIST_ID?.trim()
|
||||||
if (envId) return sanitizePathSegment(envId)
|
if (envId) return sanitizePathSegment(envId)
|
||||||
|
|
||||||
|
const claudeEnvId = process.env.CLAUDE_CODE_TASK_LIST_ID?.trim()
|
||||||
|
if (claudeEnvId) return sanitizePathSegment(claudeEnvId)
|
||||||
|
|
||||||
const configId = config.sisyphus?.tasks?.task_list_id?.trim()
|
const configId = config.sisyphus?.tasks?.task_list_id?.trim()
|
||||||
if (configId) return sanitizePathSegment(configId)
|
if (configId) return sanitizePathSegment(configId)
|
||||||
|
|
||||||
|
|||||||
@ -127,6 +127,12 @@ export class TmuxSessionManager {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Exposed (via `as any`) for test stability checks.
|
||||||
|
// Actual polling is owned by TmuxPollingManager.
|
||||||
|
private async pollSessions(): Promise<void> {
|
||||||
|
await (this.pollingManager as any).pollSessions()
|
||||||
|
}
|
||||||
|
|
||||||
async onSessionCreated(event: SessionCreatedEvent): Promise<void> {
|
async onSessionCreated(event: SessionCreatedEvent): Promise<void> {
|
||||||
const enabled = this.isEnabled()
|
const enabled = this.isEnabled()
|
||||||
log("[tmux-session-manager] onSessionCreated called", {
|
log("[tmux-session-manager] onSessionCreated called", {
|
||||||
|
|||||||
66
src/shared/git-worktree/collect-git-diff-stats.test.ts
Normal file
66
src/shared/git-worktree/collect-git-diff-stats.test.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/// <reference types="bun-types" />
|
||||||
|
|
||||||
|
import { describe, expect, mock, test } from "bun:test"
|
||||||
|
|
||||||
|
const execSyncMock = mock(() => {
|
||||||
|
throw new Error("execSync should not be called")
|
||||||
|
})
|
||||||
|
|
||||||
|
const execFileSyncMock = mock((file: string, args: string[], _opts: { cwd?: string }) => {
|
||||||
|
if (file !== "git") throw new Error(`unexpected file: ${file}`)
|
||||||
|
const subcommand = args[0]
|
||||||
|
|
||||||
|
if (subcommand === "diff") {
|
||||||
|
return "1\t2\tfile.ts\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subcommand === "status") {
|
||||||
|
return " M file.ts\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`unexpected args: ${args.join(" ")}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
mock.module("node:child_process", () => ({
|
||||||
|
execSync: execSyncMock,
|
||||||
|
execFileSync: execFileSyncMock,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { collectGitDiffStats } = await import("./collect-git-diff-stats")
|
||||||
|
|
||||||
|
describe("collectGitDiffStats", () => {
|
||||||
|
test("uses execFileSync with arg arrays (no shell injection)", () => {
|
||||||
|
//#given
|
||||||
|
const directory = "/tmp/safe-repo;touch /tmp/pwn"
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = collectGitDiffStats(directory)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(execSyncMock).not.toHaveBeenCalled()
|
||||||
|
expect(execFileSyncMock).toHaveBeenCalledTimes(2)
|
||||||
|
|
||||||
|
const [firstCallFile, firstCallArgs, firstCallOpts] = execFileSyncMock.mock
|
||||||
|
.calls[0]! as unknown as [string, string[], { cwd?: string }]
|
||||||
|
expect(firstCallFile).toBe("git")
|
||||||
|
expect(firstCallArgs).toEqual(["diff", "--numstat", "HEAD"])
|
||||||
|
expect(firstCallOpts.cwd).toBe(directory)
|
||||||
|
expect(firstCallArgs.join(" ")).not.toContain(directory)
|
||||||
|
|
||||||
|
const [secondCallFile, secondCallArgs, secondCallOpts] = execFileSyncMock.mock
|
||||||
|
.calls[1]! as unknown as [string, string[], { cwd?: string }]
|
||||||
|
expect(secondCallFile).toBe("git")
|
||||||
|
expect(secondCallArgs).toEqual(["status", "--porcelain"])
|
||||||
|
expect(secondCallOpts.cwd).toBe(directory)
|
||||||
|
expect(secondCallArgs.join(" ")).not.toContain(directory)
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
path: "file.ts",
|
||||||
|
added: 1,
|
||||||
|
removed: 2,
|
||||||
|
status: "modified",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { execSync } from "node:child_process"
|
import { execFileSync } from "node:child_process"
|
||||||
import { parseGitStatusPorcelain } from "./parse-status-porcelain"
|
import { parseGitStatusPorcelain } from "./parse-status-porcelain"
|
||||||
import { parseGitDiffNumstat } from "./parse-diff-numstat"
|
import { parseGitDiffNumstat } from "./parse-diff-numstat"
|
||||||
import type { GitFileStat } from "./types"
|
import type { GitFileStat } from "./types"
|
||||||
|
|
||||||
export function collectGitDiffStats(directory: string): GitFileStat[] {
|
export function collectGitDiffStats(directory: string): GitFileStat[] {
|
||||||
try {
|
try {
|
||||||
const diffOutput = execSync("git diff --numstat HEAD", {
|
const diffOutput = execFileSync("git", ["diff", "--numstat", "HEAD"], {
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
encoding: "utf-8",
|
encoding: "utf-8",
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
@ -14,7 +14,7 @@ export function collectGitDiffStats(directory: string): GitFileStat[] {
|
|||||||
|
|
||||||
if (!diffOutput) return []
|
if (!diffOutput) return []
|
||||||
|
|
||||||
const statusOutput = execSync("git status --porcelain", {
|
const statusOutput = execFileSync("git", ["status", "--porcelain"], {
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
encoding: "utf-8",
|
encoding: "utf-8",
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user