Redmine へチケットを起票するボタンを追加

chktime のタスクと git 履歴から下書きを作り、まとめて Redmine へ登録できる
ようにした。外部通信はこの機能を使ったときだけで、使わなければ従来どおり
ローカルの jsonl を読むだけ。

- Redmine の REST API を叩く最小クライアント (標準ライブラリのみ)
- 下書きは「タスクから」(1タスク=1チケット) と「git 履歴から」
  (日ごと / 日 x 種別 / 期間一括) の 2 系統
- 起票は件数 x 間隔ぶん時間がかかるのでジョブにし、進捗だけ見に行く
- 作成時の status_id は Redmine 側で無視されるため、作成後に付け直す
- 連続アクセスに 403 を返すサーバがあるので 1 件ごとに間隔をあける (既定 7 秒)
- 自己署名証明書が普通なので、既定は証明書の検証なし
- API キーは redmine.json に置き、git 管理外にする

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 13:55:46 +09:00
co-authored by Claude Opus 5
parent d23bcabd76
commit a458509014
7 changed files with 1021 additions and 5 deletions
+32 -3
View File
@@ -6,20 +6,25 @@ Claude Code の会話ログ(`~/.claude/projects/<プロジェクト>/<セッ
## 構成
```
chktime.py サーバ + jsonl 解析(これ1本で完結)
chktime.py サーバ + jsonl 解析 + Redmine 連携(これ1本で完結)
web/index.html 画面の骨組み
web/app.js 表示ロジック(フレームワークなし・素の DOM 操作)
web/style.css スタイル(ダークテーマ固定)
run.bat コンソール表示で起動
stop.cmd 起動中の chktime を終了
redmine.json Redmine 連携の設定(自動生成・git 管理外)
```
`chktime.py` の中身は上から「解析ロジック → Store(キャッシュ)/ Watcher(更新検出)→ HTTP」の順。
`chktime.py` の中身は上から
「解析ロジック → Store(キャッシュ)/ Watcher(更新検出)→ Redmine 連携 → HTTP」の順。
## 守ること
- **標準ライブラリのみ**。外部パッケージも CDN も使わない。ブラウザ側もフレームワークなし。
- **外部通信しない**。読むのはローカルの jsonl だけ。
- **外部通信は Redmine 連携だけ**。それ以外はローカルの jsonl を読むだけで、どこにも接続しない。
新しい通信先を増やすときは、この行を書き換えるところから始める。
- **API キーをリポジトリに入れない**。`redmine.json` は `.gitignore` 済み。ログにも出さない
(`/api/redmine/config` はキーの有無だけ返す)。
- 会話ログは**読み取り専用**。検証で書き換えるときはスクラッチパッドにコピーしてから行う。
- `.bat` / `.cmd` は cmd の既定コードページで読まれるので**中身は ASCII のみ**(日本語を書かない)。
- コメント・コミットメッセージ・UI の文言は日本語。
@@ -50,6 +55,16 @@ python chktime.py --port 8799 --no-browser
いずれも `&format=csv` を付けると CSV を返す(Excel 用に BOM 付き)。
Redmine 連携(POST を使う唯一の系統):
| ルート | 内容 |
| --- | --- |
| `GET/POST /api/redmine/config` | 接続設定の取得(キーは返さない)/ 保存 |
| `GET /api/redmine/meta` | プロジェクト・トラッカー・ステータス・自分の情報 |
| `POST /api/redmine/draft` | 下書きを作る(`source=tasks` / `source=git`) |
| `POST /api/redmine/issues` | 起票をジョブとして開始。返り値の `id` で進捗を見る |
| `GET /api/redmine/job?id=` | 起票ジョブの進捗と結果 |
## 解析の前提
- ターンの起点は**人間の発言だけ**。ツール実行結果・システム挿入・サブエージェント(`isSidechain`)は起点にしない。
@@ -70,3 +85,17 @@ python chktime.py --port 8799 --no-browser
ターン単位で共有している。
- `/api/timeline` は表示範囲より前から続くセッションの全体時間・往復数・ツール数も範囲内に切り詰め、
`clipped` を立てて返す(作業時間だけ切り詰めると数字が食い違うため)。
- Redmine 起票のダイアログは `rm` オブジェクトが状態を持ち、`renderRedmine()` が中身を作り直す。
HTML 属性に NUL は入れられない(パーサが置換する)ので、タスクの識別は `data-project` /
`data-id` の 2 属性で持つ。
## Redmine 連携の落とし穴
実際に踏んだもの。同じところで転ばないように。
- **作成時の `status_id` は無視される**(既定の New で入る)。状態を指定したいなら作成後に
`PUT /issues/<id>.json` で付け直す(`Redmine.create()` がやっている)。
- **連続アクセスに 403 を返すサーバがある**。7〜8 秒あければ通る。`Redmine.throttle()` が
クライアント単位で間隔を保つので、クライアントは作り直さず使い回す。
- **自己署名証明書**が普通なので、既定は検証なし(`verifySsl: false`)。
- 起票は件数×間隔ぶん時間がかかるので HTTP を掴んだままにしない。`Jobs` に投げて進捗を取りに来てもらう。