SLOPSHOPPER

branch-band

입력창 위에 현재 git 브랜치를 표시한다

newbandguardprocess
v0.1.0no licenseupdated 2026-10-15izel6446/claude-branch-band
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · branch-band
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM app ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
app
README

branch-band

Claude Code 입력창 위에 현재 git 레포지토리 이름과 브랜치를 표시하는 mod 예요.

[ im-ground-app-server ] feature/MP-2621
  • 레포지토리 이름은 뱃지(다크 모드용 antd blue 계열)로, 브랜치는 그 오른쪽에 표시해요.
  • 하위 폴더에서 세션을 열어도 git 최상위 폴더 이름이 나와요.
  • 세션 시작, Bash 실행 후, 턴이 끝날 때 브랜치를 다시 읽어요. 터미널에서 직접 checkout 한 경우에는 다음 턴이 끝나야 반영돼요.
  • git 리포지토리가 아니거나 detached HEAD 상태면 표시하지 않아요.

설치

Claude Code 세션 입력창에서 실행해요.

/plugin install branch-band --marketplace izel6446/claude-branch-band

Add marketplace? 에 y, 설치 범위는 user 를 고르면 이후 여는 모든 세션에 로드돼요. 이미 떠 있는 세션은 /reload-plugins 를 실행해요.

업데이트

리포지토리에 새 커밋을 올린 뒤 각 PC 에서 실행해요.

claude plugin update branch-band@bjh-mods

그다음 세션에서 /reload-plugins 를 실행해요.

구성

파일내용
.claude-plugin/plugin.jsonmod 정보
.claude-plugin/marketplace.json이 리포지토리를 marketplace 로 쓰기 위한 목록
hooks/register.tsxband 를 그리고 브랜치를 읽는 코드
types/index.d.tsmod 가 쓰는 상태 값의 타입
Source 2 files
hooks/register.tsx 66 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { BranchBandGit } from '../types'
5
6const git = atom({ plugin: 'branch-band', key: 'git' } as const, null)
7
8// 그리는 중에 git 을 부르면 렌더마다 프로세스가 뜨므로, 브랜치가 바뀔 수 있는 시점에만 다시 읽는다.
9async function refresh($: EngineInterface) {
10  try {
11    const top = await $.process.run(['git', 'rev-parse', '--show-toplevel'], { timeoutMs: 5000 })
12    const head = await $.process.run(['git', 'branch', '--show-current'], { timeoutMs: 5000 })
13    const root = top.exitCode === 0 ? top.stdout.trim() : ''
14    const branch = head.exitCode === 0 ? head.stdout.trim() : ''
15    // 하위 폴더에서 세션을 열어도 레포 이름이 나오도록 cwd 가 아니라 최상위 경로의 마지막 이름을 쓴다.
16    const repo = root.split('/').pop() ?? ''
17    const next: BranchBandGit | null = repo && branch ? { repo, branch } : null
18    await update($, git, () => next)
19  } catch {
20    await update($, git, () => null)
21  }
22}
23
24export const register: Register = on => {
25  on('session.start', async ($, e, next) => {
26    const result = await next(e)
27    await refresh($)
28    return result
29  })
30
31  // 사용자가 터미널에서 직접 checkout 한 경우도 다음 턴이 끝나면 반영된다.
32  on('turn.complete', async ($, e, next) => {
33    const result = await next(e)
34    await refresh($)
35    return result
36  })
37
38  // 도구 결과가 브랜치 조회를 기다리지 않도록 기다리지 않고 넘긴다.
39  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
40    const result = await next(e)
41    refresh($).catch(() => {})
42    return result
43  })
44
45  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
46    const current = await read($, git)
47
48    if (e.props.hasSurvey || current === null) {
49      return next(e)
50    }
51
52    const { Box, Text } = $.ui.resolve(e)
53
54    return (
55      <Box gap={1}>
56        {/* 다크 모드에서 antd 라이트 Tag 색은 너무 밝아서 antd 다크 blue Tag 계열로 맞췄다. */}
57        {/* 테두리를 두면 band 가 세 줄을 차지하고 Box 에는 radius 가 없어서, 둥근 모서리 없이 배경색으로만 구분한다. */}
58        <Box backgroundColor="#1a2f4d" paddingX={1}>
59          <Text color="#69b1ff">{current.repo}</Text>
60        </Box>
61        <Text>{current.branch}</Text>
62      </Box>
63    )
64  })
65}
66
types/index.d.ts 8 lines
1export type BranchBandGit = { repo: string; branch: string }
2
3declare module 'claude-code' {
4  interface PluginState {
5    'branch-band': { git: BranchBandGit | null }
6  }
7}
8