← back to jpdlr__hydra

Function bodies 224 total

All specs Real LLM only Function bodies
AgentManager.preflight method · typescript · L71-L76 (6 LOC)
electron/agents/AgentManager.ts
  async preflight(providerId: ProviderId = 'claude'): Promise<{
    ok: boolean
    claudePath: string | null
    version: string | null
    error: string | null
  }> {
AgentManager.create method · typescript · L90-L132 (43 LOC)
electron/agents/AgentManager.ts
  create(payload: CreateAgentPayload): AgentState {
    const id = randomUUID().slice(0, 8)
    const now = new Date().toISOString()

    const state: AgentState = {
      id,
      name: payload.name,
      projectDir: payload.projectDir,
      provider: payload.provider,
      model: payload.model,
      reasoningEffort: payload.reasoningEffort,
      yolo: payload.yolo,
      isManager: payload.isManager ?? false,
      sessionId: payload.resumeSessionId ?? null,
      initialPrompt: payload.initialPrompt,
      createdAt: now,
      status: 'starting',
      pid: null,
      restartCount: 0,
      startedAt: null
    }

    const managed: ManagedAgent = {
      state,
      pty: null,
      outputBuffer: [],
      killTimeout: null,
      submitQueue: Promise.resolve(),
      cols: DEFAULT_PTY_COLS,
      rows: DEFAULT_PTY_ROWS,
      source: 'hydra',
      latestUserPrompt: payload.initialPrompt.trim() || null,
      sessionSyncTimer: null,
      sessionDiscoveryAttempts: 0,
     
AgentManager.importSessions method · typescript · L134-L181 (48 LOC)
electron/agents/AgentManager.ts
  importSessions(sessions: ClaudeSessionSummary[], defaultModel: ModelId, defaultProvider: ProviderId = 'claude'): number {
    let imported = 0

    for (const session of sessions) {
      if (!session.sessionId || !session.projectPath) continue

      const exists = Array.from(this.agents.values()).some(
        (managed) => managed.state.sessionId === session.sessionId
      )
      if (exists) continue

      const state: AgentState = {
        id: this.buildImportedAgentId(session.sessionId),
        name: this.buildImportedAgentName(session),
        projectDir: session.projectPath,
        provider: defaultProvider,
        model: defaultModel,
        yolo: false,
        isManager: false,
        sessionId: session.sessionId,
        initialPrompt: '',
        createdAt: session.createdAt || new Date().toISOString(),
        status: 'idle',
        pid: null,
        restartCount: 0,
        startedAt: null
      }

      this.agents.set(state.id, {
        state,
        pty:
AgentManager.hydrateWorkspaceAgents method · typescript · L183-L229 (47 LOC)
electron/agents/AgentManager.ts
  hydrateWorkspaceAgents(agents: PersistedWorkspaceAgent[]): number {
    let restored = 0
    for (const persisted of agents) {
      if (!persisted.id || !persisted.projectDir) continue

      const id = this.buildHydraAgentId(persisted.id)
      const alreadyHasSession = persisted.sessionId
        ? Array.from(this.agents.values()).some((managed) => managed.state.sessionId === persisted.sessionId)
        : false
      if (alreadyHasSession) continue

      const state: AgentState = {
        id,
        name: persisted.name,
        projectDir: persisted.projectDir,
        provider: persisted.provider ?? 'claude',
        model: persisted.model,
        yolo: persisted.yolo,
        isManager: persisted.isManager ?? false,
        sessionId: persisted.sessionId,
        initialPrompt: '',
        createdAt: persisted.createdAt,
        status: 'idle',
        pid: null,
        restartCount: 0,
        startedAt: null
      }

      this.agents.set(id, {
        state,
        pt
AgentManager.exportWorkspaceAgents method · typescript · L231-L245 (15 LOC)
electron/agents/AgentManager.ts
  exportWorkspaceAgents(): PersistedWorkspaceAgent[] {
    return Array.from(this.agents.values())
      .filter((managed) => managed.source === 'hydra')
      .map((managed) => ({
        id: managed.state.id,
        name: managed.state.name,
        projectDir: managed.state.projectDir,
        provider: managed.state.provider,
        model: managed.state.model,
        yolo: managed.state.yolo,
        isManager: managed.state.isManager,
        sessionId: managed.state.sessionId,
        createdAt: managed.state.createdAt
      }))
  }
AgentManager.activeCount method · typescript · L247-L255 (9 LOC)
electron/agents/AgentManager.ts
  activeCount(): number {
    let count = 0
    for (const managed of this.agents.values()) {
      if (managed.pty || managed.state.status === 'running' || managed.state.status === 'starting') {
        count++
      }
    }
    return count
  }
AgentManager.buildImportedAgentId method · typescript · L257-L267 (11 LOC)
electron/agents/AgentManager.ts
  private buildImportedAgentId(sessionId: string): string {
    const shortId = sessionId.slice(0, 8)
    const baseId = `sess-${shortId}`
    if (!this.agents.has(baseId)) return baseId

    let suffix = 2
    while (this.agents.has(`${baseId}-${suffix}`)) {
      suffix++
    }
    return `${baseId}-${suffix}`
  }
Repobility analyzer · published findings · https://repobility.com
AgentManager.generateName method · typescript · L269-L281 (13 LOC)
electron/agents/AgentManager.ts
  static generateName(prompt: string, projectDir: string): string {
    const cleaned = prompt
      .replace(/\s+/g, ' ')
      .trim()
      .replace(/^<[^>]+>/, '')

    if (cleaned) {
      return cleaned.length > 44 ? `${cleaned.slice(0, 44)}...` : cleaned
    }

    const projectName = basename(projectDir) || 'Agent'
    return `${projectName} ${randomUUID().slice(0, 6)}`
  }
AgentManager.buildHydraAgentId method · typescript · L287-L295 (9 LOC)
electron/agents/AgentManager.ts
  private buildHydraAgentId(preferredId: string): string {
    if (!this.agents.has(preferredId)) return preferredId

    let suffix = 2
    while (this.agents.has(`${preferredId}-${suffix}`)) {
      suffix++
    }
    return `${preferredId}-${suffix}`
  }
AgentManager.killPtyProcess method · typescript · L302-L308 (7 LOC)
electron/agents/AgentManager.ts
  private killPtyProcess(pty: IPty, force: boolean): void {
    if (process.platform === 'win32') {
      pty.kill()
      return
    }
    pty.kill(force ? 'SIGKILL' : 'SIGTERM')
  }
AgentManager.spawnProcess method · typescript · L310-L375 (66 LOC)
electron/agents/AgentManager.ts
  private spawnProcess(managed: ManagedAgent): void {
    const provider = getProvider(managed.state.provider)
    const cmd = this.providerPaths.get(managed.state.provider) || provider.command
    const args = this.buildArgs(managed.state)

    try {
      const pty = ptySpawn(cmd, args, {
        name: 'xterm-256color',
        cols: managed.cols,
        rows: managed.rows,
        cwd: managed.state.projectDir,
        env: {
          ...process.env,
          TERM: 'xterm-256color',
          FORCE_COLOR: '1'
        }
      })

      managed.pty = pty
      managed.state.pid = pty.pid
      managed.state.startedAt = new Date().toISOString()
      this.updateStatus(managed.state.id, 'running')
      this.startSessionDiscovery(managed)

      pty.onData((data: string) => {
        this.captureSessionIdFromOutput(managed, data)

        // Buffer output
        const lines = data.split('\n')
        managed.outputBuffer.push(...lines)
        if (managed.outputBuffer.length > MAX_B
AgentManager.updateStatus method · typescript · L378-L387 (10 LOC)
electron/agents/AgentManager.ts
  private updateStatus(agentId: string, status: AgentStatus): void {
    const managed = this.agents.get(agentId)
    if (!managed) return
    managed.state.status = status
    this.emit('status', {
      agentId,
      status,
      sessionId: managed.state.sessionId
    })
  }
AgentManager.updateSessionId method · typescript · L389-L398 (10 LOC)
electron/agents/AgentManager.ts
  private updateSessionId(managed: ManagedAgent, sessionId: string): void {
    const normalized = sessionId.trim()
    if (!normalized || managed.state.sessionId === normalized) return
    managed.state.sessionId = normalized
    this.emit('status', {
      agentId: managed.state.id,
      status: managed.state.status,
      sessionId: managed.state.sessionId
    })
  }
AgentManager.captureSessionIdFromOutput method · typescript · L400-L421 (22 LOC)
electron/agents/AgentManager.ts
  private captureSessionIdFromOutput(managed: ManagedAgent, data: string): void {
    if (managed.state.sessionId) return

    const provider = getProvider(managed.state.provider)

    // Try provider-specific session ID regex
    if (provider.sessionIdRegex) {
      const directMatch = data.match(provider.sessionIdRegex)
      if (directMatch?.[1]) {
        this.updateSessionId(managed, directMatch[1])
        return
      }
    }

    // Fallback: generic UUID pattern
    const uuidMatch = data.match(
      /\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/i
    )
    if (uuidMatch?.[0]) {
      this.updateSessionId(managed, uuidMatch[0])
    }
  }
AgentManager.startSessionDiscovery method · typescript · L423-L432 (10 LOC)
electron/agents/AgentManager.ts
  private startSessionDiscovery(managed: ManagedAgent): void {
    const provider = getProvider(managed.state.provider)
    if (!provider.supportsResume) return
    if (managed.state.sessionId || managed.source !== 'hydra') return
    this.stopSessionDiscovery(managed)
    this.probeSessionIdFromCatalog(managed, { forceRefresh: true })
    if (!managed.state.sessionId) {
      this.scheduleSessionDiscovery(managed)
    }
  }
Repobility — same analyzer, your code, free for public repos · /scan/
AgentManager.stopSessionDiscovery method · typescript · L434-L439 (6 LOC)
electron/agents/AgentManager.ts
  private stopSessionDiscovery(managed: ManagedAgent): void {
    if (!managed.sessionSyncTimer) return
    clearTimeout(managed.sessionSyncTimer)
    managed.sessionSyncTimer = null
    managed.sessionDiscoveryAttempts = 0
  }
AgentManager.probeSessionIdFromCatalog method · typescript · L463-L511 (49 LOC)
electron/agents/AgentManager.ts
  private probeSessionIdFromCatalog(managed: ManagedAgent, options: { forceRefresh?: boolean } = {}): void {
    if (managed.state.sessionId || managed.source !== 'hydra') return
    if (!managed.state.projectDir) return

    try {
      const sessions = this.sessionCatalog.listSessions({
        limit: 120,
        projectPathPrefix: managed.state.projectDir,
        forceRefresh: options.forceRefresh === true
      })
      if (sessions.length === 0) return

      const usedSessionIds = new Set(
        Array.from(this.agents.values())
          .map((agent) => agent.state.sessionId)
          .filter((value): value is string => !!value)
      )

      const startedAtMs = Date.parse(managed.state.startedAt ?? managed.state.createdAt)
      const promptHint = this.normalizePromptHint(managed.latestUserPrompt)

      const candidates = sessions.filter((session) => !usedSessionIds.has(session.sessionId))
      if (candidates.length === 0) return

      const hinted = promptHint
        
AgentManager.normalizePromptHint method · typescript · L513-L520 (8 LOC)
electron/agents/AgentManager.ts
  private normalizePromptHint(input: string | null): string {
    if (!input) return ''
    return input
      .replace(/\s+/g, ' ')
      .trim()
      .toLowerCase()
      .slice(0, SESSION_HINT_MAX_LENGTH)
  }
AgentManager.remove method · typescript · L546-L556 (11 LOC)
electron/agents/AgentManager.ts
  remove(agentId: string): boolean {
    const managed = this.agents.get(agentId)
    if (!managed) return false
    this.stopSessionDiscovery(managed)
    this.kill(agentId)
    if (managed.killTimeout) {
      clearTimeout(managed.killTimeout)
      managed.killTimeout = null
    }
    return this.agents.delete(agentId)
  }
AgentManager.clearTimeout method · typescript · L552-L582 (31 LOC)
electron/agents/AgentManager.ts
      clearTimeout(managed.killTimeout)
      managed.killTimeout = null
    }
    return this.agents.delete(agentId)
  }

  restart(agentId: string): AgentState | null {
    const managed = this.agents.get(agentId)
    if (!managed) return null

    // Kill existing process
    if (managed.pty) {
      try {
        this.killPtyProcess(managed.pty, true)
      } catch {
        // Already dead
      }
      managed.pty = null
    }

    managed.state.restartCount++
    managed.state.status = 'starting'
    managed.outputBuffer = []
    managed.submitQueue = Promise.resolve()
    managed.notifiedIdle = false
    managed.lastOutputAt = 0
    this.stopSessionDiscovery(managed)

    this.spawnProcess(managed)
    return { ...managed.state }
  }
AgentManager.toggleYolo method · typescript · L584-L591 (8 LOC)
electron/agents/AgentManager.ts
  toggleYolo(agentId: string, yolo: boolean): AgentState | null {
    const managed = this.agents.get(agentId)
    if (!managed) return null

    managed.state.yolo = yolo
    // Restart with new flag, preserving session
    return this.restart(agentId)
  }
AgentManager.setTimeout method · typescript · L611-L624 (14 LOC)
electron/agents/AgentManager.ts
          setTimeout(resolve, INPUT_SUBMIT_DELAY_MS)
        })
        if (managed.pty !== pty) return
        pty.write('\r')
      })

    return true
  }

  private ensureProcess(managed: ManagedAgent): boolean {
    if (managed.pty) return true
    this.spawnProcess(managed)
    return !!managed.pty
  }
AgentManager.setSessionId method · typescript · L674-L682 (9 LOC)
electron/agents/AgentManager.ts
  setSessionId(agentId: string, sessionId: string): void {
    const managed = this.agents.get(agentId)
    if (managed) {
      this.updateSessionId(managed, sessionId)
      if (managed.state.sessionId) {
        this.stopSessionDiscovery(managed)
      }
    }
  }
Same scanner, your repo: https://repobility.com — Repobility
AgentManager.resize method · typescript · L684-L695 (12 LOC)
electron/agents/AgentManager.ts
  resize(agentId: string, cols: number, rows: number): void {
    const managed = this.agents.get(agentId)
    if (!managed) return
    if (cols < 2 || rows < 2) return

    managed.cols = cols
    managed.rows = rows

    if (managed.pty) {
      managed.pty.resize(cols, rows)
    }
  }
AgentManager.killAll method · typescript · L697-L719 (23 LOC)
electron/agents/AgentManager.ts
  killAll(): void {
    if (this.activityPollInterval) {
      clearInterval(this.activityPollInterval)
      this.activityPollInterval = null
    }
    for (const [id] of this.agents) {
      this.kill(id)
    }

    // Force kill stragglers after timeout
    setTimeout(() => {
      for (const [, managed] of this.agents) {
        this.stopSessionDiscovery(managed)
        if (managed.pty) {
          try {
            this.killPtyProcess(managed.pty, true)
          } catch {
            // Already dead
          }
        }
      }
    }, GRACEFUL_KILL_TIMEOUT + 1000)
  }
AgentManager.clearInterval method · typescript · L699-L704 (6 LOC)
electron/agents/AgentManager.ts
      clearInterval(this.activityPollInterval)
      this.activityPollInterval = null
    }
    for (const [id] of this.agents) {
      this.kill(id)
    }
AgentManager.setTimeout method · typescript · L707-L718 (12 LOC)
electron/agents/AgentManager.ts
    setTimeout(() => {
      for (const [, managed] of this.agents) {
        this.stopSessionDiscovery(managed)
        if (managed.pty) {
          try {
            this.killPtyProcess(managed.pty, true)
          } catch {
            // Already dead
          }
        }
      }
    }, GRACEFUL_KILL_TIMEOUT + 1000)
AgentManager.getProjectDirs method · typescript · L721-L727 (7 LOC)
electron/agents/AgentManager.ts
  getProjectDirs(): string[] {
    const dirs = new Set<string>()
    for (const [, managed] of this.agents) {
      dirs.add(managed.state.projectDir)
    }
    return Array.from(dirs)
  }
resolveCommandPath function · typescript · L34-L46 (13 LOC)
electron/agents/providers.ts
function resolveCommandPath(command: string): string | null {
  const locator = process.platform === 'win32' ? 'where' : 'which'
  try {
    const output = execFileSync(locator, [command], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] })
    const firstLine = output
      .split(/\r?\n/)
      .map((line) => line.trim())
      .find((line) => line.length > 0)
    return firstLine ?? null
  } catch {
    return null
  }
}
readVersion function · typescript · L48-L63 (16 LOC)
electron/agents/providers.ts
function readVersion(commandPath: string, command: string): string | null {
  const targets = commandPath === command ? [commandPath] : [command, commandPath]
  for (const target of targets) {
    try {
      const output = execFileSync(target, ['--version'], {
        encoding: 'utf-8',
        timeout: 10000,
        stdio: ['ignore', 'pipe', 'pipe']
      }).trim()
      if (output.length > 0) return output
    } catch {
      continue
    }
  }
  return null
}
runPreflight function · typescript · L65-L82 (18 LOC)
electron/agents/providers.ts
function runPreflight(command: string, missingError: string): ProviderPreflightResult {
  const path = resolveCommandPath(command)
  if (!path) {
    return {
      ok: false,
      path: null,
      version: null,
      error: missingError
    }
  }

  return {
    ok: true,
    path,
    version: readVersion(path, command),
    error: null
  }
}
Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
ConfigStore.constructor method · typescript · L11-L16 (6 LOC)
electron/config/ConfigStore.ts
  constructor() {
    const userDataPath = app.getPath('userData')
    mkdirSync(userDataPath, { recursive: true })
    this.configPath = join(userDataPath, 'config.json')
    this.config = this.load()
  }
ConfigStore.mkdirSync method · typescript · L13-L30 (18 LOC)
electron/config/ConfigStore.ts
    mkdirSync(userDataPath, { recursive: true })
    this.configPath = join(userDataPath, 'config.json')
    this.config = this.load()
  }

  private load(): AppConfig {
    try {
      if (existsSync(this.configPath)) {
        const raw = readFileSync(this.configPath, 'utf-8')
        const parsed = JSON.parse(raw)
        return { ...DEFAULT_CONFIG, ...parsed }
      }
    } catch {
      // Corrupted config — reset to defaults
    }
    this.save(DEFAULT_CONFIG)
    return { ...DEFAULT_CONFIG }
  }
ConfigStore.save method · typescript · L42-L48 (7 LOC)
electron/config/ConfigStore.ts
  private save(config: AppConfig): void {
    try {
      writeFileSync(this.configPath, JSON.stringify(config, null, 2), 'utf-8')
    } catch (err) {
      console.error('Failed to save config:', err)
    }
  }
assertWithinProject function · typescript · L39-L46 (8 LOC)
electron/fs/FileSystemService.ts
function assertWithinProject(filePath: string, projectDir: string): void {
  const resolved = resolve(filePath)
  const resolvedProject = resolve(projectDir)
  const rel = relative(resolvedProject, resolved)
  if (rel.startsWith('..') || resolve(resolvedProject, rel) !== resolved) {
    throw new Error('Path traversal denied')
  }
}
FileSystemService.readDir method · typescript · L57-L80 (24 LOC)
electron/fs/FileSystemService.ts
  async readDir(dirPath: string, projectDir: string): Promise<FsDirEntry[]> {
    const fullPath = resolve(projectDir, dirPath)
    assertWithinProject(fullPath, projectDir)

    const names = await readdir(fullPath)
    const result: FsDirEntry[] = []

    for (const name of names) {
      if (IGNORED_NAMES.has(name)) continue
      if (name.startsWith('.') && name !== '.env.example') continue
      const info = await stat(join(fullPath, name)).catch(() => null)
      if (!info) continue
      if (info.isFile() || info.isDirectory()) {
        result.push({ name, isDirectory: info.isDirectory() })
      }
    }

    result.sort((a, b) => {
      if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1
      return a.name.localeCompare(b.name)
    })

    return result
  }
FileSystemService.assertWithinProject method · typescript · L59-L72 (14 LOC)
electron/fs/FileSystemService.ts
    assertWithinProject(fullPath, projectDir)

    const names = await readdir(fullPath)
    const result: FsDirEntry[] = []

    for (const name of names) {
      if (IGNORED_NAMES.has(name)) continue
      if (name.startsWith('.') && name !== '.env.example') continue
      const info = await stat(join(fullPath, name)).catch(() => null)
      if (!info) continue
      if (info.isFile() || info.isDirectory()) {
        result.push({ name, isDirectory: info.isDirectory() })
      }
    }
FileSystemService.assertWithinProject method · typescript · L101-L142 (42 LOC)
electron/fs/FileSystemService.ts
    assertWithinProject(fullPath, projectDir)
    await writeFile(fullPath, content, 'utf-8')
  }

  async searchFiles(
    query: string,
    projectDir: string,
    maxResults = 100
  ): Promise<FsSearchResult[]> {
    if (!query.trim()) return []
    const lowerQuery = query.toLowerCase()
    const results: FsSearchResult[] = []

    const walk = async (dir: string): Promise<void> => {
      if (results.length >= maxResults) return
      let names: string[]
      try {
        names = await readdir(dir)
      } catch {
        return
      }
      for (const name of names) {
        if (results.length >= maxResults) return
        if (IGNORED_NAMES.has(name)) continue
        if (name.startsWith('.')) continue
        const fullPath = join(dir, name)
        const relPath = relative(projectDir, fullPath).replaceAll('\\', '/')
        const info = await stat(fullPath).catch(() => null)
        if (!info) continue
        if (info.isDirectory()) {
          await walk(fullPath)
      
FileSystemService.startWatch method · typescript · L144-L170 (27 LOC)
electron/fs/FileSystemService.ts
  startWatch(
    agentId: string,
    projectDir: string,
    onEvent: (payload: FsWatchEventPayload) => void
  ): void {
    this.stopWatch(agentId)

    let debounceTimer: ReturnType<typeof setTimeout> | null = null

    const watcher = watch(projectDir, { recursive: true }, (eventType, filename) => {
      if (!filename) return
      // Ignore changes in filtered directories
      const parts = filename.split('/')
      if (parts.some((p) => IGNORED_NAMES.has(p))) return

      if (debounceTimer) clearTimeout(debounceTimer)
      debounceTimer = setTimeout(() => {
        onEvent({
          agentId,
          eventType: eventType === 'rename' ? 'rename' : 'change',
          path: filename
        })
      }, 300)
    })

    this.watchers.set(agentId, watcher)
  }
Repobility analyzer · published findings · https://repobility.com
FileSystemService.onEvent method · typescript · L161-L178 (18 LOC)
electron/fs/FileSystemService.ts
        onEvent({
          agentId,
          eventType: eventType === 'rename' ? 'rename' : 'change',
          path: filename
        })
      }, 300)
    })

    this.watchers.set(agentId, watcher)
  }

  stopWatch(agentId: string): void {
    const existing = this.watchers.get(agentId)
    if (existing) {
      existing.close()
      this.watchers.delete(agentId)
    }
  }
run function · typescript · L6-L16 (11 LOC)
electron/git/GitService.ts
function run(cwd: string, args: string[]): Promise<string> {
  return new Promise((resolve, reject) => {
    execFile('git', args, { cwd, maxBuffer: 1024 * 1024, timeout: 15000 }, (err, stdout, stderr) => {
      if (err) {
        reject(new Error(stderr.trim() || err.message))
      } else {
        resolve(stdout)
      }
    })
  })
}
runGh function · typescript · L18-L28 (11 LOC)
electron/git/GitService.ts
function runGh(cwd: string, args: string[]): Promise<string> {
  return new Promise((resolve, reject) => {
    execFile('gh', args, { cwd, maxBuffer: 5 * 1024 * 1024, timeout: 30000 }, (err, stdout, stderr) => {
      if (err) {
        reject(new Error(stderr.trim() || err.message))
      } else {
        resolve(stdout)
      }
    })
  })
}
parsePrNumber function · typescript · L48-L55 (8 LOC)
electron/git/GitService.ts
function parsePrNumber(identifier: string): number {
  const urlMatch = identifier.match(/\/pull\/(\d+)/)
  if (urlMatch) return parseInt(urlMatch[1])
  const cleaned = identifier.replace(/^#/, '').trim()
  const num = parseInt(cleaned)
  if (isNaN(num)) throw new Error(`Invalid PR identifier: ${identifier}`)
  return num
}
extractFileDiff function · typescript · L57-L64 (8 LOC)
electron/git/GitService.ts
function extractFileDiff(fullDiff: string, filePath: string): string {
  const escaped = filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  const regex = new RegExp(`diff --git a/${escaped} b/`)
  const startIdx = fullDiff.search(regex)
  if (startIdx === -1) return ''
  const nextDiff = fullDiff.indexOf('\ndiff --git ', startIdx + 1)
  return nextDiff === -1 ? fullDiff.slice(startIdx) : fullDiff.slice(startIdx, nextDiff)
}
GitService.getStatus method · typescript · L69-L106 (38 LOC)
electron/git/GitService.ts
  async getStatus(projectDir: string): Promise<GitStatus> {
    await assertGitRepo(projectDir)

    const branchOut = await run(projectDir, ['rev-parse', '--abbrev-ref', 'HEAD'])
    const branch = branchOut.trim()

    let ahead = 0
    let behind = 0
    try {
      const abOut = await run(projectDir, ['rev-list', '--left-right', '--count', `HEAD...@{upstream}`])
      const parts = abOut.trim().split(/\s+/)
      ahead = parseInt(parts[0]) || 0
      behind = parseInt(parts[1]) || 0
    } catch {
      // No upstream configured
    }

    const porcelain = await run(projectDir, ['status', '--porcelain=v1'])
    const modified: string[] = []
    const staged: string[] = []
    const untracked: string[] = []

    for (const line of porcelain.split('\n')) {
      if (!line) continue
      const x = line[0]
      const y = line[1]
      const file = line.slice(3)

      if (x === '?' && y === '?') {
        untracked.push(file)
      } else {
        if (x !== ' ' && x !== '?') staged.
GitService.getLog method · typescript · L108-L124 (17 LOC)
electron/git/GitService.ts
  async getLog(projectDir: string, limit = 20): Promise<GitCommit[]> {
    await assertGitRepo(projectDir)
    const out = await run(projectDir, [
      'log',
      `--max-count=${limit}`,
      '--format=%H%x00%s%x00%an%x00%aI'
    ])

    return out
      .trim()
      .split('\n')
      .filter(Boolean)
      .map((line) => {
        const [hash, message, author, date] = line.split('\0')
        return { hash: hash.slice(0, 8), message, author, date }
      })
  }
GitService.getDiff method · typescript · L126-L132 (7 LOC)
electron/git/GitService.ts
  async getDiff(projectDir: string, filePath?: string): Promise<string> {
    await assertGitRepo(projectDir)
    const args = ['diff']
    if (filePath) args.push('--', filePath)
    const out = await run(projectDir, args)
    return out.slice(0, 100_000)
  }
Repobility — same analyzer, your code, free for public repos · /scan/
GitService.listBranches method · typescript · L153-L181 (29 LOC)
electron/git/GitService.ts
  async listBranches(projectDir: string): Promise<GitBranch[]> {
    await assertGitRepo(projectDir)
    const out = await run(projectDir, [
      'branch', '-vv', '--format',
      '%(HEAD)%00%(refname:short)%00%(upstream:short)%00%(upstream:track,nobracket)'
    ])
    const branches: GitBranch[] = []
    for (const line of out.trim().split('\n')) {
      if (!line) continue
      const [head, name, upstream, track] = line.split('\0')
      let aheadOfUpstream = 0
      let behindUpstream = 0
      if (track) {
        const aheadMatch = track.match(/ahead (\d+)/)
        const behindMatch = track.match(/behind (\d+)/)
        if (aheadMatch) aheadOfUpstream = parseInt(aheadMatch[1])
        if (behindMatch) behindUpstream = parseInt(behindMatch[1])
      }
      branches.push({
        name,
        isCurrent: head === '*',
        isRemote: false,
        upstream: upstream || null,
        aheadOfUpstream,
        behindUpstream,
      })
    }
    return branches
  }
GitService.createBranch method · typescript · L188-L193 (6 LOC)
electron/git/GitService.ts
  async createBranch(projectDir: string, branchName: string, startPoint?: string): Promise<void> {
    await assertGitRepo(projectDir)
    const args = ['checkout', '-b', branchName]
    if (startPoint) args.push(startPoint)
    await run(projectDir, args)
  }
GitService.fetchPr method · typescript · L218-L259 (42 LOC)
electron/git/GitService.ts
  async fetchPr(projectDir: string, prIdentifier: string): Promise<GitPrDiff> {
    await assertGitRepo(projectDir)
    const prNumber = parsePrNumber(prIdentifier)

    const metaJson = await runGh(projectDir, [
      'pr', 'view', String(prNumber), '--json',
      'number,title,author,state,baseRefName,headRefName,body,url,additions,deletions,changedFiles,createdAt,updatedAt'
    ])
    const raw = JSON.parse(metaJson)
    const metadata: GitPrMetadata = {
      number: raw.number,
      title: raw.title,
      author: raw.author?.login ?? raw.author?.name ?? 'unknown',
      state: raw.state,
      baseRef: raw.baseRefName,
      headRef: raw.headRefName,
      body: raw.body ?? '',
      url: raw.url,
      additions: raw.additions,
      deletions: raw.deletions,
      changedFiles: raw.changedFiles,
      createdAt: raw.createdAt,
      updatedAt: raw.updatedAt,
    }

    const namesOutput = await runGh(projectDir, ['pr', 'diff', String(prNumber), '--name-only'])
    const fullD
page 1 / 5next ›