Claude Code のやりとり時刻ビューア chktime を追加
~/.claude/projects の会話ログ (jsonl) を解析し、タスク(セッション)ごとの やりとりの時刻を一覧表示するローカル Web アプリ。標準ライブラリのみで動作する。 - プロジェクト / タスク / ターンの3ペイン表示 - ターンごとに 発言時刻・空き時間・初回応答までの待ち・応答時間・完了時刻・ ツール呼び出し内訳を表示、タイムラインバー付き - 絶対時刻と経過時間の切替、絞り込み、CSV書き出し - ファイルの更新時刻+サイズでの解析キャッシュ、tool_result 行はパースを省略 - デスクトップ用の起動 (pythonw) / 停止 (stop.cmd) スクリプト Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+164
@@ -0,0 +1,164 @@
|
||||
: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); }
|
||||
Reference in New Issue
Block a user