pr-docent 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +214 -0
- package/README.md +131 -93
- package/bin/pr-docent.mjs +32 -4
- package/host/claude.mjs +81 -0
- package/host/native.mjs +3 -2
- package/host/pr-docent-host.mjs +46 -64
- package/host/render-short.mjs +96 -0
- package/host/short-cli.mjs +56 -0
- package/host/short.mjs +71 -0
- package/package.json +7 -2
- package/scripts/check-short.mjs +37 -0
- package/scripts/short-prompt.md +63 -0
- package/scripts/tour-prompt.md +11 -8
- package/src/short-scenes.js +127 -0
- package/src/short.js +158 -0
- package/src/tour.js +39 -3
package/README.ko.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# PR Docent
|
|
2
|
+
|
|
3
|
+
[English](README.md) | **한국어**
|
|
4
|
+
|
|
5
|
+
GitHub 풀 리퀘스트를 안내하는 도슨트 역할의 Chrome 확장입니다. **Files changed** 화면에서 리뷰어에게 변경 사항의 **투어**를 안내합니다. 수천 줄짜리 PR을 챕터로 나누고, **읽을 순서대로** 해당 파일과 줄로 이동하며 테두리로 표시하고, 볼 곳을 음성으로 읽어 줍니다. 코드를 읽지 않는 팀원을 위해서는 30~45초 동안 그림으로 설명하는 **쇼츠**도 재생합니다.
|
|
6
|
+
|
|
7
|
+
> 상태: 개발 중. Chrome 웹 스토어에는 아직 없으며 개발자 모드로 설치합니다. 투어와 쇼츠는 GitHub Actions나 본인 컴퓨터의 Claude Code가 작성합니다.
|
|
8
|
+
|
|
9
|
+
| 용어 | 뜻 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| **투어** | 리뷰어를 위한 diff 안내. 챕터와 단계로 이루어지고, 단계마다 줄을 가리키며 설명합니다. |
|
|
12
|
+
| **쇼츠** | 코드를 읽지 않는 사람을 위한 30~45초짜리 그림 설명. 확장에서 재생합니다. |
|
|
13
|
+
| **영상 파일** | 쇼츠를 GitHub 밖에서 공유하려고 MP4로 저장한 것(선택, macOS). |
|
|
14
|
+
| **로컬 도우미** | `npx pr-docent install`로 등록하는 작은 프로그램. 확장 대신 본인의 Claude Code를 실행합니다. |
|
|
15
|
+
|
|
16
|
+
## 기능
|
|
17
|
+
|
|
18
|
+
- 챕터 목록, 진행률, 이전·재생·다음, **집중 단계만 골라 건너뛰기**, 단축키
|
|
19
|
+
- 단계마다 파일과 줄 범위로 스크롤하고 테두리로 표시합니다. GitHub의 초록색(추가)과 빨간색(삭제)은 그대로 보이고, 나머지 코드는 흐리게 처리합니다.
|
|
20
|
+
- 음성이 읽는 문장에 맞춰 해당 줄을 진한 테두리로 가리킵니다(`note`를 문장별 배열로 쓴 경우).
|
|
21
|
+
- 중요도 표시: **집중**(꼼꼼히 볼 곳), **훑기**, **생략 가능**
|
|
22
|
+
- 브라우저 내장 음성 합성으로 설명 읽기(속도 조절). 네트워크 요청이나 비용이 없습니다.
|
|
23
|
+
- **투어가 다루지 않은 파일** 목록: 투어만 믿고 놓치는 파일이 없게 합니다.
|
|
24
|
+
- 접힌 대용량 diff("Load Diff")는 자동으로 펼칩니다.
|
|
25
|
+
- 패널이 열려 있는 동안 diff가 패널에 가리지 않도록 페이지 폭을 줄입니다.
|
|
26
|
+
- PR마다 마지막 위치를 기억합니다.
|
|
27
|
+
- **Viewed**로 표시한 파일은 그대로 접어 둡니다. 그 파일의 단계에서는 다시 열어서 볼지(Viewed 표시가 풀림), 건너뛸지 묻습니다.
|
|
28
|
+
- Files changed에서 커밋이나 커밋 범위를 골라 보는 중에는 투어를 재생하지 않습니다. 투어의 줄 번호가 PR 전체 변경 기준이기 때문이며, 패널에서 전체 변경으로 돌아가는 링크를 보여 줍니다.
|
|
29
|
+
- **쇼츠:** PR을 그림으로 설명하는 쇼츠를 패널에서 바로 봅니다.
|
|
30
|
+
- 화면 언어는 영어(기본)와 한국어를 지원합니다. 툴바의 PR Docent 아이콘을 눌러 자동(브라우저 언어), English, 한국어 중에서 고릅니다. 로컬에서 만드는 투어도 고른 언어로 작성되고, 음성은 투어 문장의 언어에 맞춰 읽습니다.
|
|
31
|
+
|
|
32
|
+
## 단축키
|
|
33
|
+
|
|
34
|
+
GitHub의 diff 화면은 화살표 키와 한 글자 단축키를 이미 쓰므로, PR Docent는 Alt(Mac은 Option) 조합만 씁니다. 코멘트를 입력하는 중에는 동작하지 않습니다.
|
|
35
|
+
|
|
36
|
+
| 단축키 | 동작 |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `Alt` + `→` / `←` | 다음 / 이전 단계 |
|
|
39
|
+
| `Alt` + `↓` / `↑` | 다음 / 이전 **집중** 단계로 건너뛰기 |
|
|
40
|
+
| `Alt` + `P` | 재생 / 일시정지 |
|
|
41
|
+
|
|
42
|
+
## 바로 체험해 보기
|
|
43
|
+
|
|
44
|
+
PR Docent를 체험할 수 있는 데모 PR 두 개를 열어 두었습니다. 같은 작은 변경(로그인에 5번 연속 실패하면 이름 잠금)을 언어별로 안내합니다. 확장을 설치한 뒤 PR을 열고 Files changed 탭에서 **PR Docent**를 누르세요.
|
|
45
|
+
|
|
46
|
+
- English: [#22 Lock out repeated failed logins](https://github.com/thomas783/pr-docent/pull/22/changes)
|
|
47
|
+
- 한국어: [#23 로그인 연속 실패 시 잠금](https://github.com/thomas783/pr-docent/pull/23/changes)
|
|
48
|
+
|
|
49
|
+
두 PR은 데모 코드가 있는 `demo/base` 브랜치를 대상으로 하며, `main`에는 머지하지 않습니다.
|
|
50
|
+
|
|
51
|
+
## 설치 (개발용)
|
|
52
|
+
|
|
53
|
+
1. `chrome://extensions`에서 **개발자 모드**를 켭니다.
|
|
54
|
+
2. **압축해제된 확장 프로그램을 로드합니다**를 누르고 이 폴더를 선택합니다.
|
|
55
|
+
3. PR의 Files changed 탭을 열면 오른쪽 아래에 **PR Docent** 버튼이 나타납니다.
|
|
56
|
+
|
|
57
|
+
## 투어 자동 생성 (GitHub Actions)
|
|
58
|
+
|
|
59
|
+
PR이 열리거나 커밋이 추가될 때마다 Claude Code가 diff를 읽고 투어를 만들어 PR 코멘트로 올립니다. 확장은 Files changed 탭에서 그 코멘트를 찾아 투어를 자동으로 불러옵니다. 비공개 저장소에서도 로그인한 사용자 권한으로 읽으므로 별도 토큰이 필요 없습니다.
|
|
60
|
+
|
|
61
|
+
1. Claude 구독 계정으로 OAuth 토큰을 만듭니다. 생성에는 그 구독의 사용량이 쓰입니다.
|
|
62
|
+
```bash
|
|
63
|
+
claude setup-token
|
|
64
|
+
```
|
|
65
|
+
2. 투어를 만들 저장소에 secret으로 등록합니다.
|
|
66
|
+
```bash
|
|
67
|
+
gh secret set CLAUDE_CODE_OAUTH_TOKEN -R <owner>/<repo>
|
|
68
|
+
```
|
|
69
|
+
3. 그 저장소에 `.github/workflows/pr-docent.yml`을 추가합니다.
|
|
70
|
+
```yaml
|
|
71
|
+
name: PR Docent tour
|
|
72
|
+
on:
|
|
73
|
+
pull_request:
|
|
74
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
75
|
+
concurrency:
|
|
76
|
+
group: pr-docent-tour-${{ github.event.pull_request.number }}
|
|
77
|
+
cancel-in-progress: true
|
|
78
|
+
jobs:
|
|
79
|
+
tour:
|
|
80
|
+
if: github.event.pull_request.draft == false && github.event.pull_request.head.repo.full_name == github.repository
|
|
81
|
+
uses: thomas783/pr-docent/.github/workflows/generate-tour.yml@main
|
|
82
|
+
secrets:
|
|
83
|
+
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
84
|
+
permissions:
|
|
85
|
+
contents: read
|
|
86
|
+
pull-requests: write
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
동작 방식
|
|
90
|
+
- Claude는 투어 파일 하나만 쓸 수 있고, 저장소의 다른 파일은 읽기만 합니다.
|
|
91
|
+
- `scripts/check-tour.mjs`가 투어를 검사합니다. 형식, 모든 줄 번호가 실제 diff 화면에 보이는지, 문장별 줄이 단계 범위 안에 있는지, 바뀐 파일을 모두 다루거나 건너뛴 이유를 적었는지 확인합니다. Claude는 검사를 통과할 때까지 고치고, 통과하지 못하면 코멘트를 올리지 않습니다.
|
|
92
|
+
- 투어 다음에 Claude가 그 투어로 **쇼츠** 대본도 쓰고, 코멘트에 둘을 함께 담습니다. 쇼츠가 검사를 통과하지 못하면 투어만 올립니다.
|
|
93
|
+
- 코멘트는 PR마다 하나이며, 새 커밋이 올라오면 같은 코멘트를 갱신합니다.
|
|
94
|
+
- 입력값 `model`(기본 `claude-opus-5-5`)과 `language`(기본 `한국어`)로 모델과 언어를 바꿀 수 있습니다.
|
|
95
|
+
- 포크에서 온 PR에는 secret이 전달되지 않으므로 실행하지 않습니다.
|
|
96
|
+
|
|
97
|
+
## 투어 로컬 생성 (본인 Claude Code)
|
|
98
|
+
|
|
99
|
+
저장소 설정 없이, 패널의 **로컬 Claude Code로 투어 생성** 버튼으로 지금 보고 있는 PR의 투어를 만듭니다. 본인 컴퓨터의 Claude Code와 구독을 쓰므로 API 키나 추가 비용이 없고, 설정 권한이 없는 저장소의 PR에서도 됩니다.
|
|
100
|
+
|
|
101
|
+
준비 (컴퓨터마다 한 번, macOS와 Linux)
|
|
102
|
+
1. [Claude Code](https://claude.com/claude-code)를 설치하고 로그인합니다.
|
|
103
|
+
2. 로컬 도우미를 Chrome에 등록합니다. Node.js 18 이상이 필요합니다.
|
|
104
|
+
```bash
|
|
105
|
+
npx pr-docent install
|
|
106
|
+
```
|
|
107
|
+
`~/.pr-docent/`에 도우미 파일과 실행 스크립트를 복사하고, Chrome의 `NativeMessagingHosts` 폴더에 `dev.prdocent.host.json`을 만듭니다. PR Docent만 연결할 수 있으며(Chrome 웹 스토어 버전 ID `deejphpcfjilekklajdhdhfepjbenjii`, 개발용 설치 ID `hleefogoiedjahnmjgmmgonckaeicppc`), 다른 ID는 `--extension-id <ID>`로 추가합니다. 이 저장소에서는 `npm run install-host`도 같습니다.
|
|
108
|
+
3. `chrome://extensions`에서 확장을 새로고침합니다.
|
|
109
|
+
|
|
110
|
+
빠진 단계가 있으면 패널이 알려 줍니다. 로컬 도우미가 없으면 위 단계를 명령 복사 버튼과 함께 보여 주고, Claude Code를 찾을 수 없거나 로그인되어 있지 않으면 그렇게 안내합니다. `npx pr-docent install`도 Claude Code에 로그인되어 있지 않으면 알려 줍니다.
|
|
111
|
+
|
|
112
|
+
동작 방식
|
|
113
|
+
- 확장이 로그인 세션으로 PR의 diff와 바뀐 파일을 가져와 로컬 도우미(`host/pr-docent-host.mjs`)에 넘깁니다.
|
|
114
|
+
- 도우미가 임시 폴더에서 `claude -p`를 실행합니다. GitHub Actions와 같은 프롬프트와 검사기를 쓰고, Claude는 투어 파일 하나만 쓸 수 있습니다.
|
|
115
|
+
- 검사를 통과한 투어를 이 PR에 저장하고 바로 재생합니다. 생성에는 보통 2~3분이 걸립니다.
|
|
116
|
+
- 제거: `npx pr-docent uninstall`
|
|
117
|
+
|
|
118
|
+
## 쇼츠
|
|
119
|
+
|
|
120
|
+
쇼츠는 PR을 30~45초 동안 **코드 대신 그림으로** 설명합니다. 기획자처럼 코드를 읽지 않는 팀원을 위한 것입니다. 제목 카드, 그림 장면 2~4개, 마무리 카드로 구성되고, 장면마다 큰 헤드라인과 그림이 문장을 읽는 동안 한 요소씩 나타나며 자막도 표시됩니다.
|
|
121
|
+
|
|
122
|
+
- 그림 종류: **흐름도**(처리 순서), **전후 비교**, **구조도**(모듈과 계층), **핵심 요점**. 이 PR이 새로 만든 부분은 보라색 NEW, 바꾼 부분은 노란색으로 표시합니다.
|
|
123
|
+
- 만드는 곳: GitHub Actions 워크플로가 투어와 함께 만들거나, 패널의 **더 보기 → 쇼츠 만들기**로 지금 투어를 바탕으로 본인의 Claude Code가 만듭니다(약 1분).
|
|
124
|
+
- 보기: 조작 버튼 옆의 **영상 버튼**(쇼츠 보기)을 누르면 페이지 위에서 브라우저가 바로 재생합니다. 영상을 렌더링하거나 저장하지 않고, 몇 KB짜리 대본만 투어와 함께 보관합니다.
|
|
125
|
+
- 대본은 Claude Code가 투어를 바탕으로 쓰고, 검사기(`scripts/check-short.mjs`)가 휴대폰 화면에 맞는지(장면 수, 상자와 항목 수, 헤드라인·라벨·문장 길이) 확인합니다.
|
|
126
|
+
|
|
127
|
+
쇼츠를 영상 파일로 저장하기 (선택, macOS)
|
|
128
|
+
- **더 보기 → 영상 파일로 저장**을 누르면 GitHub 밖에서 공유할 수 있도록 `~/Downloads/pr-docent-<owner>-<repo>-<번호>.mp4`(1080×1920)로 저장하고, **Finder에서 보기**로 파일을 찾습니다.
|
|
129
|
+
- 터미널에서는 `npx pr-docent short <owner/repo#번호 | PR 주소>`로 대본과 영상 파일을 함께 만듭니다(`gh` 로그인 필요, PR 코멘트의 투어나 `--tour <파일>`을 씁니다).
|
|
130
|
+
- 필요한 것: 로컬 도우미, Google Chrome, ffmpeg(`brew install ffmpeg`). 음성은 macOS의 `say`(한국어 Yuna, 영어 Samantha)를 씁니다.
|
|
131
|
+
|
|
132
|
+
## 투어 생성 규칙 바꾸기 (`.github/pr-docent.md`)
|
|
133
|
+
|
|
134
|
+
Actions 생성과 로컬 생성 모두 기본적으로 짧은 투어를 만듭니다. 단계 수는 바뀐 줄 25줄당 1개에 3을 더한 값까지(최대 20)이고, 단계마다 문장 3개, 문장마다 80자까지입니다. 주석만 바뀐 곳, 임포트, 문서처럼 사소한 변경은 단계 대신 "건너뛴 파일"에 넣습니다. 검사기가 이 기준을 확인하고, 넘으면 Claude가 다시 줄입니다.
|
|
135
|
+
|
|
136
|
+
저장소에 `.github/pr-docent.md`를 두면 그 저장소의 규칙을 더할 수 있습니다. 앞부분 `---` 블록은 숫자 기준을 바꾸고, 본문은 생성 지시문 뒤에 붙어 기본 규칙보다 우선합니다.
|
|
137
|
+
|
|
138
|
+
```markdown
|
|
139
|
+
---
|
|
140
|
+
maxSteps: 6 # 단계 수 상한 (기본: 3 + 바뀐 줄 25줄당 1, 최대 20)
|
|
141
|
+
sentencesPerStep: 2 # 단계당 문장 수 (기본 3)
|
|
142
|
+
sentenceChars: 100 # 문장 길이 (기본 80자)
|
|
143
|
+
pointChars: 120 # 리뷰 포인트 길이 (기본 120자)
|
|
144
|
+
summaryChars: 200 # PR 요약 길이 (기본 200자)
|
|
145
|
+
chapterSummaryChars: 60
|
|
146
|
+
---
|
|
147
|
+
- 도메인 용어는 원장, 안분, 파생 라인으로 씁니다.
|
|
148
|
+
- Flyway 마이그레이션 파일은 항상 집중 단계로 다룹니다.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
PR의 head 커밋에 있는 파일을 읽으므로, 규칙을 바꾸는 PR에서는 바뀐 규칙으로 생성됩니다.
|
|
152
|
+
|
|
153
|
+
## 투어 불러오기
|
|
154
|
+
|
|
155
|
+
- PR 코멘트에 자동 생성된 투어가 있으면 그 투어를 불러옵니다. 로컬에서 생성한 투어가 있으면 그쪽이 우선합니다.
|
|
156
|
+
- `tours/<owner>--<repo>--<number>.json` 파일이 있으면 해당 PR에서 자동으로 불러옵니다.
|
|
157
|
+
- 예제: [`tours/thomas783--pr-docent--1.json`](tours/thomas783--pr-docent--1.json) — 이 레포의 [PR #1](https://github.com/thomas783/pr-docent/pull/1/changes)(단축키와 집중 단계 건너뛰기)을 리뷰하는 투어입니다. 확장을 설치한 뒤 이 PR을 열면, PR Docent로 PR Docent 자신의 변경을 리뷰해 볼 수 있습니다.
|
|
158
|
+
- 직접 만든 투어는 같은 폴더에 두면 자동으로 불러오고, 커밋되지 않습니다(`.gitignore` 참고). 공개 예제만 커밋합니다.
|
|
159
|
+
|
|
160
|
+
## 투어 형식 (version 1)
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"version": 1,
|
|
165
|
+
"pr": { "owner": "your-org", "repo": "your-repo", "number": 42 },
|
|
166
|
+
"title": "투어 제목",
|
|
167
|
+
"summary": "PR 요약",
|
|
168
|
+
"chapters": [
|
|
169
|
+
{
|
|
170
|
+
"title": "1. 도메인 모델",
|
|
171
|
+
"summary": "챕터 설명",
|
|
172
|
+
"steps": [
|
|
173
|
+
{ "file": "src/Foo.kt", "lines": [10, 24], "side": "right", "level": "focus", "note": "이 단계에서 볼 것" }
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"skipped": [{ "file": "gradlew", "reason": "생성된 파일" }]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
| 필드 | 설명 |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `lines` | `[시작, 끝]` 줄 번호. 생략하면 파일 전체로 이동합니다. |
|
|
184
|
+
| `side` | `right`(변경 후, 기본값) 또는 `left`(변경 전, 삭제된 줄) |
|
|
185
|
+
| `level` | `focus`, `skim`(기본값), `skip` |
|
|
186
|
+
| `note` | 설명 문자열. 또는 `[{ "text": "...", "lines": [시작, 끝] }, ...]` 배열로 쓰면 음성이 각 문장을 읽는 동안 그 줄을 진하게 가리킵니다. |
|
|
187
|
+
| `point` | 리뷰어가 확인할 점(선택). 패널에 강조 상자로 보이고, 설명 다음에 따로 읽어 줍니다. |
|
|
188
|
+
| `skipped` | 일부러 건너뛴 파일과 이유. "다루지 않은 파일" 목록에서 빠집니다. |
|
|
189
|
+
| `pr.head`, `pr.base` | 투어를 만들 때의 PR head 커밋과 diff의 기준(공통 조상) 커밋입니다. Claude가 아니라 워크플로와 로컬 도우미가 넣습니다. 패널은 이 값을 PR과 비교해서 새 커밋 추가, 커밋 기록 변경(force push, rebase, fixup), base 변경을 알려 주고, PR과 맞는 코멘트 투어를 오래된 로컬 투어보다 우선합니다. |
|
|
190
|
+
|
|
191
|
+
## GitHub 화면 연동 방식
|
|
192
|
+
|
|
193
|
+
GitHub의 2026년 Files changed 화면 기준입니다. 화면 구조가 바뀌면 `src/github.js`만 고치면 됩니다.
|
|
194
|
+
|
|
195
|
+
- 파일 요소 ID: `diff-` + 파일 경로의 SHA-256
|
|
196
|
+
- 줄 셀: `data-line-anchor="diff-<해시>R<줄>"`(삭제 쪽은 `L`)
|
|
197
|
+
- URL 해시를 바꿔도 스크롤되지 않으므로 직접 스크롤합니다.
|
|
198
|
+
- 하이라이트는 요소에 클래스를 붙이지 않고 줄 앵커를 가리키는 CSS 규칙으로 적용합니다. GitHub(React)가 요소를 다시 그려도 유지됩니다.
|
|
199
|
+
- 화면 밖 파일과 접힌 파일은 그 파일로 스크롤한 뒤 내용이 그려질 때까지 기다리고, 필요하면 "Load Diff"를 누릅니다.
|
|
200
|
+
|
|
201
|
+
## 개발
|
|
202
|
+
|
|
203
|
+
- 빌드 단계가 없습니다. 콘텐츠 스크립트(`src/loader.js`)가 ES 모듈(`src/main.js`)을 불러옵니다.
|
|
204
|
+
- 테스트: `npm test` (Node 내장 테스트 러너). 투어 검증, diff 대조, 재생 상태, 단축키, PR 주소 해석, GitHub 파일 ID 해시, 줄 선택자, 번역, Native Messaging 통신, 쇼츠 대본을 다룹니다.
|
|
205
|
+
- npm 게시: `package.json`의 버전을 올려 머지한 뒤 main에서 `npm publish --access public`(2FA 필요). GitHub Actions의 trusted publishing 워크플로(`publish.yml`, `npm-v<버전>` 태그로 실행)는 준비되어 있지만, npm 쪽 trusted publisher 등록이 끝나기 전에는 태그를 푸시하지 않습니다.
|
|
206
|
+
- 투어 검사: `node scripts/check-tour.mjs <tour.json> <pr.diff> [owner/repo#number]` (`gh pr diff <number> > pr.diff`)
|
|
207
|
+
|
|
208
|
+
## 라이선스
|
|
209
|
+
|
|
210
|
+
MIT
|
|
211
|
+
|
|
212
|
+
## 다음 단계
|
|
213
|
+
|
|
214
|
+
1. **Chrome 웹 스토어 등록:** 아이콘, 스크린샷, 개인정보 처리 안내
|
package/README.md
CHANGED
|
@@ -1,51 +1,72 @@
|
|
|
1
1
|
# PR Docent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**English** | [한국어](README.ko.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A Chrome extension that acts as a docent for GitHub pull requests: on the **Files changed** page it takes a reviewer on a **tour** of the change. It breaks a pull request of thousands of lines into chapters, moves through the files and lines **in the order to read them**, frames them, and reads out what to look at. For teammates who won't read the code, it also plays a **short**: a 30-45 second explanation in pictures.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
> Status: in development. Not on the Chrome Web Store yet; install it in developer mode. Tours and shorts are written by Claude Code, either in GitHub Actions or on your own computer.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
9
|
+
| Term | Meaning |
|
|
10
|
+
|---|---|
|
|
11
|
+
| **Tour** | A guided walk through the diff for reviewers: chapters of steps, each pointing at lines with a note. |
|
|
12
|
+
| **Short** | A 30-45 second explanation in pictures for people who won't read the code, played in the extension. |
|
|
13
|
+
| **Video file** | A short saved as an MP4 to share outside GitHub (optional, macOS). |
|
|
14
|
+
| **Local helper** | The small program `npx pr-docent install` registers, which runs your Claude Code for the extension. |
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- Chapters, progress, previous / play / next, **skip between focus steps**, keyboard shortcuts
|
|
19
|
+
- Scrolls to each step's file and lines and frames them, leaving GitHub's green and red for added and removed lines visible; the rest of the diff fades.
|
|
20
|
+
- Points at the lines each sentence talks about while it is read (when `note` is a list of sentences).
|
|
21
|
+
- Importance per step: **focus** (read carefully), **skim**, **skippable**
|
|
22
|
+
- Reads notes aloud with the browser's built-in speech synthesis (adjustable speed). No network requests, no cost.
|
|
23
|
+
- **Files the tour doesn't cover**, so nothing is missed by trusting the tour.
|
|
24
|
+
- Expands large diffs that GitHub collapses ("Load Diff").
|
|
25
|
+
- Narrows the page while the panel is open so the diff isn't hidden behind it.
|
|
26
|
+
- Remembers where you were in each pull request.
|
|
27
|
+
- Files you marked as **Viewed** stay closed: at their steps the panel asks whether to open the file again (which takes the Viewed mark off) or skip it.
|
|
28
|
+
- When you pick a commit or a range of commits on Files changed, the tour doesn't play, since its line numbers are for the whole pull request; the panel links back to all changes.
|
|
29
|
+
- **Shorts:** watch a picture-based explanation of the pull request right in the panel.
|
|
30
|
+
- Interface in English (default) and Korean. Click the PR Docent icon in the toolbar to choose automatic (browser language), English or 한국어. Tours generated locally are written in the chosen language, and narration follows the tour's own language.
|
|
31
|
+
|
|
32
|
+
## Keyboard shortcuts
|
|
33
|
+
|
|
34
|
+
GitHub's diff view already uses the arrow keys and single letters, so PR Docent only uses Alt (Option on a Mac) combinations. They do nothing while you are typing a comment.
|
|
35
|
+
|
|
36
|
+
| Keys | Action |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `Alt` + `→` / `←` | Next / previous step |
|
|
39
|
+
| `Alt` + `↓` / `↑` | Skip to the next / previous **focus** step |
|
|
40
|
+
| `Alt` + `P` | Play / pause |
|
|
19
41
|
|
|
20
|
-
##
|
|
42
|
+
## Try it
|
|
21
43
|
|
|
22
|
-
|
|
44
|
+
Two demo pull requests stay open for trying PR Docent: the same small change (locking a name after five failed logins), toured in each language. With the extension installed, open one and click **PR Docent** on Files changed.
|
|
23
45
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| `Alt` + `→` / `←` | 다음 / 이전 단계 |
|
|
27
|
-
| `Alt` + `↓` / `↑` | 다음 / 이전 **집중** 단계로 건너뛰기 |
|
|
28
|
-
| `Alt` + `P` | 재생 / 일시정지 |
|
|
46
|
+
- English: [#22 Lock out repeated failed logins](https://github.com/thomas783/pr-docent/pull/22/changes)
|
|
47
|
+
- 한국어: [#23 로그인 연속 실패 시 잠금](https://github.com/thomas783/pr-docent/pull/23/changes)
|
|
29
48
|
|
|
30
|
-
|
|
49
|
+
They target the `demo/base` branch, which holds the demo's code; neither is ever merged into `main`.
|
|
31
50
|
|
|
32
|
-
|
|
33
|
-
2. **압축해제된 확장 프로그램을 로드합니다**를 누르고 이 폴더를 선택합니다.
|
|
34
|
-
3. PR의 Files changed 탭을 열면 오른쪽 아래에 **▶ PR Docent** 버튼이 나타납니다.
|
|
51
|
+
## Install (development)
|
|
35
52
|
|
|
36
|
-
|
|
53
|
+
1. Turn on **Developer mode** in `chrome://extensions`.
|
|
54
|
+
2. Click **Load unpacked** and choose this folder.
|
|
55
|
+
3. Open a pull request's Files changed tab; the **PR Docent** button appears at the bottom right.
|
|
37
56
|
|
|
38
|
-
|
|
57
|
+
## Generating tours automatically (GitHub Actions)
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
Whenever a pull request is opened or gets new commits, Claude Code reads the diff, writes a tour and posts it as a comment. On the Files changed tab the extension finds that comment and loads the tour. It reads it with your own GitHub session, so private repositories need no extra token.
|
|
60
|
+
|
|
61
|
+
1. Create an OAuth token with your Claude subscription. Generating tours uses that subscription's quota.
|
|
41
62
|
```bash
|
|
42
63
|
claude setup-token
|
|
43
64
|
```
|
|
44
|
-
2.
|
|
65
|
+
2. Add it as a secret to the repository that should get tours.
|
|
45
66
|
```bash
|
|
46
67
|
gh secret set CLAUDE_CODE_OAUTH_TOKEN -R <owner>/<repo>
|
|
47
68
|
```
|
|
48
|
-
3.
|
|
69
|
+
3. Add `.github/workflows/pr-docent.yml` to that repository.
|
|
49
70
|
```yaml
|
|
50
71
|
name: PR Docent tour
|
|
51
72
|
on:
|
|
@@ -65,112 +86,129 @@ PR이 열리거나 커밋이 추가될 때마다 Claude Code가 diff를 읽고
|
|
|
65
86
|
pull-requests: write
|
|
66
87
|
```
|
|
67
88
|
|
|
68
|
-
|
|
69
|
-
- Claude
|
|
70
|
-
- `scripts/check-tour.mjs
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
89
|
+
How it works
|
|
90
|
+
- Claude may write only the tour file; it can read the rest of the repository but not change it.
|
|
91
|
+
- `scripts/check-tour.mjs` checks the tour: its format, that every line number is shown in the diff, that each sentence's lines sit inside its step, and that every changed file is visited or skipped with a reason. Claude fixes the tour until it passes; if it never does, no comment is posted.
|
|
92
|
+
- After the tour, Claude also writes a **short** from it and the comment carries both; if the short fails its checks, the tour is posted without it.
|
|
93
|
+
- There is one comment per pull request, updated on every new commit.
|
|
94
|
+
- The `model` (default `claude-opus-5-5`) and `language` (default `한국어`) inputs change the model and the tour's language.
|
|
95
|
+
- Pull requests from forks get no secrets, so they are skipped.
|
|
74
96
|
|
|
75
|
-
##
|
|
97
|
+
## Generating tours locally (your own Claude Code)
|
|
76
98
|
|
|
77
|
-
|
|
99
|
+
Without any repository setup, the panel's **Create a tour with local Claude Code** button makes a tour of the pull request you are looking at. It uses Claude Code and the subscription on your own computer, so there is no API key or extra cost, and it works on pull requests in repositories you can't configure.
|
|
78
100
|
|
|
79
|
-
|
|
80
|
-
1. [Claude Code](https://claude.com/claude-code)
|
|
81
|
-
2.
|
|
101
|
+
Setup (once per computer, macOS and Linux)
|
|
102
|
+
1. Install [Claude Code](https://claude.com/claude-code) and log in.
|
|
103
|
+
2. Register the local helper with Chrome. Requires Node.js 18 or later.
|
|
82
104
|
```bash
|
|
83
105
|
npx pr-docent install
|
|
84
106
|
```
|
|
85
|
-
|
|
86
|
-
3. `chrome://extensions
|
|
107
|
+
This copies the helper and a launcher script to `~/.pr-docent/` and writes `dev.prdocent.host.json` to Chrome's `NativeMessagingHosts` folder. Only PR Docent may connect (the Chrome Web Store release, ID `deejphpcfjilekklajdhdhfepjbenjii`, and the unpacked development install, ID `hleefogoiedjahnmjgmmgonckaeicppc`); add other IDs with `--extension-id <ID>`. In this repository `npm run install-host` does the same.
|
|
108
|
+
3. Reload the extension in `chrome://extensions`.
|
|
109
|
+
|
|
110
|
+
If a step is missing, the panel says which: without the local helper it shows these steps with a button that copies the command, and it tells you when Claude Code can't be found or isn't signed in. `npx pr-docent install` also warns when Claude Code isn't signed in.
|
|
111
|
+
|
|
112
|
+
How it works
|
|
113
|
+
- The extension fetches the pull request's diff and changed files with your session and hands them to the local helper (`host/pr-docent-host.mjs`).
|
|
114
|
+
- The helper runs `claude -p` in a temporary folder with the same prompt and checker as GitHub Actions; Claude may write only the tour file.
|
|
115
|
+
- The checked tour is saved for the pull request and starts playing. It usually takes 2-3 minutes.
|
|
116
|
+
- To remove it: `npx pr-docent uninstall`
|
|
117
|
+
|
|
118
|
+
## Shorts
|
|
119
|
+
|
|
120
|
+
A short explains a pull request in 30-45 seconds **with pictures instead of code**, for teammates who won't read the code, such as planners. It has an opening card, 2-4 picture scenes and a closing card; each scene has a large headline and a picture that builds up while its sentence is read aloud and subtitled.
|
|
121
|
+
|
|
122
|
+
- Picture kinds: **flow** (what happens in order), **before and after**, **structure** (modules and layers) and **key points**. What the pull request adds is marked NEW in purple and what it changes in yellow.
|
|
123
|
+
- Where it comes from: the GitHub Actions workflow writes one with every tour, or **More → Make a short** in the panel writes one with your local Claude Code from the current tour (about a minute).
|
|
124
|
+
- Watching: the **video button** (Watch the short) next to the controls plays it over the page, live in your browser. Nothing is rendered or saved; only the script (a few KB) is kept with the tour.
|
|
125
|
+
- Claude Code writes the script from the tour, and `scripts/check-short.mjs` checks that it fits a phone screen (number of scenes, boxes and items; headline, label and sentence lengths).
|
|
87
126
|
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
- 제거: `npx pr-docent uninstall`
|
|
127
|
+
Saving a short as a video file (optional, macOS)
|
|
128
|
+
- **More → Save as a video file** renders it to `~/Downloads/pr-docent-<owner>-<repo>-<number>.mp4` (1080×1920) for sharing outside GitHub, and **Show in Finder** finds the file.
|
|
129
|
+
- From a terminal: `npx pr-docent short <owner/repo#number | pull request URL>` writes the script and the video file (needs `gh` logged in; uses the tour in the pull request's comments, or `--tour <file>`).
|
|
130
|
+
- Requires the local helper, Google Chrome and ffmpeg (`brew install ffmpeg`). Narration uses macOS `say` (Yuna for Korean, Samantha for English).
|
|
93
131
|
|
|
94
|
-
##
|
|
132
|
+
## Changing how tours are generated (`.github/pr-docent.md`)
|
|
95
133
|
|
|
96
|
-
Actions
|
|
134
|
+
Both GitHub Actions and local generation make short tours by default: at most 3 steps plus 1 per 25 changed lines (20 at most), 3 sentences per step and 80 characters per sentence. Trivial changes such as comment-only edits, imports and docs go in the skipped files instead of steps. The checker enforces these limits and Claude cuts the tour until it fits.
|
|
97
135
|
|
|
98
|
-
|
|
136
|
+
A repository can add its own rules in `.github/pr-docent.md`. The front matter between `---` lines changes the limits, and the rest is appended to the generator's instructions, taking precedence over the defaults.
|
|
99
137
|
|
|
100
138
|
```markdown
|
|
101
139
|
---
|
|
102
|
-
maxSteps: 6 #
|
|
103
|
-
sentencesPerStep: 2 #
|
|
104
|
-
sentenceChars: 100 #
|
|
105
|
-
pointChars: 120 #
|
|
106
|
-
summaryChars: 200 #
|
|
140
|
+
maxSteps: 6 # step limit (default: 3 + 1 per 25 changed lines, at most 20)
|
|
141
|
+
sentencesPerStep: 2 # sentences per step (default 3)
|
|
142
|
+
sentenceChars: 100 # sentence length (default 80)
|
|
143
|
+
pointChars: 120 # review point length (default 120)
|
|
144
|
+
summaryChars: 200 # pull request summary length (default 200)
|
|
107
145
|
chapterSummaryChars: 60
|
|
108
146
|
---
|
|
109
|
-
-
|
|
110
|
-
- Flyway
|
|
147
|
+
- Use the domain terms ledger, allocation and derived line.
|
|
148
|
+
- Always treat Flyway migration files as focus steps.
|
|
111
149
|
```
|
|
112
150
|
|
|
113
|
-
|
|
151
|
+
The file is read from the pull request's head commit, so a pull request that changes the rules is toured with the new rules.
|
|
114
152
|
|
|
115
|
-
##
|
|
153
|
+
## Loading tours
|
|
116
154
|
|
|
117
|
-
-
|
|
118
|
-
- `tours/<owner>--<repo>--<number>.json`
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
- 그 밖의 PR은 패널의 **투어 JSON 불러오기**로 파일을 선택합니다. 불러온 투어는 그 PR에 저장됩니다.
|
|
155
|
+
- A tour posted in the pull request's comments is loaded automatically. A tour you generated locally takes precedence.
|
|
156
|
+
- A file named `tours/<owner>--<repo>--<number>.json` is loaded for that pull request.
|
|
157
|
+
- Example: [`tours/thomas783--pr-docent--1.json`](tours/thomas783--pr-docent--1.json) tours this repository's [PR #1](https://github.com/thomas783/pr-docent/pull/1/changes) (keyboard shortcuts and skipping between focus steps). With the extension installed, open that pull request to review PR Docent's own change with PR Docent.
|
|
158
|
+
- Tours you put in that folder are loaded automatically and are not committed (see `.gitignore`); only public examples are committed.
|
|
122
159
|
|
|
123
|
-
##
|
|
160
|
+
## Tour format (version 1)
|
|
124
161
|
|
|
125
162
|
```json
|
|
126
163
|
{
|
|
127
164
|
"version": 1,
|
|
128
165
|
"pr": { "owner": "your-org", "repo": "your-repo", "number": 42 },
|
|
129
|
-
"title": "
|
|
130
|
-
"summary": "
|
|
166
|
+
"title": "Tour title",
|
|
167
|
+
"summary": "What the pull request does",
|
|
131
168
|
"chapters": [
|
|
132
169
|
{
|
|
133
|
-
"title": "1.
|
|
134
|
-
"summary": "
|
|
170
|
+
"title": "1. Domain model",
|
|
171
|
+
"summary": "What this chapter covers",
|
|
135
172
|
"steps": [
|
|
136
|
-
{ "file": "src/Foo.kt", "lines": [10, 24], "side": "right", "level": "focus", "note": "
|
|
173
|
+
{ "file": "src/Foo.kt", "lines": [10, 24], "side": "right", "level": "focus", "note": "What to look at here" }
|
|
137
174
|
]
|
|
138
175
|
}
|
|
139
176
|
],
|
|
140
|
-
"skipped": [{ "file": "gradlew", "reason": "
|
|
177
|
+
"skipped": [{ "file": "gradlew", "reason": "generated file" }]
|
|
141
178
|
}
|
|
142
179
|
```
|
|
143
180
|
|
|
144
|
-
|
|
|
181
|
+
| Field | Meaning |
|
|
145
182
|
|---|---|
|
|
146
|
-
| `lines` | `[
|
|
147
|
-
| `side` | `right`(
|
|
148
|
-
| `level` | `focus`, `skim`(
|
|
149
|
-
| `note` |
|
|
150
|
-
| `point` |
|
|
151
|
-
| `skipped` |
|
|
183
|
+
| `lines` | `[start, end]` line numbers. Without it the step goes to the whole file. |
|
|
184
|
+
| `side` | `right` (after the change, default) or `left` (before the change, for deleted lines) |
|
|
185
|
+
| `level` | `focus`, `skim` (default) or `skip` |
|
|
186
|
+
| `note` | A string, or a list `[{ "text": "...", "lines": [start, end] }, ...]` so the lines each sentence talks about are framed while it is read. |
|
|
187
|
+
| `point` | What the reviewer should check (optional). Shown in its own box and read after the note. |
|
|
188
|
+
| `skipped` | Files left out on purpose, with a reason. They don't count as uncovered. |
|
|
189
|
+
| `pr.head`, `pr.base` | The PR's head commit and the diff's merge base when the tour was made. Added by the workflow and the local helper, not by Claude. The panel compares them with the PR and says when new commits were pushed, the history was rewritten (force push, rebase, fixup) or the base changed, and a posted tour that matches the PR wins over an outdated local one. |
|
|
152
190
|
|
|
153
|
-
##
|
|
191
|
+
## How it hooks into GitHub
|
|
154
192
|
|
|
155
|
-
GitHub
|
|
193
|
+
Based on GitHub's 2026 Files changed page. If GitHub changes it, only `src/github.js` needs updating.
|
|
156
194
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
- URL
|
|
160
|
-
-
|
|
161
|
-
-
|
|
195
|
+
- File element ID: `diff-` + the SHA-256 of the file path
|
|
196
|
+
- Line cells: `data-line-anchor="diff-<hash>R<line>"` (`L` for the deleted side)
|
|
197
|
+
- Changing the URL hash doesn't scroll, so PR Docent scrolls itself.
|
|
198
|
+
- Highlights are CSS rules keyed on the line anchors rather than classes on elements, so they survive GitHub (React) redrawing the page.
|
|
199
|
+
- For files that are off screen or collapsed, it scrolls to the file, waits for it to render and clicks "Load Diff" when needed.
|
|
162
200
|
|
|
163
|
-
##
|
|
201
|
+
## Development
|
|
164
202
|
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
- npm
|
|
168
|
-
-
|
|
203
|
+
- There is no build step. The content script (`src/loader.js`) imports ES modules (`src/main.js`).
|
|
204
|
+
- Tests: `npm test` (Node's built-in test runner). They cover tour validation, checking against the diff, playback state, shortcuts, URL parsing, GitHub's file ID hash, line selectors, translations, the native messaging protocol and short scripts.
|
|
205
|
+
- Publishing to npm: bump `package.json`'s version, merge, then run `npm publish --access public` from `main` (needs 2FA). A trusted-publishing workflow (`publish.yml`, triggered by an `npm-v<version>` tag) is ready, but don't push those tags until the trusted publisher is registered on npm.
|
|
206
|
+
- Checking a tour: `node scripts/check-tour.mjs <tour.json> <pr.diff> [owner/repo#number]` (`gh pr diff <number> > pr.diff`)
|
|
169
207
|
|
|
170
|
-
##
|
|
208
|
+
## License
|
|
171
209
|
|
|
172
210
|
MIT
|
|
173
211
|
|
|
174
|
-
##
|
|
212
|
+
## Next
|
|
175
213
|
|
|
176
|
-
1.
|
|
214
|
+
1. **Chrome Web Store listing:** icons, screenshots and a privacy notice
|
package/bin/pr-docent.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
// npx pr-docent install [--extension-id <id>]... register with Chrome (once per computer)
|
|
5
5
|
// npx pr-docent uninstall remove the registration and files
|
|
6
|
+
// npx pr-docent short <owner/repo#n | PR URL> make a short video of a PR (macOS, needs gh)
|
|
6
7
|
//
|
|
7
8
|
// Install copies the generator into ~/.pr-docent/app, so it keeps working after npx clears its
|
|
8
9
|
// cache, and writes a wrapper that pins PATH, Node and Claude Code: Chrome starts native hosts
|
|
@@ -17,7 +18,11 @@ import { EXTENSION_IDS, HOST_NAME } from "../host/native.mjs";
|
|
|
17
18
|
|
|
18
19
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
19
20
|
// What the host needs at run time; everything else in the package is for the extension or tests.
|
|
20
|
-
const RUNTIME_FILES = [
|
|
21
|
+
const RUNTIME_FILES = [
|
|
22
|
+
"host/claude.mjs", "host/native.mjs", "host/pr-docent-host.mjs", "host/render-short.mjs", "host/short.mjs",
|
|
23
|
+
"src/diff.js", "src/guidelines.js", "src/short.js", "src/short-scenes.js", "src/tour.js",
|
|
24
|
+
"scripts/check-short.mjs", "scripts/check-tour.mjs", "scripts/short-prompt.md", "scripts/tour-prompt.md",
|
|
25
|
+
];
|
|
21
26
|
const HOSTS_DIRS = {
|
|
22
27
|
darwin: join(homedir(), "Library", "Application Support", "Google", "Chrome", "NativeMessagingHosts"),
|
|
23
28
|
linux: join(homedir(), ".config", "google-chrome", "NativeMessagingHosts"),
|
|
@@ -30,8 +35,11 @@ const hostManifest = hostsDir && join(hostsDir, `${HOST_NAME}.json`);
|
|
|
30
35
|
|
|
31
36
|
if (command === "install") install(args);
|
|
32
37
|
else if (command === "uninstall") uninstall();
|
|
33
|
-
else {
|
|
34
|
-
|
|
38
|
+
else if (command === "short") {
|
|
39
|
+
const { shortCommand } = await import("../host/short-cli.mjs");
|
|
40
|
+
await shortCommand(args).catch((error) => fail(error.message));
|
|
41
|
+
} else {
|
|
42
|
+
console.log("usage: pr-docent install [--extension-id <id>]... | pr-docent uninstall | pr-docent short <owner/repo#number>");
|
|
35
43
|
process.exit(command === "help" ? 0 : 2);
|
|
36
44
|
}
|
|
37
45
|
|
|
@@ -43,6 +51,7 @@ function install(args) {
|
|
|
43
51
|
} catch {
|
|
44
52
|
fail("Claude Code (claude) was not found on PATH. Install it and log in first: https://claude.com/claude-code");
|
|
45
53
|
}
|
|
54
|
+
const signedIn = claudeSignedIn(claude);
|
|
46
55
|
const extraIds = args.flatMap((arg, i) => (arg === "--extension-id" && args[i + 1] ? [args[i + 1]] : []));
|
|
47
56
|
const extensionIds = [...new Set([...EXTENSION_IDS, ...extraIds])];
|
|
48
57
|
|
|
@@ -74,9 +83,28 @@ function install(args) {
|
|
|
74
83
|
Chrome host manifest: ${hostManifest}
|
|
75
84
|
Generator: ${app}
|
|
76
85
|
Allowed extensions: ${extensionIds.join(", ")}
|
|
77
|
-
Claude Code: ${claude}
|
|
86
|
+
Claude Code: ${claude}${signedIn ? "" : " (not signed in)"}
|
|
78
87
|
Reload the extension in chrome://extensions, then click "Create a tour with local Claude Code"
|
|
79
88
|
in the panel ("로컬 Claude Code로 투어 생성" in Korean).`);
|
|
89
|
+
if (!signedIn) console.log("\nClaude Code isn't signed in yet, so tours can't be created. Run `claude` and sign in with /login.");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Whether Claude Code is signed in, from `claude auth status` (JSON with loggedIn, exit 1 when
|
|
94
|
+
* signed out). Versions without that command count as signed in: there's no telling.
|
|
95
|
+
*/
|
|
96
|
+
function claudeSignedIn(claude) {
|
|
97
|
+
let output;
|
|
98
|
+
try {
|
|
99
|
+
output = execFileSync(claude, ["auth", "status", "--json"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
100
|
+
} catch (error) {
|
|
101
|
+
output = error.stdout;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(output).loggedIn !== false;
|
|
105
|
+
} catch {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
80
108
|
}
|
|
81
109
|
|
|
82
110
|
function uninstall() {
|