aizuchi 0.1.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.
@@ -0,0 +1,167 @@
1
+ /**
2
+ * 統計ビュー (F-6-4) の派生ロジック。すべて .kanban のテキスト (frontmatter + 作業ログ) から
3
+ * 算出する純関数で、新データ源・新依存はゼロ。server/web の双方が型を共有する (LEARN#6 境界明確化)。
4
+ *
5
+ * now は引数注入する (Date.now ハードコード禁止・テスト再現性)。
6
+ * 作業ログ行の parse は shared/digest.ts の parseWorkLogLines を流用する (再実装しない)。
7
+ */
8
+ import { parseWorkLogLines } from './digest.js';
9
+ import { TASK_STATUSES } from './schema.js';
10
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
11
+ const DEFAULT_MAX_BOTTLENECKS = 5;
12
+ // 完了記録の偽陽性を避けるための否定文脈ガード (R10-1)。これにヒットする行は完了記録とみなさない。
13
+ // 例: 「未完了の項目」「完了予定を 7/1」「まだ done していない」「isn't finished」
14
+ const COMPLETION_NEGATIVE_RE = /未完了|未完|完了予定|完了見込|完了せず|undone|not\s+(done|finished|closed)|n['’]t\s+(done|finished|closed)/i;
15
+ // 完了記録とみなす肯定パターン (R10-1)。進捗行の中間出現を拾わないよう「文末寄せ」で判定する。
16
+ // 日本語: 行末が「(…)完了 / 完了した / 完了しました / 完了です」+ 任意の句点。
17
+ // → 「スキーマ定義完了。テスト作成中」は行末が「テスト作成中」なのでヒットしない (Case B で updated にフォールバック)。
18
+ const COMPLETION_JA_RE = /完了(した|しました|です|済)?[。.!!]?\s*$/;
19
+ // 英語: 語境界 \b(done|closed|finished)\b を文末寄せで。「closed PR #5」は行末が「#5」なのでヒットしない。
20
+ const COMPLETION_EN_RE = /\b(done|closed|finished)\b[.!]?\s*$/i;
21
+ /** ms を「日数」に丸める (小数第 1 位)。負値は 0 にクランプ */
22
+ function toDays(ms) {
23
+ return Math.max(0, Math.round((ms / MS_PER_DAY) * 10) / 10);
24
+ }
25
+ /** ISO 8601 文字列を epoch ms にする。無効なら null */
26
+ function parseIsoMs(iso) {
27
+ const ms = Date.parse(iso);
28
+ return Number.isNaN(ms) ? null : ms;
29
+ }
30
+ /**
31
+ * 作業ログ 1 行が「完了記録」かを判定する (R10-1)。
32
+ * 否定文脈 (未完了 / 完了予定 / not done 等) は除外し、肯定は文末寄せ (進捗行の中間出現を拾わない)。
33
+ */
34
+ function isCompletionRecord(message) {
35
+ const msg = message.trim();
36
+ if (COMPLETION_NEGATIVE_RE.test(msg))
37
+ return false;
38
+ return COMPLETION_JA_RE.test(msg) || COMPLETION_EN_RE.test(msg);
39
+ }
40
+ /**
41
+ * done タスクの完了時刻を決める (epoch ms)。
42
+ * 優先順位: (1) 完了記録 (isCompletionRecord) を満たす作業ログ最終行の日時 → 無ければ (2) updated。
43
+ * 作業ログは `YYYY-MM-DD HH:mm` (タイムゾーン無し) なので、updated のタイムゾーンに合わせず
44
+ * ローカル解釈の差を避けるため UTC ではなく Date.parse に委ねる (日別ビンは日付文字列で行う)。
45
+ * R10-4 既知近似: 作業ログ時刻はローカル解釈・created/updated はオフセット付き絶対時刻のため、
46
+ * 非 JST ブラウザではサイクルタイムが offset 差ぶんずれる (JST 運用なら実害小)。
47
+ */
48
+ function completionMs(task) {
49
+ const logs = parseWorkLogLines(task.body);
50
+ for (let i = logs.length - 1; i >= 0; i--) {
51
+ if (isCompletionRecord(logs[i].message)) {
52
+ const ms = Date.parse(`${logs[i].date}T${logs[i].time}`);
53
+ if (!Number.isNaN(ms))
54
+ return ms;
55
+ }
56
+ }
57
+ return parseIsoMs(task.updated);
58
+ }
59
+ /** 完了時刻 ms から日別ビンのキー (`YYYY-MM-DD`) を作る (ローカル日付) */
60
+ function dayKey(ms) {
61
+ const d = new Date(ms);
62
+ const y = d.getFullYear();
63
+ const m = String(d.getMonth() + 1).padStart(2, '0');
64
+ const day = String(d.getDate()).padStart(2, '0');
65
+ return `${y}-${m}-${day}`;
66
+ }
67
+ /** 完了時刻 ms からその週の月曜日のキー (`YYYY-MM-DD`) を作る (ISO 週・月曜起点・ローカル) */
68
+ function weekKey(ms) {
69
+ const d = new Date(ms);
70
+ d.setHours(0, 0, 0, 0);
71
+ // getDay(): 0=日曜。月曜を週頭にするため日曜は 6 日戻す
72
+ const offset = (d.getDay() + 6) % 7;
73
+ d.setDate(d.getDate() - offset);
74
+ return dayKey(d.getTime());
75
+ }
76
+ function median(sorted) {
77
+ const n = sorted.length;
78
+ if (n === 0)
79
+ return 0;
80
+ const mid = Math.floor(n / 2);
81
+ return n % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
82
+ }
83
+ /** ビン Map を key 昇順の配列にする */
84
+ function sortedBins(map) {
85
+ return [...map.entries()]
86
+ .map(([key, count]) => ({ key, count }))
87
+ .sort((a, b) => a.key.localeCompare(b.key));
88
+ }
89
+ /**
90
+ * タスク群と now (epoch ms) から統計を導出する純関数。
91
+ * @param tasks active board の tasks (done を含む)
92
+ * @param now 現在時刻 (epoch ms)。滞留計算の基準
93
+ * @param options.maxBottlenecks ボトルネック表示上限 (既定 5)
94
+ */
95
+ export function deriveStats(tasks, now, options = {}) {
96
+ const maxBottlenecks = options.maxBottlenecks ?? DEFAULT_MAX_BOTTLENECKS;
97
+ const doneTasks = tasks.filter((t) => t.status === 'done');
98
+ // 1. 完了数の推移 (日別 / 週別)
99
+ const byDay = new Map();
100
+ const byWeek = new Map();
101
+ // 2. サイクルタイム用サンプル (日)
102
+ const cycleDays = [];
103
+ // 4. member 別完了数
104
+ const byMember = new Map();
105
+ for (const task of doneTasks) {
106
+ const doneMs = completionMs(task);
107
+ byMember.set(task.assignee, (byMember.get(task.assignee) ?? 0) + 1);
108
+ if (doneMs === null)
109
+ continue;
110
+ byDay.set(dayKey(doneMs), (byDay.get(dayKey(doneMs)) ?? 0) + 1);
111
+ byWeek.set(weekKey(doneMs), (byWeek.get(weekKey(doneMs)) ?? 0) + 1);
112
+ const createdMs = parseIsoMs(task.created);
113
+ if (createdMs !== null && doneMs >= createdMs) {
114
+ cycleDays.push((doneMs - createdMs) / MS_PER_DAY);
115
+ }
116
+ }
117
+ const sortedCycle = [...cycleDays].sort((a, b) => a - b);
118
+ const cycleTime = {
119
+ sampleSize: sortedCycle.length,
120
+ medianDays: sortedCycle.length > 0 ? Math.round(median(sortedCycle) * 10) / 10 : null,
121
+ meanDays: sortedCycle.length > 0
122
+ ? Math.round((sortedCycle.reduce((s, v) => s + v, 0) / sortedCycle.length) * 10) / 10
123
+ : null,
124
+ };
125
+ // 3. ステータス別滞留 (now - updated)。近似 (現ステータスでの経過)
126
+ const dwellByStatus = TASK_STATUSES.map((status) => {
127
+ const group = tasks.filter((t) => t.status === status);
128
+ const dwells = group
129
+ .map((t) => parseIsoMs(t.updated))
130
+ .filter((ms) => ms !== null)
131
+ .map((ms) => now - ms);
132
+ if (dwells.length === 0) {
133
+ return { status, count: group.length, avgDays: null, maxDays: null };
134
+ }
135
+ const avgMs = dwells.reduce((s, v) => s + v, 0) / dwells.length;
136
+ return { status, count: group.length, avgDays: toDays(avgMs), maxDays: toDays(Math.max(...dwells)) };
137
+ });
138
+ // 4. member 別完了数 (件数降順 → member 名昇順、未割当は最後)
139
+ const completionsByMember = [...byMember.entries()]
140
+ .map(([member, count]) => ({ member, count }))
141
+ .sort((a, b) => b.count - a.count || (a.member ?? '￿').localeCompare(b.member ?? '￿'));
142
+ // 5. ボトルネック (pending を滞留降順、上位 maxBottlenecks 件)
143
+ const bottlenecks = tasks
144
+ .filter((t) => t.status === 'pending')
145
+ .map((t) => {
146
+ const updatedMs = parseIsoMs(t.updated);
147
+ return {
148
+ id: t.id,
149
+ title: t.title,
150
+ blockedType: t.blocked_type,
151
+ blockedReason: t.blocked_reason,
152
+ dwellDays: updatedMs !== null ? toDays(now - updatedMs) : 0,
153
+ };
154
+ })
155
+ .sort((a, b) => b.dwellDays - a.dwellDays || a.id.localeCompare(b.id, 'en', { numeric: true }))
156
+ .slice(0, maxBottlenecks);
157
+ return {
158
+ totalTasks: tasks.length,
159
+ doneTasks: doneTasks.length,
160
+ completionsByDay: sortedBins(byDay),
161
+ completionsByWeek: sortedBins(byWeek),
162
+ cycleTime,
163
+ dwellByStatus,
164
+ completionsByMember,
165
+ bottlenecks,
166
+ };
167
+ }
@@ -0,0 +1 @@
1
+ :root{--bg: #f4f5f7;--surface: #ffffff;--surface-alt: #ebecf0;--border: #dfe1e6;--text: #172b4d;--text-muted: #5e6c84;--accent: #0052cc;--accent-soft: #deebff;--danger: #de350b;--warn-bg: #fffae6;--warn-border: #ffab00;--human: #00875a;--ai: #6554c0;--priority-high: #de350b;--priority-medium: #ff991f;--priority-low: #6b778c;--blocked-decision: #6554c0;--blocked-external: #ff8b00;--blocked-dependency: #00a3bf;--radius: 6px;--shadow-card: 0 1px 2px rgba(9, 30, 66, .18);font-family:-apple-system,BlinkMacSystemFont,Hiragino Kaku Gothic ProN,Noto Sans JP,Segoe UI,Roboto,sans-serif;color:var(--text)}*{box-sizing:border-box}html,body,#root{margin:0;height:100%}body{background:var(--bg);font-size:14px;line-height:1.5}button{font-family:inherit;font-size:inherit;cursor:pointer}input,select,textarea{font-family:inherit;font-size:inherit}a{color:var(--accent)}._overlay_6l86f_1{position:fixed;top:0;right:0;bottom:0;left:0;background:#091e428a;display:flex;align-items:center;justify-content:center;padding:24px;z-index:100}._dialog_6l86f_12{background:var(--surface);border-radius:var(--radius);box-shadow:0 8px 24px #091e4252;width:100%;max-width:460px;max-height:90vh;overflow-y:auto;padding:20px 22px}._dialogWide_6l86f_23{max-width:720px}._title_6l86f_27{margin:0 0 14px;font-size:17px}._field_6l86f_32{display:flex;flex-direction:column;gap:4px;margin-bottom:14px}._label_6l86f_39{font-size:12px;font-weight:600;color:var(--text-muted)}._input_6l86f_45,._select_6l86f_46,._textarea_6l86f_47{border:1px solid var(--border);border-radius:4px;padding:7px 9px;width:100%}._input_6l86f_45:focus,._select_6l86f_46:focus,._textarea_6l86f_47:focus{outline:2px solid var(--accent);outline-offset:-1px;border-color:var(--accent)}._textarea_6l86f_47{resize:vertical;min-height:90px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}._actions_6l86f_69{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}._btn_6l86f_76{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:7px 14px;color:var(--text)}._btn_6l86f_76:hover{background:var(--surface-alt)}._btnPrimary_6l86f_88{background:var(--accent);border-color:var(--accent);color:#fff}._btnPrimary_6l86f_88:hover{background:#0747a6}._btnPrimary_6l86f_88:disabled{opacity:.5;cursor:not-allowed}._btnDanger_6l86f_103{background:var(--danger);border-color:var(--danger);color:#fff}._error_6l86f_109{color:var(--danger);font-size:12px;margin:0 0 12px}._wrap_g8rj0_1{display:flex;align-items:center;gap:6px}._track_g8rj0_7{flex:1;height:6px;background:var(--surface-alt);border-radius:3px;overflow:hidden}._fill_g8rj0_15{height:100%;background:var(--human);border-radius:3px;transition:width .2s ease}._fillComplete_g8rj0_22{background:var(--human)}._label_g8rj0_26{font-size:11px;color:var(--text-muted);white-space:nowrap}._card_gvp55_1{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow-card);padding:8px 10px;display:flex;flex-direction:column;gap:6px;cursor:grab;-webkit-user-select:none;user-select:none}._card_gvp55_1:hover{border-color:var(--accent)}._card_gvp55_1._dragging_gvp55_18{opacity:.4}._card_gvp55_1._inProgress_gvp55_22{border-left:3px solid var(--accent)}._topRow_gvp55_26{display:flex;justify-content:space-between;align-items:center;gap:6px}._id_gvp55_33{font-size:11px;font-weight:600;color:var(--text-muted);letter-spacing:.02em}._priority_gvp55_40{font-size:10px;font-weight:700;text-transform:uppercase;padding:1px 6px;border-radius:9px;color:#fff}._priorityhigh_gvp55_49{background:var(--priority-high)}._prioritymedium_gvp55_53{background:var(--priority-medium)}._prioritylow_gvp55_57{background:var(--priority-low)}._title_gvp55_61{font-weight:600;word-break:break-word}._metaRow_gvp55_66{display:flex;flex-wrap:wrap;align-items:center;gap:6px}._assignee_gvp55_73{display:inline-flex;align-items:center;gap:4px;font-size:11px;color:var(--text-muted)}._memberDot_gvp55_81{width:8px;height:8px;border-radius:50%;flex-shrink:0}._memberhuman_gvp55_88{background:var(--human)}._memberai_gvp55_92{background:var(--ai)}._memberunknown_gvp55_96{background:var(--text-muted)}._labels_gvp55_100{display:flex;flex-wrap:wrap;gap:4px}._label_gvp55_100{font-size:10px;background:var(--surface-alt);color:var(--text-muted);border-radius:3px;padding:0 5px}._elapsed_gvp55_114{font-size:11px;color:var(--text-muted);margin-left:auto}._elapsedStrong_gvp55_120{color:var(--accent);font-weight:600}._blocked_gvp55_125{display:flex;flex-direction:column;gap:3px;border-top:1px dashed var(--border);padding-top:5px}._blockedBadge_gvp55_133{align-self:flex-start;font-size:10px;font-weight:700;color:#fff;border-radius:3px;padding:1px 6px}._blockeddecision_gvp55_142{background:var(--blocked-decision)}._blockedexternal_gvp55_146{background:var(--blocked-external)}._blockeddependency_gvp55_150{background:var(--blocked-dependency)}._blockedReason_gvp55_154{font-size:11px;color:var(--text-muted);word-break:break-word}._proposalActions_gvp55_160{display:flex;gap:6px;justify-content:flex-end;border-top:1px dashed var(--border);padding-top:6px;cursor:default}._actionBtn_gvp55_169{font-size:11px;font-weight:600;border-radius:4px;padding:3px 10px;border:1px solid var(--border);background:var(--surface)}._approveBtn_gvp55_178{background:var(--human);border-color:var(--human);color:#fff}._rejectBtn_gvp55_184{color:var(--danger);border-color:var(--danger);background:var(--surface)}._column_141p8_1{display:flex;flex-direction:column;min-width:260px;max-width:300px;flex:1 0 260px;background:var(--surface-alt);border-radius:var(--radius);max-height:100%}._header_141p8_12{display:flex;align-items:center;justify-content:space-between;padding:10px 12px 6px;gap:6px}._columnOver_141p8_21{outline:2px solid var(--danger);outline-offset:-2px}._headerOver_141p8_26 ._label_141p8_26{color:var(--danger)}._label_141p8_26{font-weight:700;font-size:13px}._count_141p8_35{font-size:12px;color:var(--text-muted);background:var(--surface);border-radius:10px;padding:0 8px}._countOver_141p8_43{color:#fff;background:var(--danger)}._list_141p8_48{display:flex;flex-direction:column;gap:8px;padding:4px 8px 12px;overflow-y:auto;flex:1;min-height:40px}._over_141p8_58{background:var(--accent-soft);outline:2px dashed var(--accent);outline-offset:-2px;border-radius:var(--radius)}._empty_141p8_65{color:var(--text-muted);font-size:12px;text-align:center;padding:12px 0}._filterBar_10mhl_1{display:flex;align-items:center;gap:8px;padding:8px 16px;border-bottom:1px solid var(--border);background:var(--surface)}._search_10mhl_10{flex:0 1 280px;border:1px solid var(--border);border-radius:4px;padding:6px 9px}._filterBar_10mhl_1 select{border:1px solid var(--border);border-radius:4px;padding:6px 8px;background:var(--surface)}._filterSpacer_10mhl_24{flex:1}._archiveAllBtn_10mhl_28{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:6px 12px}._archiveAllBtn_10mhl_28:hover{background:var(--surface-alt)}._board_10mhl_39{display:flex;gap:12px;padding:8px 16px 16px;overflow-x:auto;flex:1;align-items:stretch}._overlay_es4xg_1{position:fixed;top:0;right:0;bottom:0;left:0;background:#091e428a;display:flex;align-items:flex-start;justify-content:center;padding:12vh 24px 24px;z-index:120}._palette_es4xg_12{background:var(--surface);border-radius:var(--radius);box-shadow:0 12px 32px #091e4266;width:100%;max-width:560px;max-height:70vh;display:flex;flex-direction:column;overflow:hidden}._input_es4xg_24{border:none;border-bottom:1px solid var(--border);padding:14px 16px;font-size:15px;width:100%;background:transparent;color:var(--text)}._input_es4xg_24:focus{outline:none;border-bottom-color:var(--accent)}._list_es4xg_39{list-style:none;margin:0;padding:6px;overflow-y:auto}._option_es4xg_46{padding:9px 12px;border-radius:6px;font-size:14px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}._optionActive_es4xg_56{background:var(--accent-soft)}._empty_es4xg_60{color:var(--text-muted);padding:18px 16px;font-size:13px;margin:0}._view_ruvk1_1{flex:1;overflow:auto;padding:12px 16px 16px}._toolbar_ruvk1_7{display:flex;align-items:center;gap:10px;margin-bottom:12px}._cycleWarn_ruvk1_14{background:var(--warn-bg);border:1px solid var(--warn-border);border-radius:var(--radius);padding:8px 12px;margin-bottom:12px;font-size:13px}._levels_ruvk1_23{display:flex;gap:24px;align-items:flex-start}._level_ruvk1_23{display:flex;flex-direction:column;gap:10px;min-width:220px}._levelLabel_ruvk1_36{font-size:11px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em}._node_ruvk1_44{background:var(--surface);border:1px solid var(--border);border-left:4px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow-card);padding:8px 10px;cursor:pointer;display:flex;flex-direction:column;gap:4px}._node_ruvk1_44:hover{border-color:var(--accent)}._nodeCp_ruvk1_61{border-left-color:var(--accent);background:var(--accent-soft)}._nodeCycle_ruvk1_66{border-left-color:var(--danger);background:var(--warn-bg)}._statusproposed_ruvk1_72,._statusbacklog_ruvk1_75{border-left-color:#8993a4}._statustodo_ruvk1_78{border-left-color:#5e6c84}._statusin_progress_ruvk1_81{border-left-color:var(--accent)}._statuspending_ruvk1_84{border-left-color:var(--priority-medium)}._nodeTop_ruvk1_88{display:flex;justify-content:space-between;gap:6px}._nodeId_ruvk1_94{font-size:11px;font-weight:700;color:var(--text-muted)}._cpTag_ruvk1_100{font-size:10px;font-weight:700;color:var(--accent)}._nodeTitle_ruvk1_106{font-weight:600;word-break:break-word}._deps_ruvk1_111{display:flex;flex-wrap:wrap;gap:4px;align-items:center}._depsLabel_ruvk1_118{font-size:10px;color:var(--text-muted)}._depChip_ruvk1_123{font-size:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--surface-alt);border-radius:3px;padding:0 5px}._pendingBadge_ruvk1_131{align-self:flex-start;font-size:10px;font-weight:700;color:#fff;background:var(--priority-medium);border-radius:3px;padding:1px 6px}._empty_ruvk1_141{color:var(--text-muted);padding:24px;text-align:center}._copyBtn_ruvk1_147{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:6px 12px;color:var(--accent)}._copyBtn_ruvk1_147:hover{background:var(--accent-soft)}._view_6tawd_1{flex:1;overflow:auto;padding:12px 16px 16px;max-width:820px}._day_6tawd_8{margin-bottom:20px}._dayHeader_6tawd_12{display:flex;align-items:baseline;gap:10px;border-bottom:2px solid var(--border);padding-bottom:4px;margin-bottom:8px}._date_6tawd_21{font-size:15px;font-weight:700}._count_6tawd_26{font-size:12px;color:var(--text-muted)}._entry_6tawd_31{display:flex;gap:10px;align-items:baseline;padding:3px 0;font-size:13px}._time_6tawd_39{flex:0 0 auto;color:var(--text-muted);font-variant-numeric:tabular-nums;font-size:12px}._taskId_6tawd_46{flex:0 0 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted)}._member_6tawd_53{flex:0 0 auto;display:inline-flex;align-items:center;gap:4px;font-weight:600}._memberDot_6tawd_61{width:7px;height:7px;border-radius:50%}._memberhuman_6tawd_67{background:var(--human)}._memberai_6tawd_71{background:var(--ai)}._memberunknown_6tawd_75{background:var(--text-muted)}._message_6tawd_79{word-break:break-word}._empty_6tawd_83{color:var(--text-muted);padding:24px;text-align:center}._view_1ko9s_1{flex:1;display:flex;overflow:hidden}._tree_1ko9s_8{flex:0 0 280px;overflow-y:auto;border-right:1px solid var(--border);background:var(--surface);padding:12px}._treeTitle_1ko9s_16{font-size:13px;font-weight:700;margin:0 0 8px}._treeRoot_1ko9s_22,._treeChildren_1ko9s_23{list-style:none;margin:0;padding:0}._treeChildren_1ko9s_23{padding-left:14px}._dirName_1ko9s_33{display:block;font-size:12px;font-weight:600;color:var(--text-muted);padding:4px 6px}._fileBtn_1ko9s_41{display:block;width:100%;text-align:left;border:none;background:transparent;color:var(--text);font-size:13px;padding:4px 6px;border-radius:4px;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._fileBtn_1ko9s_41:hover{background:var(--surface-alt)}._fileBtnActive_1ko9s_61{background:var(--accent-soft);color:var(--accent);font-weight:600}._detail_1ko9s_68{flex:1;overflow-y:auto;padding:14px 18px;max-width:880px}._docPath_1ko9s_75{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted);margin:0 0 10px}._refs_1ko9s_82{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:10px 12px;margin-bottom:14px}._refsTitle_1ko9s_90{font-size:12px;font-weight:700;margin:0 0 6px}._refsList_1ko9s_96{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}._refBtn_1ko9s_105{width:100%;text-align:left;border:none;background:transparent;color:var(--text);font-size:13px;padding:4px 6px;border-radius:4px;cursor:pointer;display:flex;align-items:baseline;gap:6px}._refBtn_1ko9s_105:hover{background:var(--surface-alt)}._refId_1ko9s_124{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted);flex:0 0 auto}._refStatus_1ko9s_131{margin-left:auto;font-size:11px;color:var(--text-muted);flex:0 0 auto}._markdown_1ko9s_138{font-size:14px;line-height:1.65;word-break:break-word}._markdown_1ko9s_138 pre{background:var(--surface-alt);padding:10px 12px;border-radius:6px;overflow-x:auto;font-size:12px}._markdown_1ko9s_138 code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.92em}._muted_1ko9s_157{color:var(--text-muted);font-size:13px}._broken_1ko9s_162{color:var(--danger);font-size:13px}._error_1ko9s_167{color:var(--danger);font-size:12px;margin:0 0 10px}._view_1b67y_1{flex:1;display:flex;min-height:0}._sidebar_1b67y_7{flex:0 0 280px;border-right:1px solid var(--border);overflow-y:auto;padding:12px}._sectionTitle_1b67y_14{font-size:11px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin:12px 0 4px}._fileItem_1b67y_23{display:block;width:100%;text-align:left;border:none;background:transparent;padding:4px 6px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--text);cursor:pointer}._fileItem_1b67y_23:hover{background:var(--surface-alt)}._fileItemActive_1b67y_41{background:var(--accent-soft);color:var(--accent)}._tree_1b67y_46{font-size:12px}._treeDir_1b67y_50{font-weight:600;padding:3px 0;color:var(--text-muted)}._catalogItem_1b67y_56{padding:4px 0;font-size:12px}._catalogName_1b67y_61{font-weight:700}._catalogDesc_1b67y_65{color:var(--text-muted)}._main_1b67y_69{flex:1;display:flex;flex-direction:column;min-width:0;padding:12px 16px}._mainHeader_1b67y_77{display:flex;align-items:center;gap:10px;margin-bottom:8px}._mainPath_1b67y_84{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:700;flex:1;word-break:break-all}._editor_1b67y_91{flex:1;min-height:320px;border:1px solid var(--border);border-radius:4px;padding:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;line-height:1.6;resize:none}._notice_1b67y_103{background:var(--warn-bg);border:1px solid var(--warn-border);border-radius:4px;padding:6px 10px;font-size:12px;margin-top:8px}._footer_1b67y_112{display:flex;align-items:center;gap:10px;margin-top:8px}._error_1b67y_119{color:var(--danger);font-size:12px}._saved_1b67y_124{color:var(--human);font-size:12px}._btn_1b67y_129{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:7px 14px}._btnPrimary_1b67y_136{background:var(--accent);border-color:var(--accent);color:#fff}._btnPrimary_1b67y_136:disabled{opacity:.5;cursor:not-allowed}._empty_1b67y_147{color:var(--text-muted);margin:auto}._view_znlga_1{flex:1;overflow:auto;padding:12px 16px 16px;max-width:820px}._sectionTitle_znlga_8{font-size:13px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin:16px 0 8px}._roadmap_znlga_17{display:flex;flex-direction:column;gap:2px}._milestone_znlga_23{display:flex;align-items:center;gap:12px;padding:10px 12px;border-left:3px solid var(--border);background:var(--surface)}._milestoneactive_znlga_32{border-left-color:var(--accent)}._milestonedone_znlga_36{border-left-color:var(--human)}._milestoneplanned_znlga_40{border-left-color:var(--text-muted)}._msInfo_znlga_44{flex:1;min-width:0}._msTitle_znlga_49{font-weight:700}._msStatus_znlga_53{font-size:11px;color:var(--text-muted)}._msProgress_znlga_58{flex:0 0 180px}._month_znlga_62{margin-bottom:16px}._monthHeader_znlga_66{font-size:14px;font-weight:700;border-bottom:1px solid var(--border);padding-bottom:4px;margin-bottom:6px}._histEntry_znlga_74{display:flex;gap:10px;padding:3px 0;font-size:13px;cursor:pointer}._histEntry_znlga_74:hover{color:var(--accent)}._histId_znlga_86{flex:0 0 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted)}._histTitle_znlga_93{font-weight:600;flex:0 0 auto}._histSummary_znlga_98{color:var(--text-muted);word-break:break-word}._empty_znlga_103{color:var(--text-muted);padding:24px;text-align:center}._section_1cnyn_1{margin-bottom:18px}._sectionTitle_1cnyn_5{font-size:12px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 8px}._modeBox_1cnyn_14{background:var(--accent-soft);border:1px solid var(--accent);border-radius:var(--radius);padding:12px;margin-bottom:18px}._memberRow_1cnyn_22{display:flex;gap:8px;align-items:center;margin-bottom:6px}._memberRow_1cnyn_22 input,._memberRow_1cnyn_22 select{border:1px solid var(--border);border-radius:4px;padding:5px 8px}._memberId_1cnyn_36{flex:1}._removeBtn_1cnyn_40{border:1px solid var(--border);background:var(--surface);color:var(--danger);border-radius:4px;padding:4px 10px}._addBtn_1cnyn_48{border:1px dashed var(--border);background:var(--surface);border-radius:4px;padding:5px 12px;color:var(--accent);margin-top:4px}._advanced_1cnyn_57 summary{cursor:pointer;font-size:12px;font-weight:600;color:var(--text-muted);margin-bottom:8px}._jsonEditor_1cnyn_65{width:100%;min-height:160px;border:1px solid var(--border);border-radius:4px;padding:8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;resize:vertical}._saved_1cnyn_76{color:var(--human);font-size:12px}._reloadBtn_1cnyn_82{margin-left:6px;padding:2px 8px;font-size:12px;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface-alt);color:var(--text);cursor:pointer}._view_1nb8r_1{flex:1;overflow:auto;padding:12px 16px 16px;max-width:820px;display:flex;flex-direction:column;gap:16px}._card_1nb8r_11{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow-card);padding:14px 16px}._cardHead_1nb8r_19{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}._cardTitle_1nb8r_27{font-size:14px;font-weight:700;margin:0 0 10px}._cardHead_1nb8r_19 ._cardTitle_1nb8r_27{margin-bottom:0}._note_1nb8r_37{font-size:12px;color:var(--text-muted);margin:4px 0 10px;line-height:1.5}._metrics_1nb8r_45{display:flex;gap:24px;flex-wrap:wrap;align-items:flex-end}._metric_1nb8r_45{display:flex;flex-direction:column;gap:2px}._metricValue_1nb8r_58{font-size:26px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1.1}._metricLabel_1nb8r_65,._metricSub_1nb8r_70{font-size:12px;color:var(--text-muted)}._toggle_1nb8r_76{display:inline-flex;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}._toggleBtn_1nb8r_83{border:none;background:var(--surface-alt);color:var(--text);font-size:12px;padding:4px 10px;cursor:pointer}._toggleBtn_1nb8r_83+._toggleBtn_1nb8r_83{border-left:1px solid var(--border)}._toggleActive_1nb8r_96{background:var(--accent);color:#fff}._chartWrap_1nb8r_102{margin-top:10px;overflow-x:auto}._chart_1nb8r_102{display:block;width:100%;max-height:160px;height:auto}._bar_1nb8r_114{fill:var(--accent)}._barCount_1nb8r_118{fill:var(--text-muted);font-size:10px;font-variant-numeric:tabular-nums}._barLabel_1nb8r_124{fill:var(--text-muted);font-size:9px;font-variant-numeric:tabular-nums}._table_1nb8r_131{width:100%;border-collapse:collapse;font-size:13px}._table_1nb8r_131 caption{text-align:left}._table_1nb8r_131 th,._table_1nb8r_131 td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);vertical-align:top}._table_1nb8r_131 th{font-size:11px;color:var(--text-muted);font-weight:600}._table_1nb8r_131 td{font-variant-numeric:tabular-nums}._bId_1nb8r_159{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted)}._empty_1nb8r_165{color:var(--text-muted);padding:24px;text-align:center}._srOnly_1nb8r_172{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}._intro_9mryh_1{color:var(--text-muted);margin:0 0 12px}._diff_9mryh_6{border:1px solid var(--border);border-radius:4px;max-height:46vh;overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5;background:var(--surface)}._line_9mryh_17{display:flex;white-space:pre-wrap;word-break:break-word;padding:0 8px}._sign_9mryh_24{flex:0 0 16px;color:var(--text-muted);-webkit-user-select:none;user-select:none}._equal_9mryh_30{color:var(--text)}._add_9mryh_34{background:#e3fcef;color:#064}._remove_9mryh_39{background:#ffebe6;color:#bf2600}._legend_9mryh_44{display:flex;gap:14px;font-size:11px;color:var(--text-muted);margin:8px 0 0}._overlay_1vdme_1{position:fixed;top:0;right:0;bottom:0;left:0;background:#091e426b;display:flex;justify-content:flex-end;z-index:90}._panel_1vdme_10{background:var(--surface);width:100%;max-width:640px;height:100%;display:flex;flex-direction:column;box-shadow:-4px 0 16px #091e4240}._header_1vdme_20{display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid var(--border)}._id_1vdme_28{font-size:12px;font-weight:700;color:var(--text-muted)}._title_1vdme_34{font-size:16px;font-weight:700;flex:1;word-break:break-word}._copyBtn_1vdme_41{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:5px 10px;font-size:12px;color:var(--accent);white-space:nowrap}._copyBtn_1vdme_41:hover{background:var(--accent-soft)}._close_1vdme_55{border:none;background:transparent;font-size:20px;color:var(--text-muted);line-height:1;padding:4px 8px}._close_1vdme_55:hover{color:var(--text)}._tabs_1vdme_68{display:flex;gap:2px;padding:8px 18px 0;border-bottom:1px solid var(--border)}._tab_1vdme_68{border:none;background:transparent;padding:8px 14px;color:var(--text-muted);border-bottom:2px solid transparent;font-weight:600}._tab_1vdme_68:hover{color:var(--text)}._tabActive_1vdme_88{color:var(--accent);border-bottom-color:var(--accent)}._body_1vdme_93{flex:1;overflow-y:auto;padding:18px}._markdown_1vdme_99{line-height:1.7;word-break:break-word}._markdown_1vdme_99 h1,._markdown_1vdme_99 h2,._markdown_1vdme_99 h3{margin-top:1.2em}._markdown_1vdme_99 code{background:var(--surface-alt);border-radius:3px;padding:1px 4px;font-size:.9em}._markdown_1vdme_99 pre{background:var(--surface-alt);border-radius:4px;padding:10px;overflow-x:auto}._markdown_1vdme_99 table{border-collapse:collapse}._markdown_1vdme_99 th,._markdown_1vdme_99 td{border:1px solid var(--border);padding:4px 8px}._editor_1vdme_134{width:100%;min-height:360px;height:100%;border:1px solid var(--border);border-radius:4px;padding:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;line-height:1.6;resize:vertical}._timeline_1vdme_147{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}._entry_1vdme_156{display:flex;gap:10px;border-left:2px solid var(--border);padding-left:12px;position:relative}._entry_1vdme_156:before{content:"";position:absolute;left:-5px;top:4px;width:8px;height:8px;border-radius:50%;background:var(--accent)}._entryMeta_1vdme_175{flex:0 0 auto;font-size:11px;color:var(--text-muted);min-width:120px}._entryMember_1vdme_182{font-weight:700;color:var(--text)}._entryMessage_1vdme_187{word-break:break-word}._emptyTimeline_1vdme_191{color:var(--text-muted);font-size:13px}._footer_1vdme_196{display:flex;align-items:center;gap:10px;padding:12px 18px;border-top:1px solid var(--border)}._dirty_1vdme_204{color:var(--priority-medium);font-size:12px}._error_1vdme_209{color:var(--danger);font-size:12px;flex:1}._spacer_1vdme_215{flex:1}._btn_1vdme_219{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:7px 14px}._btn_1vdme_219:hover{background:var(--surface-alt)}._btnPrimary_1vdme_230{background:var(--accent);border-color:var(--accent);color:#fff}._btnPrimary_1vdme_230:disabled{opacity:.5;cursor:not-allowed}._commentInput_1vdme_241{display:flex;gap:8px;align-items:center;margin-top:12px;border-top:1px solid var(--border);padding-top:12px}._commentInput_1vdme_241 select{border:1px solid var(--border);border-radius:4px;padding:6px 8px}._commentField_1vdme_256{flex:1;border:1px solid var(--border);border-radius:4px;padding:6px 9px}._docsHint_1vdme_264{font-size:12px;color:var(--text-muted);background:var(--warn-bg);border:1px solid var(--warn-border);border-radius:4px;padding:6px 10px;margin:0 0 10px}._docsList_1vdme_274{list-style:none;margin:0 0 10px;padding:0;display:flex;flex-direction:column;gap:2px}._docRow_1vdme_283{display:flex;align-items:center;gap:8px}._docLink_1vdme_289{flex:1;text-align:left;border:none;background:transparent;color:var(--accent);padding:5px 6px;border-radius:4px;font-size:13px;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._docLink_1vdme_289:hover{background:var(--surface-alt)}._docLinkActive_1vdme_308{background:var(--accent-soft)}._docBroken_1vdme_312{font-size:11px;color:var(--danger);border:1px solid var(--danger);border-radius:4px;padding:1px 6px;flex:0 0 auto}._docRemove_1vdme_321{border:1px solid var(--border);background:var(--surface);border-radius:4px;padding:2px 8px;color:var(--text-muted);cursor:pointer;flex:0 0 auto}._docRemove_1vdme_321:disabled{opacity:.4;cursor:not-allowed}._docsActions_1vdme_336{margin:4px 0 10px}._docsPicker_1vdme_340{border:1px solid var(--border);border-radius:var(--radius);padding:8px 10px;margin-bottom:12px;max-height:200px;overflow-y:auto;background:var(--surface-alt)}._docsPreview_1vdme_350{border-top:2px solid var(--border);padding-top:10px}._docsPreviewPath_1vdme_355{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted);margin:0 0 8px}._banner_1p1es_1{background:var(--warn-bg);border:1px solid var(--warn-border);border-radius:var(--radius);margin:0 16px 12px;padding:8px 12px}._summary_1p1es_9{display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:600;list-style:none}._summary_1p1es_9::-webkit-details-marker{display:none}._icon_1p1es_22{font-size:15px}._list_1p1es_26{margin:8px 0 0;padding-left:20px;display:flex;flex-direction:column;gap:4px;font-size:13px}._item_1p1es_35{color:var(--text)}._kind_1p1es_39{display:inline-block;font-size:10px;font-weight:700;text-transform:uppercase;border-radius:3px;padding:0 5px;margin-right:6px;background:var(--warn-border);color:#fff}._path_1p1es_51{color:var(--text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}._renameBtn_1p1es_57{margin-left:8px;border:1px solid var(--accent);background:var(--surface);color:var(--accent);border-radius:4px;padding:1px 8px;font-size:11px}._renameBtn_1p1es_57:hover{background:var(--accent-soft)}._app_1br7f_1{display:flex;flex-direction:column;height:100%}._header_1br7f_7{display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--surface);border-bottom:1px solid var(--border)}._brand_1br7f_16{font-size:18px;font-weight:800;letter-spacing:.02em}._tabs_1br7f_22{display:flex;gap:2px;padding:0 16px;background:var(--surface);border-bottom:1px solid var(--border)}._tab_1br7f_22{border:none;background:transparent;padding:10px 16px;color:var(--text-muted);border-bottom:2px solid transparent;font-weight:600}._tab_1br7f_22:hover{color:var(--text)}._tabActive_1br7f_43{color:var(--accent);border-bottom-color:var(--accent)}._project_1br7f_48{color:var(--text-muted);font-size:13px}._spacer_1br7f_53{flex:1}._status_1br7f_57{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-muted)}._dot_1br7f_65{width:8px;height:8px;border-radius:50%}._dotOn_1br7f_71{background:var(--human)}._dotOff_1br7f_75{background:var(--priority-low)}._langSelect_1br7f_79{border:1px solid var(--border);border-radius:4px;padding:6px 8px;background:var(--surface);color:var(--text)}._settingsBtn_1br7f_87{border:1px solid var(--border);background:var(--surface);color:var(--text);border-radius:4px;padding:8px 14px}._settingsBtn_1br7f_87:hover{background:var(--surface-alt)}._addBtn_1br7f_99{background:var(--accent);color:#fff;border:none;border-radius:4px;padding:8px 16px;font-weight:600}._addBtn_1br7f_99:hover{background:#0747a6}._banner_1br7f_112{background:var(--danger);color:#fff;padding:8px 16px;font-size:13px;display:flex;align-items:center;gap:10px}._bannerClose_1br7f_122{margin-left:auto;background:transparent;border:1px solid rgba(255,255,255,.6);color:#fff;border-radius:3px;padding:1px 8px}._center_1br7f_131{display:flex;align-items:center;justify-content:center;flex:1;color:var(--text-muted)}._app_1fu9m_1{display:flex;flex-direction:column;height:100%}._header_1fu9m_7{display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--surface);border-bottom:1px solid var(--border)}._brand_1fu9m_16{font-size:18px;font-weight:800;letter-spacing:.02em}._mode_1fu9m_22{color:var(--text-muted);font-size:13px}._spacer_1fu9m_27{flex:1}._status_1fu9m_31{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-muted)}._dot_1fu9m_39{width:8px;height:8px;border-radius:50%}._dotOn_1fu9m_45{background:var(--human)}._dotOff_1fu9m_49{background:var(--priority-low)}._langSelect_1fu9m_53{border:1px solid var(--border);border-radius:4px;padding:4px 6px;font-size:12px;background:var(--surface);color:var(--text)}._banner_1fu9m_62{background:var(--danger);color:#fff;padding:8px 16px;font-size:13px}._center_1fu9m_70{flex:1;display:flex;align-items:center;justify-content:center;color:var(--text-muted)}._main_1fu9m_78{flex:1;overflow:auto;padding:16px;display:flex;flex-direction:column;gap:24px;max-width:980px}._sectionTitle_1fu9m_88{font-size:15px;font-weight:700;margin:0 0 10px}._cards_1fu9m_95{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px}._card_1fu9m_95{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow-card);padding:12px 14px}._cardName_1fu9m_109{font-size:14px;font-weight:700;margin:0}._cardDir_1fu9m_115{color:var(--text-muted);font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;margin:2px 0 10px}._counts_1fu9m_122{display:flex;flex-wrap:wrap;gap:8px 14px;margin:0}._count_1fu9m_122{display:flex;align-items:baseline;gap:4px}._count_1fu9m_122 dt{font-size:11px;color:var(--text-muted)}._count_1fu9m_122 dd{margin:0;font-size:13px;font-weight:700;font-variant-numeric:tabular-nums}._badges_1fu9m_147{display:flex;gap:6px;margin-top:10px;flex-wrap:wrap}._badgeWip_1fu9m_154{background:var(--danger);color:#fff;font-size:11px;border-radius:4px;padding:2px 8px}._badgeWarn_1fu9m_162{background:var(--warn-bg);border:1px solid var(--warn-border);font-size:11px;border-radius:4px;padding:2px 8px}._tableWrap_1fu9m_171{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}._table_1fu9m_171{width:100%;border-collapse:collapse;font-size:13px}._table_1fu9m_171 th,._table_1fu9m_171 td{text-align:left;padding:7px 10px;border-bottom:1px solid var(--border);vertical-align:top}._table_1fu9m_171 th{font-size:11px;color:var(--text-muted);font-weight:600}._taskId_1fu9m_199{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--text-muted)}._empty_1fu9m_205{color:var(--text-muted);font-size:13px;padding:12px 0}