~/.claude/projects の会話ログ (jsonl) を解析し、タスク(セッション)ごとの やりとりの時刻を一覧表示するローカル Web アプリ。標準ライブラリのみで動作する。 - プロジェクト / タスク / ターンの3ペイン表示 - ターンごとに 発言時刻・空き時間・初回応答までの待ち・応答時間・完了時刻・ ツール呼び出し内訳を表示、タイムラインバー付き - 絶対時刻と経過時間の切替、絞り込み、CSV書き出し - ファイルの更新時刻+サイズでの解析キャッシュ、tool_result 行はパースを省略 - デスクトップ用の起動 (pythonw) / 停止 (stop.cmd) スクリプト Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
165 lines
5.3 KiB
CSS
165 lines
5.3 KiB
CSS
:root {
|
|
--bg: #14161a;
|
|
--pane: #1a1d23;
|
|
--pane2: #20242c;
|
|
--line: #2c313b;
|
|
--fg: #e6e9ef;
|
|
--dim: #8f98a8;
|
|
--accent: #7aa2f7;
|
|
--user: #7aa2f7;
|
|
--work: #9ece6a;
|
|
--idle: #3d4350;
|
|
--warn: #e0af68;
|
|
--cmd: #bb9af7;
|
|
font-synthesis: none;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
body {
|
|
margin: 0;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
font: 13px/1.5 "Segoe UI", "Yu Gothic UI", system-ui, sans-serif;
|
|
}
|
|
|
|
header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 8px 14px;
|
|
background: var(--pane);
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
header h1 { margin: 0; font-size: 15px; letter-spacing: .04em; }
|
|
header .sub { color: var(--dim); font-size: 11px; }
|
|
header .spacer { flex: 1; }
|
|
.chk { color: var(--dim); user-select: none; cursor: pointer; }
|
|
|
|
button, .btn {
|
|
background: var(--pane2);
|
|
color: var(--fg);
|
|
border: 1px solid var(--line);
|
|
border-radius: 5px;
|
|
padding: 3px 10px;
|
|
font: inherit;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
}
|
|
button:hover, .btn:hover { border-color: var(--accent); color: var(--accent); }
|
|
|
|
main { flex: 1; display: flex; min-height: 0; }
|
|
|
|
.pane { display: flex; flex-direction: column; min-width: 0; border-right: 1px solid var(--line); }
|
|
#projects { width: 220px; flex: none; resize: horizontal; overflow: hidden; }
|
|
#sessions { width: 330px; flex: none; resize: horizontal; overflow: hidden; }
|
|
#detail { flex: 1; border-right: none; }
|
|
|
|
.pane-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 6px 10px;
|
|
font-size: 11px;
|
|
letter-spacing: .08em;
|
|
color: var(--dim);
|
|
text-transform: uppercase;
|
|
background: var(--pane);
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
.pane-head > span:first-child { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
#filter {
|
|
flex: 1 1 120px;
|
|
min-width: 80px;
|
|
background: var(--bg);
|
|
border: 1px solid var(--line);
|
|
border-radius: 5px;
|
|
color: var(--fg);
|
|
padding: 3px 8px;
|
|
font: inherit;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.scroll { flex: 1; overflow: auto; }
|
|
|
|
/* プロジェクト一覧 */
|
|
#project-list { list-style: none; margin: 0; padding: 0; overflow: auto; }
|
|
#project-list li { padding: 7px 10px; border-bottom: 1px solid var(--line); cursor: pointer; }
|
|
#project-list li:hover { background: var(--pane2); }
|
|
#project-list li.sel { background: var(--pane2); box-shadow: inset 3px 0 var(--accent); }
|
|
#project-list .p-path { font-size: 12px; word-break: break-all; }
|
|
#project-list .p-meta { color: var(--dim); font-size: 11px; }
|
|
|
|
/* セッション一覧 */
|
|
table { width: 100%; border-collapse: collapse; }
|
|
#session-table tr { border-bottom: 1px solid var(--line); cursor: pointer; }
|
|
#session-table tr:hover { background: var(--pane2); }
|
|
#session-table tr.sel { background: var(--pane2); box-shadow: inset 3px 0 var(--accent); }
|
|
#session-table td { padding: 6px 10px; vertical-align: top; }
|
|
.s-title { font-size: 12.5px; margin-bottom: 2px; }
|
|
.s-meta { color: var(--dim); font-size: 11px; display: flex; gap: 10px; flex-wrap: wrap; }
|
|
.s-when { white-space: nowrap; }
|
|
|
|
/* 詳細 */
|
|
#detail-body { padding: 0 0 40px; }
|
|
.empty, .loading { color: var(--dim); padding: 20px; }
|
|
.err { color: #f7768e; padding: 20px; white-space: pre-wrap; }
|
|
|
|
.sum {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 18px;
|
|
padding: 10px 14px;
|
|
background: var(--pane);
|
|
border-bottom: 1px solid var(--line);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 2;
|
|
}
|
|
.sum div { display: flex; flex-direction: column; }
|
|
.sum .k { color: var(--dim); font-size: 10.5px; letter-spacing: .06em; }
|
|
.sum .v { font-size: 13px; }
|
|
|
|
#turns { width: 100%; border-collapse: collapse; }
|
|
#turns th {
|
|
position: sticky;
|
|
top: 0;
|
|
background: var(--pane);
|
|
border-bottom: 1px solid var(--line);
|
|
color: var(--dim);
|
|
font-weight: 500;
|
|
font-size: 11px;
|
|
text-align: left;
|
|
padding: 6px 8px;
|
|
white-space: nowrap;
|
|
z-index: 1;
|
|
}
|
|
#turns td { padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
|
|
#turns tr:hover td { background: var(--pane2); }
|
|
#turns .num, #turns .n { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
#turns .time { font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
#turns .done { color: var(--dim); }
|
|
#turns .d { color: var(--dim); font-size: 11px; margin-right: 1px; }
|
|
#turns .msg { width: 40%; min-width: 160px; cursor: pointer; }
|
|
#turns .small { color: var(--dim); font-size: 11px; }
|
|
#turns .small .u { font-size: 9px; opacity: .65; margin: 0 3px 0 1px; }
|
|
#turns .msg .txt { white-space: pre-wrap; word-break: break-word; max-height: 3em; overflow: hidden; }
|
|
#turns tr.open .msg .txt { max-height: none; }
|
|
#turns .tools { color: var(--dim); font-size: 11px; margin-top: 3px; word-break: break-all; }
|
|
|
|
.kind { font-size: 10px; padding: 0 5px; border-radius: 3px; border: 1px solid var(--line); color: var(--dim); }
|
|
.kind.command { color: var(--cmd); border-color: var(--cmd); }
|
|
.kind.resume { color: var(--warn); border-color: var(--warn); }
|
|
.int { color: var(--warn); font-size: 11px; }
|
|
.ovl { color: var(--cmd); font-size: 11px; cursor: help; }
|
|
|
|
.bar { display: flex; align-items: center; gap: 2px; height: 12px; min-width: 95px; }
|
|
.bar i { display: block; height: 8px; border-radius: 2px; }
|
|
.bar .b-idle { background: var(--idle); }
|
|
.bar .b-wait { background: var(--user); }
|
|
.bar .b-work { background: var(--work); }
|