issue-map 0.3.0 → 0.4.0

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.ja.md CHANGED
@@ -7,157 +7,134 @@
7
7
  GitHub Issues のブロック関係を 1 ページの開発マップにします:**いま着手できるのはどれか、どれが
8
8
  何を待っているか、クリティカルパスはどこを通るか。**
9
9
 
10
- 状態の正は常に GitHub Issues です。このページはスナップショットにすぎず、ここでは状態を変えられ
11
- ません——だから 2 つ目の正が生まれません。
12
-
13
- ## なぜこれを作ったか
14
-
15
- 出発点は [mattpocock/skills](https://github.com/mattpocock/skills) です。「ワークフローを skill と
16
- して書き、agent に走らせる」というやり方をチームで採り入れてから、チケットを起票するコストが
17
- 下がりました。思いついたら 1 枚起票して skill に渡す。結果としてチケットは一気に増えます。それは
18
- プロセスが機能している証拠であって、問題ではありません。
19
-
20
- 問題は次の一手です。Agent は 1 ラウンドに 1 枚しか扱えないので、毎ラウンド実際に決めるのは**どれを
21
- 渡すか**です。その答えはどの 1 枚の中にもなく、チケットとチケットの間にあります——誰が誰を
22
- ブロックしているか、親はあと何枚のサブチケットを待っているか、いちばん長い鎖は何段か。GitHub
23
- Issues は一度に 1 枚しか見せてくれないので、その絵を組み立てるには 1 枚ずつ開くしかなく、しかも
24
- 明日もまた同じことをします。
25
-
26
- このページがその絵です。
27
-
28
- ## 使い方
29
-
30
- **見たい repo の中で**実行します:
31
-
32
10
  ```bash
33
11
  bunx issue-map@latest
34
12
  ```
35
13
 
36
- `@latest` npm 上の最新版を取ります。特定のバージョンに固定するなら `bunx issue-map@0.2.0`。
14
+ 見たい repo の中で実行します。ブラウザのタブが開き、更新するたびに GitHub を取り直します。状態の
15
+ 正は常に GitHub Issues——このページはスナップショットで、状態は変えられません。
37
16
 
38
- `http://localhost:4747` で起動し、**そのままブラウザを開きます**。更新するたびに GitHub を取り直す
39
- ので、見えているのは常に現在の状態です。repo は `gh` が cwd の git から推測するため、指定は不要
40
- です。
41
-
42
- タブを勝手に開いてほしくなければ `ISSUE_MAP_OPEN=0` を設定します。
17
+ ## なぜこれを作ったか
43
18
 
44
- 静的な HTML 1 枚欲しいだけなら(`-p` はもう一方の bin を選ぶためのもので、これがないと server が
45
- 起動します):
19
+ Agent 1 ラウンドに 1 枚しか扱えないので、毎ラウンド実際に決めるのは**どれを渡すか**です。その
20
+ 答えはどの 1 枚の中にもなく、チケットとチケットの間にあります——誰が誰をブロックしているか、親は
21
+ あと何枚のサブチケットを待っているか、いちばん長い鎖は何段か。GitHub は一度に 1 枚しか見せてくれ
22
+ ません。このページがその絵です。
46
23
 
47
- ```bash
48
- bunx -p issue-map@latest issue-map-build # dist/issue-map.html に書き出す
49
- bunx -p issue-map@latest issue-map-build out.html
50
- ```
24
+ [mattpocock/skills](https://github.com/mattpocock/skills) のやり方——ワークフローを skill として
25
+ 書き、agent に走らせる——を前提に作っており、既定のラベルとコマンドもそこから来ています。
51
26
 
52
- スナップショットはスナップショットです——状態は古くなります。いまの状態を見たいときは上の server
53
- を使ってください。
27
+ ## 使い方
54
28
 
55
- ## 言語
29
+ | コマンド | 得られるもの |
30
+ | --------------------------------------------------- | ---------------------------------------- |
31
+ | `bunx issue-map@latest` | 空き port で server 起動、ブラウザも開く |
32
+ | `bunx -p issue-map@latest issue-map-build` | 静的ファイルを `dist/issue-map.html` へ |
33
+ | `bunx -p issue-map@latest issue-map-build out.html` | 静的ファイルを指定したパスへ |
56
34
 
57
- 右上で切り替えます。**既定は英語**で、ほかに繁体字中国語・簡体字中国語・日本語に対応しています。
58
- 選んだ言語はブラウザ(localStorage `issue-map:locale`)に記憶され、repo ごとではありません
59
- ——言語は読む人の好みであって、プロジェクトの設定ではないからです。`navigator.language` は意図的に
60
- 見ていません:既定が英語である以上、推測を外すと毎回戻す手間だけが増えます。
35
+ - repo は `gh` が cwd の git から推測するので、指定は不要です。
36
+ - `ISSUE_MAP_PORT` で port を固定できます。固定は厳密で、埋まっていれば黙って移らず失敗します。
37
+ - `ISSUE_MAP_OPEN=0` でタブを開きません。
38
+ - 静的ファイルは古くなります。いまの状態を見たいときは server を使ってください。
39
+ - スクリプトが動かせない場所(厳しい CSP、一部のプレビュー)では、空白ではなくチケットの
40
+ プレーンな一覧にフォールバックします。
41
+ - `@latest` は npm 上の最新版です。固定するなら `bunx issue-map@0.2.0`。
61
42
 
62
- 文言はすべて `scripts/issue-map-i18n.ts` にあり、ページ上のあらゆる一文はそこが唯一の出どころです:
43
+ ## 前提条件
63
44
 
64
- - `EN` が原稿であり、キーの定義場所でもあります。3 つの翻訳の型はそこから導かれるので、キーを 1 つ
65
- 訳し忘れると `bun run typecheck` が赤くなります。
66
- - 文中の差し込み名(`{n}`、`{issues}`)も型の一部で、1 つ渡し忘れるとコンパイルが通りません。
67
- そうでなければ、欠けたものが `{n}` のまま画面に出てしまい、そのマスに到達して初めて気づくことに
68
- なります。
69
- - 英語で単複を分けるキーは `{ one, other }` で書き、中国語と日本語は 1 本の文字列で構いません
70
- (`Intl.PluralRules` はこれらの言語では `other` しか返しません)。
45
+ - **Bun**——`Bun.build`、`Bun.serve`、`Bun.file` を使っているので、Node では動きません。
46
+ - **`gh` CLI にログイン済み**で、対象 repo への読み取り権限があること。
47
+ - 対象 repo に GitHub を指す git remote があること。
71
48
 
72
- モデルと取得の側は**もう文を組み立てません**:`nextStep`
73
- `{ kind: 'waitChildren', count: 2 }` のような構造化された値で、グループ名も同じです。言葉になるのは
74
- i18n の層です。スナップショットに文を保存していたら、言語を切り替えるたびに GitHub を取り直す
75
- ことになります。
49
+ runtime 依存はありません。
76
50
 
77
- CLI 側(生成メッセージ、エラー)は意図的に中国語のままです。あれはこのツールを開発する人向けで
78
- あって、ページの一部ではありません。
51
+ ## 言語
79
52
 
80
- ## 前提条件
53
+ 右上で切り替えます:英語(既定)、繁体字中国語、簡体字中国語、日本語。選んだ言語はブラウザに記憶
54
+ され、repo ごとではありません——言語は読む人の好みであって、プロジェクトの設定ではないからです。
81
55
 
82
- - **Bun**。`Bun.build`、`Bun.serve`、`Bun.file` と bun の `spawnSync` を使っているので、Node では
83
- 動きません。
84
- - **`gh` CLI にログイン済み**で、対象 repo への読み取り権限があること。
85
- - 対象 repo に GitHub を指す git remote があること。
86
- - runtime 依存はなし。devDependencies は型と lint/format のツールだけです。
56
+ CLI 側(生成メッセージ、エラー)は英語のみです。
87
57
 
88
58
  ## 設定
89
59
 
90
60
  すべて既定値があり、何も設定しなくても動きます。既定値は `scripts/issue-map.ts` の `CONFIG` に
91
61
  あります。
92
62
 
93
- | 環境変数 | 既定 | 意味 |
94
- | -------------------------- | --------------------------------- | -------------------------------------------------------------------------------------- |
95
- | `GH_REPO` | cwd の git から推測 | 別の repo を描くときに設定(`gh` 自身の変数。fork や複数 remote の判断も任せます) |
96
- | `ISSUE_MAP_PARENT_HEADING` | `Parent` | サブチケットが本文で親を指す見出し。GitHub ネイティブの sub-issue があればそちらを優先 |
97
- | `ISSUE_MAP_LABELS_UNREADY` | `needs-triage,needs-info` | 付いていれば未評価で、まだ誰にも渡せない |
98
- | `ISSUE_MAP_LABELS_READY` | `ready-for-agent,ready-for-human` | 付いて初めて評価済み・着手可とみなす |
99
- | `ISSUE_MAP_LABELS_ACTIVE` | `in-progress` | 付いていれば誰かが対応中(assignee がなくてもよい) |
100
- | `ISSUE_MAP_LABELS_HUMAN` | `ready-for-human` | 人がやるもの。次の一手に実装コマンドを出さない |
101
- | `ISSUE_MAP_CMD_IMPLEMENT` | `/implement` | 着手できるときにマップが促すコマンド |
102
- | `ISSUE_MAP_CMD_TRIAGE` | `/triage` | まだ評価が要るときにマップが促すコマンド |
103
- | `ISSUE_MAP_PORT` | `4747` | server のポート |
104
- | `ISSUE_MAP_OPEN` | 有効 | `0` にするとブラウザを開かない(`bun --watch` の開発モードは既定で無効) |
105
-
106
- とくに考えておくべきものが 2 つ:
107
-
108
- - **ラベルの語彙**:対象 repo がこのセットを使っていないなら、その repo の名前に置き換えてください。
109
- コード側で検知します——スナップショットに ready/unready のどのラベルも現れないときは triage
110
- ゲートにしません。そうしないと全チケットが「未評価」になってしまいます。
111
- - **コマンド名**:`/implement` と `/triage` は Claude Code の skill です。対象 repo にそれがない
112
- 場合は必ず差し替えてください。さもないと、存在しないものを走らせろとマップが指示します。
63
+ | 環境変数 | 既定 | 意味 |
64
+ | -------------------------- | --------------------------------- | ---------------------------------------------------------- |
65
+ | `GH_REPO` | cwd の git から推測 | 別の repo を描くときに設定(`gh` 自身の変数。fork も同様) |
66
+ | `ISSUE_MAP_PARENT_HEADING` | `Parent` | サブチケットが本文で親を指す見出し |
67
+ | `ISSUE_MAP_LABELS_UNREADY` | `needs-triage,needs-info` | 未評価で、まだ誰にも渡せない |
68
+ | `ISSUE_MAP_LABELS_READY` | `ready-for-agent,ready-for-human` | 評価済み・着手可 |
69
+ | `ISSUE_MAP_LABELS_ACTIVE` | `in-progress` | 誰かが対応中(assignee がなくてもよい) |
70
+ | `ISSUE_MAP_LABELS_HUMAN` | `ready-for-human` | 人がやるもの。次の一手に実装コマンドを出さない |
71
+ | `ISSUE_MAP_CMD_IMPLEMENT` | `/implement` | 着手できるときにマップが促すコマンド |
72
+ | `ISSUE_MAP_CMD_TRIAGE` | `/triage` | まだ評価が要るときにマップが促すコマンド |
73
+ | `ISSUE_MAP_PORT` | OS が割り当てる空き port | server のポート |
74
+ | `ISSUE_MAP_OPEN` | 有効 | `0` にするとブラウザを開かない |
75
+
76
+ とくに考えておくべきものが 3 つ:
77
+
78
+ - **ラベルの語彙。** ready/unready の既定値は mattpocock/skills の 5 つの[標準 triage ラベル](https://github.com/mattpocock/skills/blob/main/skills/engineering/setup-matt-pocock-skills/triage-labels.md)
79
+ のうち 4 つです。対象 repo が別の名前を使っているなら差し替えてください。これらのラベルが 1 つも
80
+ 現れないときは triage をゲートにしません。そうしないと全チケットが「未評価」になってしまいます
81
+ (`in-progress` はこのツール独自で、skill 側に「対応中」のラベルはありません)。
82
+ - **コマンド名。** `/implement` と `/triage` は向こうの [`implement`](https://github.com/mattpocock/skills/tree/main/skills/engineering/implement) と
83
+ [`triage`](https://github.com/mattpocock/skills/tree/main/skills/engineering/triage) skill です。対象 repo に実在するものを指すようにしてください。さもないと、
84
+ 存在しないものを走らせろとマップが指示します。
85
+ - **クローズ済みの兄弟にはネイティブ sub-issue が要る。** マップが問い合わせるクローズ済みチケット
86
+ は、open なチケットがまだ指しているものだけで、子チケットはネイティブの sub-issue 関係から取り
87
+ ます。`## Parent` の本文慣例を使う repo ではグループ内の**クローズ済み**の子が出てこず、進捗が
88
+ 実際より少なく見えます。チケットの Sub-issues で一度リンクし直せば戻ります。本文の慣例は残して
89
+ おいて構いません——ネイティブのほうが優先されます。
113
90
 
114
91
  ## よくある失敗
115
92
 
116
- - `gh api graphql 失敗:…` — `gh` にログインしていないか、cwd が対象 repo の git ツリーの中に
117
- ありません。
118
- - `open issue 超過 100 張,這支要改成分頁抓` — GraphQL の `first` の上限が 100 です。それ以上の
119
- チケットに対応するには `issue-map.ts` の `query()` にページングを足す必要があります。これは設定
120
- ではなくコードの変更です。
121
-
122
- (CLI のメッセージは中国語なので、実際に出力される通りに引用しています。)
93
+ `gh api graphql failed: …` — `gh` にログインしていないか、cwd が対象 repo の git ツリーの中に
94
+ ありません。
123
95
 
124
96
  ## ファイル
125
97
 
126
- | ファイル | 責務 |
127
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
128
- | `scripts/issue-map.ts` | スナップショット取得、各チケットの状態と次の一手の導出、HTML の生成。移植時に触る設定は中の `CONFIG` |
129
- | `scripts/issue-map-model.ts` | 純粋なデータモデル:グルーピング、クリティカルパス。両側で共用 |
130
- | `scripts/issue-map-i18n.ts` | 4 言語の文言と引き当て。ページ上のあらゆる一文の唯一の出どころ |
131
- | `scripts/issue-map-page.ts` | ブラウザ側のコード。ビルド時に HTML へバンドルされる |
132
- | `scripts/issue-map.html` | テンプレート。2 つのプレースホルダ(`issue-map-data`、`issue-map-code`)が埋められる |
133
- | `scripts/issue-map-serve.ts` | ローカル server。リクエストごとに取り直す |
134
- | `scripts/mutate.ts` | ミューテーションテスト:1 行を壊してテストが赤くなるか見る。ガードテストの逆検証はこれで行い、手でファイルを書き換えない |
98
+ | ファイル | 責務 |
99
+ | ---------------------------- | ---------------------------------------------------------------------- |
100
+ | `scripts/issue-map.ts` | スナップショット取得、状態と次の一手の導出、HTML 生成。設定は `CONFIG` |
101
+ | `scripts/issue-map-model.ts` | 純粋なデータモデル:グルーピング、クリティカルパス、レイアウト |
102
+ | `scripts/issue-map-i18n.ts` | 4 言語の文言と引き当て |
103
+ | `scripts/issue-map-page.ts` | ブラウザ側のコード。ビルド時に HTML へバンドルされる |
104
+ | `scripts/issue-map.html` | テンプレート。2 つのプレースホルダが埋められる |
105
+ | `scripts/issue-map-serve.ts` | ローカル server。リクエストごとに取り直す |
106
+ | `scripts/mutate.ts` | ミューテーションテスト:1 行を壊してテストが赤くなるか見る |
135
107
 
136
108
  ## この repo で開発する
137
109
 
138
110
  ```bash
139
111
  bun install
140
- bun run issue-map:serve # --watch。コードを変えると自動で再起動。ブラウザは意図的に開かない(保存のたびにタブが増えるため)
112
+ bun run issue-map:serve # --watch。ブラウザは開かない(保存のたびにタブが増えるため)
141
113
  bun run issue-map # dist/issue-map.html を生成するだけ
142
114
  bun run check # lint + format:check + typecheck
143
- bun test # 純粋なモデル層(グルーピング、クリティカルパス、レイアウト)
115
+ bun test # 純粋なモデル層
144
116
  ```
145
117
 
146
118
  この repo 自体にはまだ issue がないので、`GH_REPO=<owner>/<repo>` でチケットのある repo を指さない
147
119
  と何も描けません。
148
120
 
149
- `tests/` が守るのは「マップが嘘をつく」「読めなくなる」ことだけで、見た目(色・形・間隔)は意図的に
150
- 検証しません。ガードテストを足すときは逆検証で——そのテストが防ぐと主張する欠陥を製品コードに
151
- 戻し、赤くなることを確かめます:
121
+ **テスト。** `tests/` が守るのは「マップが嘘をつく」「読めなくなる」ことだけで、見た目(色・形・
122
+ 間隔)は意図的に検証しません。ガードテストを足すときは逆検証で——そのテストが防ぐと主張する欠陥を
123
+ 製品コードに戻し、赤くなることを確かめます:
152
124
 
153
125
  ```bash
154
126
  bun run mutate scripts/issue-map-model.ts tests/issue-map-layout.test.ts
155
127
  ```
156
128
 
157
- ## 変える前に知っておく 2 つの設計判断
129
+ **`scripts/issue-map-i18n.ts` を触るとき。** `EN` が原稿であり、キーの定義場所です。3 つの翻訳の型
130
+ はそこから導かれるので、キーや `{n}` の差し込み名が 1 つ欠けると `bun run typecheck` が赤くなります。
131
+ 英語で単複を分けるキーは `{ one, other }`、中国語と日本語は 1 本の文字列で構いません。モデル側は文
132
+ を組み立てません——`nextStep` は `{ kind: 'waitChildren', count: 2 }` のような構造化された値で、
133
+ 言葉になるのはここです。
134
+
135
+ ## 2 つの設計判断
158
136
 
159
- - **このページでは状態を変えられません。** GitHub に書き戻すボタンはありません。意図的です:状態の
160
- 正は 1 つだけで、入口が増えれば必ず食い違います。
161
- - **チケット名はマップに載せません。** ノードに載るのは番号だけで、名前は下の一覧にあります。本文に
162
- 短縮名の節を置く案は試しましたが、それはタイトルの 2 つ目の正であり、タイトルを直しても追随しま
163
- せん。機械的に短縮したものは読めませんでした。
137
+ - **このページでは状態を変えられません。** GitHub に書き戻すボタンはありません。状態の正は 1 つだけ
138
+ で、入口が増えれば必ず食い違います。
139
+ - **短縮名の欄は設けません。** 駅にはタイトルの先頭数文字を出します。本文に短縮名を手で書くと
140
+ タイトルの 2 つ目の正になり、タイトルを直しても追随しません。完全なタイトルは下の一覧にあります。
package/README.md CHANGED
@@ -5,157 +5,137 @@
5
5
  Draws the blocking relationships between your GitHub Issues as a one-page dev map: **which issues
6
6
  can be picked up now, which are waiting on what, and where the critical path runs.**
7
7
 
8
- GitHub Issues stays the source of truth. This page is only a snapshot — you cannot change status on
9
- it, so no second source of truth grows out of it.
10
-
11
- ## Why this exists
12
-
13
- It started with [mattpocock/skills](https://github.com/mattpocock/skills). Once the team adopted
14
- that way of working — write the workflow as a skill, let the agent run it — filing an issue got
15
- cheap: think of something, open a ticket, hand it to a skill. So the issue count grew fast. That is
16
- the process working, not a problem.
17
-
18
- The problem is the next step. An agent takes one issue per round, so what you actually decide each
19
- round is **which one**. That answer is in no single issue; it lives between them: who blocks whom,
20
- how many sub-issues a parent is still waiting on, how long the longest chain is. GitHub Issues only
21
- ever shows you one issue at a time, so assembling that picture means opening them one by one — and
22
- doing it again tomorrow.
23
-
24
- This page is that picture.
25
-
26
- ## Usage
27
-
28
- Run it inside **the repo you want to look at**:
29
-
30
8
  ```bash
31
9
  bunx issue-map@latest
32
10
  ```
33
11
 
34
- `@latest` takes the newest version on npm; pin one with `bunx issue-map@0.2.0`.
12
+ Run it inside the repo you want to look at. A browser tab opens; every refresh re-fetches from
13
+ GitHub. GitHub Issues stays the source of truth — this page is a snapshot and cannot change status.
35
14
 
36
- It serves `http://localhost:4747` **and opens your browser**. Every refresh re-fetches from GitHub,
37
- so what you see is the current state. The repo is what `gh` infers from the git remote in your cwd —
38
- nothing to fill in.
15
+ ## Why
39
16
 
40
- Set `ISSUE_MAP_OPEN=0` if you don't want the tab.
17
+ An agent takes one issue per round, so what you decide each round is **which one**. That answer is
18
+ in no single issue; it lives between them — who blocks whom, how many sub-issues a parent is still
19
+ waiting on, how long the longest chain is. GitHub shows you one issue at a time. This page shows
20
+ the picture.
41
21
 
42
- If all you want is a static HTML file (`-p` is what picks the other bin; without it you get the
43
- server):
44
-
45
- ```bash
46
- bunx -p issue-map@latest issue-map-build # writes dist/issue-map.html
47
- bunx -p issue-map@latest issue-map-build out.html
48
- ```
22
+ It is built around [mattpocock/skills](https://github.com/mattpocock/skills) write the workflow
23
+ as a skill, let the agent run it — which is where the default labels and commands come from.
49
24
 
50
- A snapshot is a snapshot — it goes stale. Use the server above when you need the current state.
25
+ ## Usage
51
26
 
52
- ## Language
27
+ | Command | What you get |
28
+ | --------------------------------------------------- | ------------------------------------ |
29
+ | `bunx issue-map@latest` | Server on a free port, browser opens |
30
+ | `bunx -p issue-map@latest issue-map-build` | Static file at `dist/issue-map.html` |
31
+ | `bunx -p issue-map@latest issue-map-build out.html` | Static file at a path you name |
53
32
 
54
- Switch in the top right. **English is the default**; Traditional Chinese, Simplified Chinese and
55
- Japanese are also supported. The choice is remembered in the browser (`issue-map:locale` in
56
- localStorage) and is not tied to a repo — language is the preference of whoever is reading, not a
57
- setting of the project. `navigator.language` is deliberately ignored: English is the default, and
58
- guessing wrong just means changing it back on every visit.
33
+ - The repo comes from `gh` reading the git remote in your cwd — nothing to fill in.
34
+ - `ISSUE_MAP_PORT` pins the port. Pinned is strict: it fails rather than moving if taken.
35
+ - `ISSUE_MAP_OPEN=0` stops the browser tab.
36
+ - A static file goes stale. Use the server when you need the current state.
37
+ - Where scripts cannot run (a strict CSP, some preview panes) the file falls back to a plain
38
+ listing of the issues rather than a blank page.
39
+ - `@latest` takes the newest version on npm; pin one with `bunx issue-map@0.2.0`.
59
40
 
60
- Every string lives in `scripts/issue-map-i18n.ts`, the single source for every sentence on the page:
41
+ ## Requirements
61
42
 
62
- - `EN` is the original, and the place the keys are defined. The three translations are typed from
63
- it, so missing a key turns `bun run typecheck` red.
64
- - The placeholder names inside a sentence (`{n}`, `{issues}`) are part of the type too — miss one
65
- and it will not compile. Otherwise the missing one prints as a literal `{n}` on the page, and
66
- you would only find it by reaching that exact cell.
67
- - Keys that need English plurals are written `{ one, other }`; Chinese and Japanese take a single
68
- string (`Intl.PluralRules` only has `other` for those languages).
43
+ - **Bun** these scripts use `Bun.build`, `Bun.serve` and `Bun.file`; Node will not run them.
44
+ - **`gh` CLI, logged in**, with read access to the target repo.
45
+ - A git remote pointing at GitHub.
69
46
 
70
- The model and fetch side **no longer builds sentences**: `nextStep` is a structured value such as
71
- `{ kind: 'waitChildren', count: 2 }`, and so are group names. The words are assembled in the i18n
72
- layer. If the snapshot stored sentences, switching language would mean re-fetching from GitHub.
47
+ No runtime dependencies.
73
48
 
74
- The CLI side (build messages, errors) is deliberately left in Chinese: that output is for whoever
75
- develops this tool, not part of the page.
49
+ ## Language
76
50
 
77
- ## Requirements
51
+ Switch in the top right: English (default), 繁體中文, 简体中文, 日本語. The choice is remembered in
52
+ the browser and is not tied to a repo — language is the reader's preference, not a project setting.
78
53
 
79
- - **Bun.** These scripts use `Bun.build`, `Bun.serve`, `Bun.file` and bun's `spawnSync`; Node will
80
- not run them.
81
- - **`gh` CLI, logged in**, with read access to the target repo.
82
- - The target repo has a git remote pointing at GitHub.
83
- - No runtime dependencies; devDependencies are only types and lint/format tools.
54
+ CLI output (build messages, errors) is English only.
84
55
 
85
56
  ## Configuration
86
57
 
87
58
  Everything has a default — it runs with nothing set. The defaults live in `CONFIG` in
88
59
  `scripts/issue-map.ts`.
89
60
 
90
- | Environment variable | Default | Meaning |
91
- | -------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
92
- | `GH_REPO` | inferred from the git in cwd | Set it to map another repo (`gh`'s own variable; forks and multiple remotes are its job too) |
93
- | `ISSUE_MAP_PARENT_HEADING` | `Parent` | The body heading under which a sub-issue points at its parent. A native GitHub sub-issue relation wins when present |
94
- | `ISSUE_MAP_LABELS_UNREADY` | `needs-triage,needs-info` | Carrying one means it is not assessed yet and cannot be handed to anyone |
95
- | `ISSUE_MAP_LABELS_READY` | `ready-for-agent,ready-for-human` | Only with one of these does an issue count as assessed and ready to work on |
96
- | `ISSUE_MAP_LABELS_ACTIVE` | `in-progress` | Carrying one means somebody is on it, with or without an assignee |
97
- | `ISSUE_MAP_LABELS_HUMAN` | `ready-for-human` | These need a person, so the next step is not an implementation command |
98
- | `ISSUE_MAP_CMD_IMPLEMENT` | `/implement` | The command the map tells you to run when an issue is ready |
99
- | `ISSUE_MAP_CMD_TRIAGE` | `/triage` | The command the map tells you to run when it still needs assessing |
100
- | `ISSUE_MAP_PORT` | `4747` | Port for the server |
101
- | `ISSUE_MAP_OPEN` | on | Set `0` to stop opening the browser (the `bun --watch` dev mode has it off) |
102
-
103
- Two worth thinking through:
104
-
105
- - **Label vocabulary**: if the target repo does not use this set, replace them with its own names.
106
- The code detects it — when the snapshot contains none of the ready/unready labels at all, triage
107
- is not used as a gate; otherwise every issue would come out as "needs triage".
108
- - **Command names**: `/implement` and `/triage` are Claude Code skills. If the target repo has no
109
- such skills you must change them, or the map will tell people to run something that does not
110
- exist.
61
+ | Environment variable | Default | Meaning |
62
+ | -------------------------- | --------------------------------- | ------------------------------------------------------------------------------ |
63
+ | `GH_REPO` | inferred from the git in cwd | Map another repo (`gh`'s own variable; forks and multiple remotes are its job) |
64
+ | `ISSUE_MAP_PARENT_HEADING` | `Parent` | Body heading under which a sub-issue points at its parent |
65
+ | `ISSUE_MAP_LABELS_UNREADY` | `needs-triage,needs-info` | Not assessed yet, cannot be handed to anyone |
66
+ | `ISSUE_MAP_LABELS_READY` | `ready-for-agent,ready-for-human` | Assessed and ready to work on |
67
+ | `ISSUE_MAP_LABELS_ACTIVE` | `in-progress` | Somebody is on it, with or without an assignee |
68
+ | `ISSUE_MAP_LABELS_HUMAN` | `ready-for-human` | Needs a person, so the next step is not an implementation command |
69
+ | `ISSUE_MAP_CMD_IMPLEMENT` | `/implement` | Command the map suggests when an issue is ready |
70
+ | `ISSUE_MAP_CMD_TRIAGE` | `/triage` | Command the map suggests when it still needs assessing |
71
+ | `ISSUE_MAP_PORT` | an OS-assigned free port | Port for the server |
72
+ | `ISSUE_MAP_OPEN` | on | `0` stops the browser tab |
73
+
74
+ Three worth knowing:
75
+
76
+ - **Label vocabulary.** The ready/unready defaults are four of the five canonical
77
+ [triage labels](https://github.com/mattpocock/skills/blob/main/skills/engineering/setup-matt-pocock-skills/triage-labels.md)
78
+ from mattpocock/skills. If the target repo uses different names, set them. When none of these
79
+ labels appear at all, triage stops being a gate otherwise every issue would come out as "needs
80
+ triage". (`in-progress` is this tool's own; the skills have no "somebody is on it" label.)
81
+ - **Command names.** `/implement` and `/triage` are the
82
+ [`implement`](https://github.com/mattpocock/skills/tree/main/skills/engineering/implement) and
83
+ [`triage`](https://github.com/mattpocock/skills/tree/main/skills/engineering/triage) skills. Point
84
+ them at something that exists in the target repo, or the map tells people to run what isn't there.
85
+ - **Closed siblings need native sub-issues.** The map asks GitHub only for the closed issues an
86
+ open one still points at, and children come from the native sub-issue relation. With the
87
+ `## Parent` body convention a group's _closed_ children never appear, so its progress looks
88
+ smaller than it is. Linking them once in the issue's Sub-issues panel brings them back; the body
89
+ convention can stay, the native relation wins anyway.
111
90
 
112
91
  ## When it fails
113
92
 
114
- - `gh api graphql 失敗:…` — `gh` is not logged in, or your cwd is not inside the target repo's git
115
- tree.
116
- - `open issue 超過 100 張,這支要改成分頁抓` — 100 is the hard cap on GraphQL's `first`. Supporting
117
- more issues means adding pagination to `query()` in `issue-map.ts`; that is a code change, not
118
- configuration.
119
-
120
- (CLI messages are in Chinese, so they are quoted here as they actually appear.)
93
+ `gh api graphql failed: …` — `gh` is not logged in, or your cwd is not inside the target repo's git
94
+ tree.
121
95
 
122
96
  ## Files
123
97
 
124
- | File | Responsibility |
125
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
126
- | `scripts/issue-map.ts` | Takes the snapshot, derives each issue's status and next step, produces the HTML. Porting knobs live in its `CONFIG` |
127
- | `scripts/issue-map-model.ts` | Pure data model: grouping, critical path. Shared by both sides |
128
- | `scripts/issue-map-i18n.ts` | Strings for the four languages, plus the lookup. Single source for every sentence on the page |
129
- | `scripts/issue-map-page.ts` | Browser-side code, bundled into the HTML at build time |
130
- | `scripts/issue-map.html` | The template. Two placeholder blocks (`issue-map-data`, `issue-map-code`) get filled in |
131
- | `scripts/issue-map-serve.ts` | Local server, re-fetches on every request |
132
- | `scripts/mutate.ts` | Mutation testing: break one line and see whether a test goes red. Use it to verify guard tests in reverse instead of editing files by hand |
98
+ | File | Responsibility |
99
+ | ---------------------------- | ------------------------------------------------------------------------ |
100
+ | `scripts/issue-map.ts` | Snapshot, status and next step, produces the HTML. Knobs in its `CONFIG` |
101
+ | `scripts/issue-map-model.ts` | Pure data model: grouping, critical path, layout. Shared by both sides |
102
+ | `scripts/issue-map-i18n.ts` | Strings for the four languages, plus the lookup |
103
+ | `scripts/issue-map-page.ts` | Browser-side code, bundled into the HTML at build time |
104
+ | `scripts/issue-map.html` | The template. Two placeholder blocks get filled in |
105
+ | `scripts/issue-map-serve.ts` | Local server, re-fetches on every request |
106
+ | `scripts/mutate.ts` | Mutation testing: break one line, see whether a test goes red |
133
107
 
134
108
  ## Developing in this repo
135
109
 
136
110
  ```bash
137
111
  bun install
138
- bun run issue-map:serve # --watch, restarts on change; deliberately does not open a tab (you would get one per save)
112
+ bun run issue-map:serve # --watch; no browser tab (you would get one per save)
139
113
  bun run issue-map # build the file only, to dist/issue-map.html
140
114
  bun run check # lint + format:check + typecheck
141
- bun test # the pure model layer (grouping, critical path, layout)
115
+ bun test # the pure model layer
142
116
  ```
143
117
 
144
118
  This repo has no issues of its own yet, so point `GH_REPO=<owner>/<repo>` at one that has tickets to
145
119
  get anything drawn.
146
120
 
147
- `tests/` only guards things that would make the map lie or make it unreadable; looks (colour, shape,
148
- spacing) are deliberately not asserted. A new guard test has to be verified in reverse — put the
149
- defect it claims to catch back into the product code and confirm it goes red:
121
+ **Tests.** `tests/` only guards what would make the map lie or make it unreadable; looks (colour,
122
+ shape, spacing) are deliberately not asserted. A new guard test has to be verified in reverse — put
123
+ the defect it claims to catch back into the product code and confirm it goes red:
150
124
 
151
125
  ```bash
152
126
  bun run mutate scripts/issue-map-model.ts tests/issue-map-layout.test.ts
153
127
  ```
154
128
 
155
- ## Two design decisions, know them before you change things
129
+ **Adding to `scripts/issue-map-i18n.ts`.** `EN` is the original and defines the keys; the three
130
+ translations are typed from it, so a missing key or a missing `{n}` placeholder turns
131
+ `bun run typecheck` red. Keys needing English plurals are written `{ one, other }`; Chinese and
132
+ Japanese take a single string. The model never builds sentences — `nextStep` is a structured value
133
+ like `{ kind: 'waitChildren', count: 2 }`, assembled into words here.
134
+
135
+ ## Two design decisions
156
136
 
157
- - **This page cannot change status.** No button writes back to GitHub. That is deliberate: status
158
- has exactly one source of truth, and a second entry point makes them disagree.
159
- - **Issue titles stay off the map.** Nodes carry only the number; names are in the list below. A
160
- short-name section in the body was tried, and it is a second source of truth for the title —
161
- editing the title does not update it; shortening titles mechanically does not read.
137
+ - **The page cannot change status.** No button writes back to GitHub. Status has exactly one source
138
+ of truth, and a second entry point makes them disagree.
139
+ - **No separate short name.** Stations are labelled with the first few characters of the title.
140
+ A hand-maintained short name in the issue body would be a second source of truth editing the
141
+ title would not update it. The list below carries the full titles.