create-walle 0.9.30 → 0.9.32
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/package.json +1 -1
- package/template/claude-task-manager/api-prompts.js +410 -5
- package/template/claude-task-manager/api-reviews.js +251 -3
- package/template/claude-task-manager/approval-agent.js +322 -24
- package/template/claude-task-manager/db.js +77 -13
- package/template/claude-task-manager/docs/codex-app-server-approvals.md +35 -1
- package/template/claude-task-manager/docs/postgres-concurrency-dgx-spark.html +407 -0
- package/template/claude-task-manager/docs/prompt-manager-redesign-proposal.html +667 -0
- package/template/claude-task-manager/docs/resume-ux-redesign.html +493 -0
- package/template/claude-task-manager/docs/review-redesign-proposal.html +892 -0
- package/template/claude-task-manager/docs/unified-auto-approver-proposal.html +520 -0
- package/template/claude-task-manager/git-utils.js +164 -26
- package/template/claude-task-manager/lib/agent-capabilities.js +26 -5
- package/template/claude-task-manager/lib/agent-cli-cache.js +1 -1
- package/template/claude-task-manager/lib/agent-presets.js +12 -0
- package/template/claude-task-manager/lib/agent-version-service.js +650 -0
- package/template/claude-task-manager/lib/approval-drift.js +57 -0
- package/template/claude-task-manager/lib/approval-hook.js +13 -0
- package/template/claude-task-manager/lib/auth-rules.js +6 -0
- package/template/claude-task-manager/lib/broadcast-payload-memo.js +109 -0
- package/template/claude-task-manager/lib/coding-agent-models.js +89 -8
- package/template/claude-task-manager/lib/db-owner-cooperative-scheduler.js +10 -1
- package/template/claude-task-manager/lib/document-review.js +75 -1
- package/template/claude-task-manager/lib/escalation-review.js +33 -3
- package/template/claude-task-manager/lib/headless-term-service.js +54 -9
- package/template/claude-task-manager/lib/mcp-risk.js +128 -0
- package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +51 -2
- package/template/claude-task-manager/lib/native-agent-model-args.js +149 -0
- package/template/claude-task-manager/lib/opencode-conversation-store.js +269 -0
- package/template/claude-task-manager/lib/permission-match.js +77 -5
- package/template/claude-task-manager/lib/read-pool-client.js +15 -6
- package/template/claude-task-manager/lib/restore-backoff.js +82 -0
- package/template/claude-task-manager/lib/runtime-registry.js +1 -0
- package/template/claude-task-manager/lib/scheduled-wake.js +42 -0
- package/template/claude-task-manager/lib/session-capture.js +33 -6
- package/template/claude-task-manager/lib/session-history.js +60 -3
- package/template/claude-task-manager/lib/session-jobs.js +19 -0
- package/template/claude-task-manager/lib/session-restore.js +5 -4
- package/template/claude-task-manager/lib/session-standup.js +2 -0
- package/template/claude-task-manager/lib/session-stream.js +9 -0
- package/template/claude-task-manager/lib/state-sync/cell-diff.js +31 -4
- package/template/claude-task-manager/lib/state-sync/restore-frame-hold.js +39 -0
- package/template/claude-task-manager/lib/tui-input-modes.js +40 -0
- package/template/claude-task-manager/lib/walle-ctm-history.js +103 -36
- package/template/claude-task-manager/lib/walle-session-model-catalog.js +7 -1
- package/template/claude-task-manager/lib/walle-token-chip.js +65 -0
- package/template/claude-task-manager/package.json +1 -1
- package/template/claude-task-manager/providers/claude-code.js +20 -1
- package/template/claude-task-manager/providers/codex-mcp-extract.js +33 -0
- package/template/claude-task-manager/providers/codex-mcp.js +23 -20
- package/template/claude-task-manager/providers/codex.js +65 -1
- package/template/claude-task-manager/public/css/prompts.css +345 -0
- package/template/claude-task-manager/public/css/reviews.css +248 -40
- package/template/claude-task-manager/public/css/walle-session.css +90 -26
- package/template/claude-task-manager/public/index.html +2031 -428
- package/template/claude-task-manager/public/js/document-review-links.js +255 -13
- package/template/claude-task-manager/public/js/file-context-menu.js +185 -0
- package/template/claude-task-manager/public/js/message-renderer.js +46 -1
- package/template/claude-task-manager/public/js/mobile-review-core.js +54 -0
- package/template/claude-task-manager/public/js/prompt-diff.js +55 -0
- package/template/claude-task-manager/public/js/prompt-editor-chrome.js +108 -0
- package/template/claude-task-manager/public/js/prompt-editor-modes.js +87 -0
- package/template/claude-task-manager/public/js/prompt-organize.js +179 -0
- package/template/claude-task-manager/public/js/prompt-reuse.js +77 -0
- package/template/claude-task-manager/public/js/prompts.js +683 -215
- package/template/claude-task-manager/public/js/resume-state.js +186 -0
- package/template/claude-task-manager/public/js/reviews.js +402 -121
- package/template/claude-task-manager/public/js/screenshot-router.js +91 -0
- package/template/claude-task-manager/public/js/session-search-utils.js +81 -0
- package/template/claude-task-manager/public/js/state-sync-client.js +134 -17
- package/template/claude-task-manager/public/js/stream-view.js +93 -20
- package/template/claude-task-manager/public/js/walle-session.js +183 -32
- package/template/claude-task-manager/public/js/walle.js +21 -9
- package/template/claude-task-manager/public/m/app.css +117 -0
- package/template/claude-task-manager/public/m/app.js +309 -3
- package/template/claude-task-manager/public/m/index.html +56 -1
- package/template/claude-task-manager/server.js +724 -305
- package/template/claude-task-manager/workers/db-owner-worker.js +8 -0
- package/template/claude-task-manager/workers/read-pool-worker.js +4 -0
- package/template/claude-task-manager/workers/state-detectors/claude-code.js +10 -1
- package/template/docs/proposals/2026-06-23-local-model-right-path.html +340 -0
- package/template/docs/proposals/2026-06-24-qlora-done-right.md +255 -0
- package/template/package.json +1 -1
- package/template/wall-e/api-walle.js +21 -3
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +27 -4
- package/template/wall-e/brain.js +50 -5
- package/template/wall-e/chat/force-compact.js +73 -0
- package/template/wall-e/chat.js +137 -9
- package/template/wall-e/coding/action-memory-policy.js +120 -1
- package/template/wall-e/coding/compaction-service.js +10 -3
- package/template/wall-e/coding/model-router.js +116 -0
- package/template/wall-e/coding-orchestrator.js +303 -11
- package/template/wall-e/coding-prompts.js +1 -1
- package/template/wall-e/docs/skill-self-heal-design.html +429 -0
- package/template/wall-e/llm/client.js +115 -6
- package/template/wall-e/llm/codex-cli.js +71 -23
- package/template/wall-e/llm/codex-cli.plugin.json +1 -0
- package/template/wall-e/llm/default-fallback.js +71 -11
- package/template/wall-e/llm/mlx-worker.js +0 -0
- package/template/wall-e/llm/mlx.js +46 -12
- package/template/wall-e/llm/provider-error.js +9 -3
- package/template/wall-e/llm/provider-health-state.js +561 -11
- package/template/wall-e/llm/registry.js +6 -0
- package/template/wall-e/llm/routing-policy.js +255 -25
- package/template/wall-e/llm/tool-call-validator.js +156 -0
- package/template/wall-e/skills/skill-dispatch-decision.js +82 -2
- package/template/wall-e/skills/skill-planner.js +72 -5
- package/template/wall-e/tools/command-registry.js +34 -0
- package/template/wall-e/training/gemma-e4b-qlora.js +197 -1
- package/template/wall-e/training/mlx_lora_launch.py +196 -0
- package/template/wall-e/training/training-coexistence.sh +87 -0
- package/template/wall-e/training/training-mem-guard.sh +76 -0
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" data-theme="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>CTM Review — Redesign Proposal</title>
|
|
7
|
+
<style>
|
|
8
|
+
/* ===== CTM theme tokens (copied verbatim from index.html so this mock reads native) ===== */
|
|
9
|
+
:root {
|
|
10
|
+
--bg: #1a1b26; --bg-light: #24283b; --bg-lighter: #2f3349; --bg-card: #24283b;
|
|
11
|
+
--bg-panel: #1f2335; --bg-elevated: #2b3045; --bg-input: #1a1b26;
|
|
12
|
+
--bg-hover: rgba(255,255,255,0.06); --code-bg: rgba(122,162,247,0.12);
|
|
13
|
+
--fg: #c0caf5; --fg-dim: #565f89; --fg-muted: #8b94bd;
|
|
14
|
+
--accent: #7aa2f7; --accent-hover: #89b4fa; --accent-fg: #0d1117; --accent-soft: rgba(122,162,247,0.13);
|
|
15
|
+
--green: #9ece6a; --success-soft: rgba(158,206,106,0.14);
|
|
16
|
+
--red: #f7768e; --danger-soft: rgba(247,118,142,0.14);
|
|
17
|
+
--yellow: #e0af68; --warning-soft: rgba(224,175,104,0.14);
|
|
18
|
+
--purple: #bb9af7; --border: #3b4261; --focus-ring: rgba(122,162,247,0.32);
|
|
19
|
+
--overlay-bg: rgba(5,8,15,0.72);
|
|
20
|
+
/* syntax (Tokyo Night) */
|
|
21
|
+
--syn-kw: #bb9af7; --syn-fn: #7aa2f7; --syn-str: #9ece6a; --syn-num: #ff9e64;
|
|
22
|
+
--syn-com: #565f89; --syn-type: #2ac3de; --syn-prop: #73daca; --syn-punc: #89ddff;
|
|
23
|
+
--diff-add-bg: rgba(158,206,106,0.16); --diff-add-gutter: rgba(158,206,106,0.30);
|
|
24
|
+
--diff-del-bg: rgba(247,118,142,0.16); --diff-del-gutter: rgba(247,118,142,0.30);
|
|
25
|
+
--shadow-lg: 0 18px 46px rgba(0,0,0,0.42), 0 0 0 1px rgba(255,255,255,0.03) inset;
|
|
26
|
+
}
|
|
27
|
+
html[data-theme="light"] {
|
|
28
|
+
--bg: #f6f7f9; --bg-light: #ffffff; --bg-lighter: #eceef2; --bg-card: #ffffff;
|
|
29
|
+
--bg-panel: #fafbfc; --bg-elevated: #ffffff; --bg-input: #ffffff;
|
|
30
|
+
--bg-hover: rgba(15,23,42,0.045); --code-bg: rgba(15,23,42,0.06);
|
|
31
|
+
--fg: #0f172a; --fg-dim: #3d4b5e; --fg-muted: #52606f;
|
|
32
|
+
--accent: #3b66e0; --accent-hover: #2c54c8; --accent-fg: #ffffff; --accent-soft: rgba(59,102,224,0.10);
|
|
33
|
+
--green: #15803d; --success-soft: rgba(21,128,61,0.10);
|
|
34
|
+
--red: #b91c1c; --danger-soft: rgba(185,28,28,0.10);
|
|
35
|
+
--yellow: #92400e; --warning-soft: rgba(146,64,14,0.10);
|
|
36
|
+
--purple: #7c3aed; --border: rgba(15,23,42,0.10); --focus-ring: rgba(59,102,224,0.32);
|
|
37
|
+
--overlay-bg: rgba(15,23,42,0.40);
|
|
38
|
+
--syn-kw: #7c3aed; --syn-fn: #2c54c8; --syn-str: #15803d; --syn-num: #b45309;
|
|
39
|
+
--syn-com: #94a3b8; --syn-type: #0e7490; --syn-prop: #0f766e; --syn-punc: #2563eb;
|
|
40
|
+
--diff-add-bg: rgba(21,128,61,0.10); --diff-add-gutter: rgba(21,128,61,0.28);
|
|
41
|
+
--diff-del-bg: rgba(185,28,28,0.10); --diff-del-gutter: rgba(185,28,28,0.28);
|
|
42
|
+
--shadow-lg: 0 24px 60px rgba(15,23,42,0.18), 0 8px 20px rgba(15,23,42,0.08), 0 0 0 1px rgba(15,23,42,0.04);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
46
|
+
html { scroll-behavior: smooth; }
|
|
47
|
+
body {
|
|
48
|
+
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif;
|
|
49
|
+
background: var(--bg); color: var(--fg);
|
|
50
|
+
line-height: 1.55; -webkit-font-smoothing: antialiased;
|
|
51
|
+
}
|
|
52
|
+
.mono { font-family: 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace; }
|
|
53
|
+
a { color: var(--accent); }
|
|
54
|
+
|
|
55
|
+
/* ===== proposal chrome ===== */
|
|
56
|
+
.topbar {
|
|
57
|
+
position: sticky; top: 0; z-index: 50;
|
|
58
|
+
display: flex; align-items: center; gap: 18px;
|
|
59
|
+
padding: 12px 26px; background: color-mix(in srgb, var(--bg) 86%, transparent);
|
|
60
|
+
backdrop-filter: blur(14px) saturate(1.1); border-bottom: 1px solid var(--border);
|
|
61
|
+
}
|
|
62
|
+
.topbar .brand { font-weight: 700; letter-spacing: -0.01em; font-size: 15px; }
|
|
63
|
+
.topbar .brand b { color: var(--accent); }
|
|
64
|
+
.topbar nav { display: flex; gap: 4px; margin-left: 6px; flex-wrap: wrap; }
|
|
65
|
+
.topbar nav a {
|
|
66
|
+
font-size: 12.5px; color: var(--fg-muted); text-decoration: none;
|
|
67
|
+
padding: 5px 10px; border-radius: 7px;
|
|
68
|
+
}
|
|
69
|
+
.topbar nav a:hover { background: var(--bg-hover); color: var(--fg); }
|
|
70
|
+
.topbar .spacer { flex: 1; }
|
|
71
|
+
.toggle {
|
|
72
|
+
display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
|
|
73
|
+
font-size: 12px; color: var(--fg-dim); background: var(--bg-light);
|
|
74
|
+
border: 1px solid var(--border); border-radius: 8px; padding: 6px 11px; user-select: none;
|
|
75
|
+
}
|
|
76
|
+
.toggle:hover { color: var(--fg); border-color: var(--accent); }
|
|
77
|
+
|
|
78
|
+
.wrap { max-width: 1180px; margin: 0 auto; padding: 0 26px 120px; }
|
|
79
|
+
.hero { padding: 64px 0 30px; }
|
|
80
|
+
.eyebrow {
|
|
81
|
+
font-size: 11px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
|
|
82
|
+
color: var(--accent); margin-bottom: 16px;
|
|
83
|
+
}
|
|
84
|
+
.hero h1 { font-size: 42px; line-height: 1.08; letter-spacing: -0.025em; font-weight: 750; max-width: 16ch; }
|
|
85
|
+
.hero h1 em { font-style: normal; color: var(--accent); }
|
|
86
|
+
.hero p.lead { margin-top: 18px; font-size: 17px; color: var(--fg-muted); max-width: 64ch; line-height: 1.6; }
|
|
87
|
+
.meta-row { margin-top: 26px; display: flex; gap: 22px; flex-wrap: wrap; font-size: 12.5px; color: var(--fg-dim); }
|
|
88
|
+
.meta-row b { color: var(--fg); font-weight: 600; }
|
|
89
|
+
|
|
90
|
+
section { padding: 46px 0; border-top: 1px solid var(--border); }
|
|
91
|
+
.sec-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 8px; }
|
|
92
|
+
.sec-num {
|
|
93
|
+
font-size: 12px; font-weight: 700; color: var(--accent); font-family: 'SF Mono', Menlo, monospace;
|
|
94
|
+
background: var(--accent-soft); border-radius: 6px; padding: 3px 8px;
|
|
95
|
+
}
|
|
96
|
+
h2 { font-size: 27px; letter-spacing: -0.02em; font-weight: 700; }
|
|
97
|
+
.sec-sub { color: var(--fg-muted); font-size: 15px; max-width: 70ch; margin: 14px 0 30px; line-height: 1.6; }
|
|
98
|
+
|
|
99
|
+
/* ===== issue audit cards ===== */
|
|
100
|
+
.issues { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 16px; }
|
|
101
|
+
.issue {
|
|
102
|
+
background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px;
|
|
103
|
+
padding: 20px 20px 18px; position: relative; overflow: hidden;
|
|
104
|
+
}
|
|
105
|
+
.issue::before {
|
|
106
|
+
content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--red);
|
|
107
|
+
}
|
|
108
|
+
.issue .tag {
|
|
109
|
+
display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
|
|
110
|
+
color: var(--red); background: var(--danger-soft); padding: 3px 8px; border-radius: 5px; margin-bottom: 11px;
|
|
111
|
+
}
|
|
112
|
+
.issue h3 { font-size: 15.5px; font-weight: 650; margin-bottom: 8px; }
|
|
113
|
+
.issue p { font-size: 13.5px; color: var(--fg-muted); line-height: 1.55; }
|
|
114
|
+
.issue code {
|
|
115
|
+
font-family: 'SF Mono', Menlo, monospace; font-size: 11.5px; color: var(--fg-dim);
|
|
116
|
+
background: var(--code-bg); padding: 1px 5px; border-radius: 4px;
|
|
117
|
+
}
|
|
118
|
+
.issue .fix {
|
|
119
|
+
margin-top: 13px; padding-top: 12px; border-top: 1px dashed var(--border);
|
|
120
|
+
font-size: 12.5px; color: var(--fg); display: flex; gap: 8px;
|
|
121
|
+
}
|
|
122
|
+
.issue .fix b { color: var(--green); font-weight: 700; flex-shrink: 0; }
|
|
123
|
+
|
|
124
|
+
/* ===== mock frame ===== */
|
|
125
|
+
.mock {
|
|
126
|
+
margin-top: 6px; border: 1px solid var(--border); border-radius: 14px; overflow: hidden;
|
|
127
|
+
box-shadow: var(--shadow-lg); background: var(--bg);
|
|
128
|
+
}
|
|
129
|
+
.mock-caption {
|
|
130
|
+
display: flex; align-items: center; gap: 9px; padding: 9px 14px;
|
|
131
|
+
background: var(--bg-lighter); border-bottom: 1px solid var(--border);
|
|
132
|
+
font-size: 11.5px; color: var(--fg-dim);
|
|
133
|
+
}
|
|
134
|
+
.dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
|
135
|
+
.dot.r { background: #ff5f57; } .dot.y { background: #febc2e; } .dot.g { background: #28c840; }
|
|
136
|
+
.mock-caption .url {
|
|
137
|
+
margin-left: 10px; font-family: 'SF Mono', Menlo, monospace; font-size: 11px;
|
|
138
|
+
color: var(--fg-muted); background: var(--bg); border: 1px solid var(--border);
|
|
139
|
+
border-radius: 7px; padding: 4px 12px; flex: 1;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* shared app shell inside mocks */
|
|
143
|
+
.shell-header {
|
|
144
|
+
display: flex; align-items: center; gap: 12px; padding: 11px 16px;
|
|
145
|
+
background: var(--bg-panel); border-bottom: 1px solid var(--border);
|
|
146
|
+
}
|
|
147
|
+
.breadcrumb { display: flex; align-items: center; gap: 7px; font-size: 13px; }
|
|
148
|
+
.breadcrumb .crumb { color: var(--fg-muted); display: inline-flex; align-items: center; gap: 6px; }
|
|
149
|
+
.breadcrumb .crumb.active { color: var(--fg); font-weight: 600; }
|
|
150
|
+
.breadcrumb .sep { color: var(--fg-dim); }
|
|
151
|
+
.pill-sel {
|
|
152
|
+
display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--fg);
|
|
153
|
+
background: var(--bg-light); border: 1px solid var(--border); border-radius: 8px; padding: 5px 11px; cursor: default;
|
|
154
|
+
}
|
|
155
|
+
.pill-sel svg { opacity: 0.6; }
|
|
156
|
+
.seg {
|
|
157
|
+
display: inline-flex; background: var(--bg-light); border: 1px solid var(--border);
|
|
158
|
+
border-radius: 9px; padding: 3px; gap: 2px;
|
|
159
|
+
}
|
|
160
|
+
.seg button {
|
|
161
|
+
font: inherit; font-size: 12px; color: var(--fg-muted); background: none; border: 0;
|
|
162
|
+
padding: 5px 12px; border-radius: 6px; cursor: pointer;
|
|
163
|
+
}
|
|
164
|
+
.seg button.on { background: var(--accent); color: var(--accent-fg); font-weight: 600; }
|
|
165
|
+
.grow { flex: 1; }
|
|
166
|
+
.searchbox {
|
|
167
|
+
display: flex; align-items: center; gap: 9px; background: var(--bg-input);
|
|
168
|
+
border: 1px solid var(--border); border-radius: 9px; padding: 7px 13px; color: var(--fg-dim); font-size: 13px;
|
|
169
|
+
}
|
|
170
|
+
.searchbox svg { flex-shrink: 0; opacity: 0.7; }
|
|
171
|
+
.kbd {
|
|
172
|
+
font-family: 'SF Mono', Menlo, monospace; font-size: 10.5px; color: var(--fg-dim);
|
|
173
|
+
border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; background: var(--bg);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* ===== HUB ===== */
|
|
177
|
+
.hub-body { padding: 22px 24px 30px; background: var(--bg); }
|
|
178
|
+
.hub-bigsearch {
|
|
179
|
+
display: flex; align-items: center; gap: 12px; background: var(--bg-light);
|
|
180
|
+
border: 1px solid var(--border); border-radius: 12px; padding: 13px 18px; margin-bottom: 22px;
|
|
181
|
+
}
|
|
182
|
+
.hub-bigsearch svg { opacity: 0.6; }
|
|
183
|
+
.hub-bigsearch .ph { color: var(--fg-dim); font-size: 15px; }
|
|
184
|
+
.hub-bigsearch .grow { flex: 1; }
|
|
185
|
+
.hub-cols { display: grid; grid-template-columns: 1.45fr 1fr; gap: 22px; }
|
|
186
|
+
.col-head {
|
|
187
|
+
display: flex; align-items: center; gap: 10px; margin-bottom: 13px;
|
|
188
|
+
}
|
|
189
|
+
.col-head h4 { font-size: 13px; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase; color: var(--fg-muted); }
|
|
190
|
+
.col-head .count {
|
|
191
|
+
font-size: 11px; color: var(--fg-dim); background: var(--bg-lighter);
|
|
192
|
+
border-radius: 20px; padding: 2px 9px; font-weight: 600;
|
|
193
|
+
}
|
|
194
|
+
.proj-card {
|
|
195
|
+
display: flex; align-items: center; gap: 14px; padding: 13px 15px; margin-bottom: 9px;
|
|
196
|
+
background: var(--bg-card); border: 1px solid var(--border); border-radius: 11px; cursor: pointer;
|
|
197
|
+
transition: border-color .12s, transform .12s;
|
|
198
|
+
}
|
|
199
|
+
.proj-card:hover { border-color: var(--accent); transform: translateX(2px); }
|
|
200
|
+
.proj-card .icn {
|
|
201
|
+
width: 36px; height: 36px; border-radius: 9px; flex-shrink: 0; display: grid; place-items: center;
|
|
202
|
+
background: var(--accent-soft); color: var(--accent);
|
|
203
|
+
}
|
|
204
|
+
.proj-card .body { flex: 1; min-width: 0; }
|
|
205
|
+
.proj-card .name { font-size: 14px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
|
|
206
|
+
.proj-card .name .star { color: var(--yellow); }
|
|
207
|
+
.proj-card .sub {
|
|
208
|
+
font-size: 11.5px; color: var(--fg-dim); margin-top: 3px; display: flex; gap: 10px; align-items: center;
|
|
209
|
+
font-family: 'SF Mono', Menlo, monospace;
|
|
210
|
+
}
|
|
211
|
+
.branch-chip {
|
|
212
|
+
display: inline-flex; align-items: center; gap: 5px; color: var(--purple);
|
|
213
|
+
background: color-mix(in srgb, var(--purple) 12%, transparent); border-radius: 6px; padding: 1px 7px;
|
|
214
|
+
font-family: 'SF Mono', Menlo, monospace; font-size: 10.5px;
|
|
215
|
+
}
|
|
216
|
+
.stat { display: inline-flex; gap: 8px; align-items: center; font-family: 'SF Mono', Menlo, monospace; font-size: 12px; }
|
|
217
|
+
.stat .add { color: var(--green); } .stat .del { color: var(--red); }
|
|
218
|
+
.filecount { font-size: 11px; color: var(--fg-muted); }
|
|
219
|
+
.doc-row {
|
|
220
|
+
display: flex; align-items: center; gap: 11px; padding: 10px 13px; margin-bottom: 7px;
|
|
221
|
+
background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; cursor: pointer;
|
|
222
|
+
}
|
|
223
|
+
.doc-row:hover { border-color: var(--accent); }
|
|
224
|
+
.doc-row .di { color: var(--accent); flex-shrink: 0; }
|
|
225
|
+
.doc-row .dn { font-size: 13px; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
226
|
+
.doc-row .dp { font-size: 11px; color: var(--fg-dim); font-family: 'SF Mono', Menlo, monospace; }
|
|
227
|
+
|
|
228
|
+
/* ===== MD reviewer ===== */
|
|
229
|
+
.md-layout { display: grid; grid-template-columns: 218px 1fr 250px; min-height: 460px; background: var(--bg); }
|
|
230
|
+
.outline { border-right: 1px solid var(--border); padding: 16px 12px; background: var(--bg-panel); }
|
|
231
|
+
.outline .ol-title { font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg-dim); margin: 0 6px 12px; }
|
|
232
|
+
.ol-item { font-size: 12.5px; color: var(--fg-muted); padding: 5px 8px; border-radius: 7px; cursor: pointer; display:block; border-left: 2px solid transparent; }
|
|
233
|
+
.ol-item:hover { background: var(--bg-hover); color: var(--fg); }
|
|
234
|
+
.ol-item.l2 { padding-left: 20px; font-size: 12px; }
|
|
235
|
+
.ol-item.l3 { padding-left: 34px; font-size: 11.5px; color: var(--fg-dim); }
|
|
236
|
+
.ol-item.active { color: var(--accent); background: var(--accent-soft); border-left-color: var(--accent); font-weight: 600; }
|
|
237
|
+
.md-reading { padding: 30px 40px; overflow: hidden; }
|
|
238
|
+
.md-reading .doc { max-width: 68ch; }
|
|
239
|
+
.md-reading h1 { font-size: 27px; font-weight: 720; letter-spacing: -0.02em; margin-bottom: 6px; }
|
|
240
|
+
.md-reading .doc > p.tagline { color: var(--fg-muted); font-size: 14px; margin-bottom: 22px; }
|
|
241
|
+
.md-reading h2 { font-size: 19px; font-weight: 650; margin: 26px 0 11px; padding-bottom: 7px; border-bottom: 1px solid var(--border); }
|
|
242
|
+
.md-reading p { font-size: 15px; line-height: 1.72; color: var(--fg); margin-bottom: 13px; }
|
|
243
|
+
.md-reading p code, .md-reading li code {
|
|
244
|
+
font-family: 'SF Mono', Menlo, monospace; font-size: 0.86em; color: var(--accent);
|
|
245
|
+
background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
|
|
246
|
+
border-radius: 5px; padding: 1px 6px;
|
|
247
|
+
}
|
|
248
|
+
.md-reading ul { margin: 0 0 14px 22px; }
|
|
249
|
+
.md-reading li { font-size: 15px; line-height: 1.7; margin-bottom: 5px; }
|
|
250
|
+
.codeblock {
|
|
251
|
+
background: var(--bg-lighter); border: 1px solid var(--border); border-radius: 10px;
|
|
252
|
+
margin: 6px 0 18px; overflow: hidden;
|
|
253
|
+
}
|
|
254
|
+
.codeblock .cb-head {
|
|
255
|
+
display: flex; align-items: center; justify-content: space-between; padding: 7px 13px;
|
|
256
|
+
background: color-mix(in srgb, var(--bg) 40%, var(--bg-lighter)); border-bottom: 1px solid var(--border);
|
|
257
|
+
font-size: 11px; color: var(--fg-dim); font-family: 'SF Mono', Menlo, monospace;
|
|
258
|
+
}
|
|
259
|
+
.codeblock pre { padding: 13px 15px; overflow-x: auto; font-family: 'SF Mono', Menlo, monospace; font-size: 12.5px; line-height: 1.65; }
|
|
260
|
+
.cm-rail { border-left: 1px solid var(--border); background: var(--bg-panel); padding: 16px 14px; }
|
|
261
|
+
.cm-rail .cr-title { font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg-dim); margin-bottom: 12px; }
|
|
262
|
+
.cmt {
|
|
263
|
+
background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 11px 12px; margin-bottom: 10px;
|
|
264
|
+
}
|
|
265
|
+
.cmt .who { font-size: 11.5px; font-weight: 600; color: var(--accent); margin-bottom: 5px; display: flex; align-items: center; gap: 6px; }
|
|
266
|
+
.cmt .what { font-size: 12.5px; color: var(--fg-muted); line-height: 1.5; }
|
|
267
|
+
.cmt .anchor { font-size: 10.5px; color: var(--fg-dim); font-family: 'SF Mono', Menlo, monospace; margin-top: 7px; }
|
|
268
|
+
.addcmt { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--fg-dim); padding: 9px 11px; border: 1px dashed var(--border); border-radius: 9px; cursor: pointer; }
|
|
269
|
+
.addcmt:hover { border-color: var(--accent); color: var(--fg); }
|
|
270
|
+
|
|
271
|
+
/* syntax colors */
|
|
272
|
+
.k { color: var(--syn-kw); } .fn { color: var(--syn-fn); } .s { color: var(--syn-str); }
|
|
273
|
+
.n { color: var(--syn-num); } .c { color: var(--syn-com); } .t { color: var(--syn-type); }
|
|
274
|
+
.pr { color: var(--syn-prop); } .pu { color: var(--syn-punc); }
|
|
275
|
+
|
|
276
|
+
/* ===== diff viewer ===== */
|
|
277
|
+
.diff-layout { display: grid; grid-template-columns: 256px 1fr; min-height: 470px; background: var(--bg); }
|
|
278
|
+
.ftree { border-right: 1px solid var(--border); background: var(--bg-panel); display: flex; flex-direction: column; }
|
|
279
|
+
.ftree-top { padding: 12px 12px 9px; border-bottom: 1px solid var(--border); }
|
|
280
|
+
.ftree .searchbox { padding: 6px 11px; font-size: 12px; }
|
|
281
|
+
.ftree-tools { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 11px; color: var(--fg-dim); }
|
|
282
|
+
.ftree-tools .seg button { padding: 3px 9px; font-size: 11px; }
|
|
283
|
+
.ftree-list { padding: 8px; overflow-y: auto; flex: 1; }
|
|
284
|
+
.ftree-folder { font-size: 11px; color: var(--fg-dim); padding: 6px 8px 3px; font-family: 'SF Mono', Menlo, monospace; letter-spacing: 0.02em; }
|
|
285
|
+
.ftree-file {
|
|
286
|
+
display: flex; align-items: center; gap: 9px; padding: 6px 9px; border-radius: 7px; cursor: pointer;
|
|
287
|
+
font-size: 12.5px; margin: 1px 0;
|
|
288
|
+
}
|
|
289
|
+
.ftree-file:hover { background: var(--bg-hover); }
|
|
290
|
+
.ftree-file.active { background: var(--accent-soft); }
|
|
291
|
+
.ftree-file.active .fname { color: var(--accent); font-weight: 600; }
|
|
292
|
+
.ftree-file .fdot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
|
|
293
|
+
.ftree-file .fname { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: 'SF Mono', Menlo, monospace; font-size: 12px; }
|
|
294
|
+
.ftree-file .fmini { font-family: 'SF Mono', Menlo, monospace; font-size: 10.5px; display: flex; gap: 6px; }
|
|
295
|
+
.ftree-file .fmini .a { color: var(--green); } .ftree-file .fmini .d { color: var(--red); }
|
|
296
|
+
.ftree-file .check { color: var(--green); }
|
|
297
|
+
.diff-main { overflow: hidden; display: flex; flex-direction: column; }
|
|
298
|
+
.diff-file-head {
|
|
299
|
+
position: sticky; top: 0; display: flex; align-items: center; gap: 12px; padding: 10px 16px;
|
|
300
|
+
background: var(--bg-lighter); border-bottom: 1px solid var(--border); z-index: 3;
|
|
301
|
+
}
|
|
302
|
+
.diff-file-head .fpath { font-family: 'SF Mono', Menlo, monospace; font-size: 12.5px; font-weight: 600; }
|
|
303
|
+
.diff-file-head .stat { margin-left: auto; }
|
|
304
|
+
.viewed-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--fg-dim); border: 1px solid var(--border); border-radius: 20px; padding: 3px 10px; }
|
|
305
|
+
.diff-table { width: 100%; border-collapse: collapse; font-family: 'SF Mono', Menlo, monospace; font-size: 12.5px; }
|
|
306
|
+
.diff-table td { padding: 1px 0; vertical-align: top; }
|
|
307
|
+
.gutter { width: 44px; text-align: right; padding: 1px 10px 1px 0 !important; color: var(--fg-dim); user-select: none; opacity: 0.65; }
|
|
308
|
+
.diff-code { padding-left: 14px !important; white-space: pre; padding-right: 16px !important; }
|
|
309
|
+
tr.add .diff-code { background: var(--diff-add-bg); box-shadow: inset 3px 0 0 var(--diff-add-gutter); }
|
|
310
|
+
tr.add .gutter.new { background: var(--diff-add-bg); }
|
|
311
|
+
tr.del .diff-code { background: var(--diff-del-bg); box-shadow: inset 3px 0 0 var(--diff-del-gutter); }
|
|
312
|
+
tr.del .gutter.old { background: var(--diff-del-bg); }
|
|
313
|
+
.hunk td { background: var(--accent-soft); color: var(--accent); padding: 5px 14px; font-size: 11.5px; }
|
|
314
|
+
.signp { color: var(--green); } .signm { color: var(--red); }
|
|
315
|
+
.diff-foot { margin-top: auto; display: flex; gap: 16px; padding: 9px 16px; border-top: 1px solid var(--border); background: var(--bg-panel); font-size: 11px; color: var(--fg-dim); }
|
|
316
|
+
.diff-foot .kbd { margin-right: 3px; }
|
|
317
|
+
|
|
318
|
+
/* ===== clickable files ===== */
|
|
319
|
+
.ck-layout { display: grid; grid-template-columns: 1fr 280px; gap: 24px; align-items: start; }
|
|
320
|
+
.terminal-out {
|
|
321
|
+
background: var(--bg-lighter); border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px;
|
|
322
|
+
font-family: 'SF Mono', Menlo, monospace; font-size: 12.5px; line-height: 1.85; color: var(--fg-muted);
|
|
323
|
+
}
|
|
324
|
+
.terminal-out .pfx { color: var(--green); }
|
|
325
|
+
.flink {
|
|
326
|
+
color: var(--accent); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
|
|
327
|
+
text-underline-offset: 2px; cursor: pointer; position: relative;
|
|
328
|
+
}
|
|
329
|
+
.flink:hover { text-decoration-color: var(--accent); background: var(--accent-soft); border-radius: 3px; }
|
|
330
|
+
.flink .badge {
|
|
331
|
+
font-family: -apple-system, system-ui; font-size: 9px; font-weight: 700; letter-spacing: 0.04em;
|
|
332
|
+
text-transform: uppercase; vertical-align: super; margin-left: 3px; opacity: 0.7;
|
|
333
|
+
}
|
|
334
|
+
.ctxmenu {
|
|
335
|
+
width: 250px; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 11px;
|
|
336
|
+
box-shadow: var(--shadow-lg); padding: 6px; position: relative;
|
|
337
|
+
}
|
|
338
|
+
.ctxmenu .ctx-head {
|
|
339
|
+
font-size: 10.5px; color: var(--fg-dim); font-family: 'SF Mono', Menlo, monospace;
|
|
340
|
+
padding: 7px 10px 8px; border-bottom: 1px solid var(--border); margin-bottom: 5px;
|
|
341
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
342
|
+
}
|
|
343
|
+
.ctx-item { display: flex; align-items: center; gap: 11px; padding: 8px 10px; border-radius: 7px; font-size: 13px; cursor: pointer; color: var(--fg); }
|
|
344
|
+
.ctx-item:hover { background: var(--accent); color: var(--accent-fg); }
|
|
345
|
+
.ctx-item:hover .meta { color: var(--accent-fg); opacity: 0.8; }
|
|
346
|
+
.ctx-item:hover svg { color: var(--accent-fg); }
|
|
347
|
+
.ctx-item svg { color: var(--fg-muted); flex-shrink: 0; }
|
|
348
|
+
.ctx-item .meta { margin-left: auto; font-size: 10.5px; color: var(--fg-dim); font-family: 'SF Mono', Menlo, monospace; }
|
|
349
|
+
.ctx-item.primary { color: var(--accent); }
|
|
350
|
+
.ctx-sep { height: 1px; background: var(--border); margin: 5px 6px; }
|
|
351
|
+
.ck-note { font-size: 13px; color: var(--fg-muted); margin-top: 16px; line-height: 1.6; }
|
|
352
|
+
.ck-note b { color: var(--fg); }
|
|
353
|
+
.route-table { width: 100%; border-collapse: collapse; margin-top: 16px; font-size: 12.5px; }
|
|
354
|
+
.route-table th { text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--fg-dim); padding: 8px 12px; border-bottom: 1px solid var(--border); font-weight: 700; }
|
|
355
|
+
.route-table td { padding: 9px 12px; border-bottom: 1px solid var(--border); color: var(--fg-muted); }
|
|
356
|
+
.route-table td .ext { font-family: 'SF Mono', Menlo, monospace; color: var(--accent); }
|
|
357
|
+
.route-table td b { color: var(--fg); font-weight: 600; }
|
|
358
|
+
|
|
359
|
+
/* ===== alternative + close ===== */
|
|
360
|
+
.alt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-top: 8px; }
|
|
361
|
+
.alt-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; }
|
|
362
|
+
.alt-card.rec { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-soft); }
|
|
363
|
+
.alt-card h4 { font-size: 15px; margin-bottom: 4px; display: flex; align-items: center; gap: 9px; }
|
|
364
|
+
.alt-card .rectag { font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--accent-fg); background: var(--accent); padding: 2px 8px; border-radius: 20px; }
|
|
365
|
+
.alt-card .sub { font-size: 12.5px; color: var(--fg-dim); margin-bottom: 13px; }
|
|
366
|
+
.alt-card ul { list-style: none; }
|
|
367
|
+
.alt-card li { font-size: 13px; color: var(--fg-muted); padding: 5px 0 5px 22px; position: relative; line-height: 1.5; }
|
|
368
|
+
.alt-card li::before { content: '→'; position: absolute; left: 0; color: var(--accent); }
|
|
369
|
+
.alt-card li.con::before { content: '×'; color: var(--red); }
|
|
370
|
+
|
|
371
|
+
.roadmap { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }
|
|
372
|
+
.phase { display: flex; gap: 16px; padding: 16px 18px; background: var(--bg-card); border: 1px solid var(--border); }
|
|
373
|
+
.phase:first-child { border-radius: 12px 12px 0 0; }
|
|
374
|
+
.phase:last-child { border-radius: 0 0 12px 12px; }
|
|
375
|
+
.phase .pn { font-family: 'SF Mono', Menlo, monospace; font-size: 13px; font-weight: 700; color: var(--accent); flex-shrink: 0; width: 64px; }
|
|
376
|
+
.phase .pbody h4 { font-size: 14px; margin-bottom: 4px; }
|
|
377
|
+
.phase .pbody p { font-size: 12.5px; color: var(--fg-muted); }
|
|
378
|
+
.phase .pbody code { font-family: 'SF Mono', Menlo, monospace; font-size: 11.5px; color: var(--fg-dim); background: var(--code-bg); padding: 1px 5px; border-radius: 4px; }
|
|
379
|
+
|
|
380
|
+
footer { padding: 50px 0 0; border-top: 1px solid var(--border); color: var(--fg-dim); font-size: 12.5px; }
|
|
381
|
+
footer a { color: var(--fg-muted); }
|
|
382
|
+
|
|
383
|
+
@media (max-width: 900px) {
|
|
384
|
+
.hub-cols, .ck-layout, .alt-grid { grid-template-columns: 1fr; }
|
|
385
|
+
.md-layout { grid-template-columns: 1fr; } .outline, .cm-rail { display: none; }
|
|
386
|
+
.diff-layout { grid-template-columns: 1fr; } .ftree { display: none; }
|
|
387
|
+
.hero h1 { font-size: 32px; }
|
|
388
|
+
}
|
|
389
|
+
</style>
|
|
390
|
+
</head>
|
|
391
|
+
<body>
|
|
392
|
+
|
|
393
|
+
<div class="topbar">
|
|
394
|
+
<div class="brand">CTM <b>Review</b> — Redesign Proposal</div>
|
|
395
|
+
<nav>
|
|
396
|
+
<a href="#audit">Issues</a>
|
|
397
|
+
<a href="#hub">Hub</a>
|
|
398
|
+
<a href="#md">Markdown</a>
|
|
399
|
+
<a href="#diff">Diff</a>
|
|
400
|
+
<a href="#click">Clickable files</a>
|
|
401
|
+
<a href="#alt">Alternative</a>
|
|
402
|
+
<a href="#plan">Plan</a>
|
|
403
|
+
</nav>
|
|
404
|
+
<div class="spacer"></div>
|
|
405
|
+
<div class="toggle" onclick="toggleTheme()">
|
|
406
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2M5 5l1.5 1.5M17.5 17.5L19 19M19 5l-1.5 1.5M6.5 17.5L5 19"/></svg>
|
|
407
|
+
<span id="themeLabel">Dark</span>
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<div class="wrap">
|
|
412
|
+
|
|
413
|
+
<div class="hero">
|
|
414
|
+
<div class="eyebrow">Design proposal · v1</div>
|
|
415
|
+
<h1>The review page should feel like <em>one place</em>, not three.</h1>
|
|
416
|
+
<p class="lead">
|
|
417
|
+
Today the Review tab is really three disconnected surfaces — a markdown reviewer, a source-diff tool,
|
|
418
|
+
and session-transcript review — with no shared home, almost no discovery, and viewers that read as plain text.
|
|
419
|
+
This proposal unifies <b>markdown</b> and <b>source-diff</b> review under a single, searchable hub, gives both
|
|
420
|
+
viewers a proper reading experience, and makes file references in your sessions actually clickable.
|
|
421
|
+
</p>
|
|
422
|
+
<div class="meta-row">
|
|
423
|
+
<div><b>Scope</b> · Review Hub + viewers + clickable files</div>
|
|
424
|
+
<div><b>Stays put</b> · Session-transcript review lives with Sessions</div>
|
|
425
|
+
<div><b>Theme</b> · native CTM tokens — toggle top-right</div>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
|
|
429
|
+
<!-- ===================== AUDIT ===================== -->
|
|
430
|
+
<section id="audit">
|
|
431
|
+
<div class="sec-head"><span class="sec-num">01</span><h2>What's broken today</h2></div>
|
|
432
|
+
<p class="sec-sub">Each issue below is traced to the responsible code so the redesign targets causes, not symptoms.</p>
|
|
433
|
+
<div class="issues">
|
|
434
|
+
<div class="issue">
|
|
435
|
+
<span class="tag">Navigation</span>
|
|
436
|
+
<h3>You can't tell where you are</h3>
|
|
437
|
+
<p><code>#review</code> aliases to <code>codereview</code>; markdown and source-diff <em>share</em> one panel while transcript review is another. No breadcrumb, no shared shell.</p>
|
|
438
|
+
<div class="fix"><b>FIX</b><span>One shared header with a live breadcrumb across both viewers.</span></div>
|
|
439
|
+
</div>
|
|
440
|
+
<div class="issue">
|
|
441
|
+
<span class="tag">Discovery</span>
|
|
442
|
+
<h3>No way to find what to review</h3>
|
|
443
|
+
<p>Only <em>code</em> has a chooser (<code>CR.showProjectList</code>). Markdown review has <b>no browse or search at all</b> — it only opens from a link.</p>
|
|
444
|
+
<div class="fix"><b>FIX</b><span>A Review Hub home: global search + Changed-Code and Documents discovery.</span></div>
|
|
445
|
+
</div>
|
|
446
|
+
<div class="issue">
|
|
447
|
+
<span class="tag">Markdown</span>
|
|
448
|
+
<h3>The doc viewer reads flat</h3>
|
|
449
|
+
<p><code>marked</code>+DOMPurify with <b>no syntax highlighting</b>, faint inline-code, hover-hidden comment buttons, and an outline that shows raw headings only.</p>
|
|
450
|
+
<div class="fix"><b>FIX</b><span>Highlighted code, real reading measure, outline scroll-spy, visible affordances.</span></div>
|
|
451
|
+
</div>
|
|
452
|
+
<div class="issue">
|
|
453
|
+
<span class="tag">Source diff</span>
|
|
454
|
+
<h3>The good diff tool is buried</h3>
|
|
455
|
+
<p>Custom parser, <b>no highlighting</b>, 8%-opacity colors, a single base-ref <code><select></code>, and no project / worktree switching inside the viewer.</p>
|
|
456
|
+
<div class="fix"><b>FIX</b><span>In-viewer switcher, searchable file tree, highlighted diffs, keyboard nav.</span></div>
|
|
457
|
+
</div>
|
|
458
|
+
<div class="issue">
|
|
459
|
+
<span class="tag">Clickable files</span>
|
|
460
|
+
<h3>Links only work for markdown</h3>
|
|
461
|
+
<p><code>document-review-links.js</code> linkifies only <code>.md</code>/<code>.txt</code>. No <code>.html</code>, no source-code → diff, <b>no right-click menu</b>.</p>
|
|
462
|
+
<div class="fix"><b>FIX</b><span>Smart left-click by type + a right-click menu with every target.</span></div>
|
|
463
|
+
</div>
|
|
464
|
+
<div class="issue" style="--red: var(--green);">
|
|
465
|
+
<span class="tag" style="color: var(--green); background: var(--success-soft);">Reusable</span>
|
|
466
|
+
<h3>What's already good</h3>
|
|
467
|
+
<p>The token system (light + dark), the structured diff/document APIs, and entry points like <code>CR.openReview</code> / <code>selectFile</code> all stay — this is mostly front-end.</p>
|
|
468
|
+
<div class="fix"><b>KEEP</b><span>No backend rewrite; two small additive endpoints only.</span></div>
|
|
469
|
+
</div>
|
|
470
|
+
</div>
|
|
471
|
+
</section>
|
|
472
|
+
|
|
473
|
+
<!-- ===================== HUB ===================== -->
|
|
474
|
+
<section id="hub">
|
|
475
|
+
<div class="sec-head"><span class="sec-num">02</span><h2>The Review Hub — one home</h2></div>
|
|
476
|
+
<p class="sec-sub">
|
|
477
|
+
A single landing that answers "what can I review right now?" Search across everything, then drop into the right viewer.
|
|
478
|
+
<b>Changed Code</b> lists projects and worktrees with live change counts; <b>Documents</b> surfaces markdown that was never discoverable before.
|
|
479
|
+
</p>
|
|
480
|
+
<div class="mock">
|
|
481
|
+
<div class="mock-caption">
|
|
482
|
+
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
|
483
|
+
<span class="url">localhost:3456/#review</span>
|
|
484
|
+
</div>
|
|
485
|
+
<div class="shell-header">
|
|
486
|
+
<div class="breadcrumb"><span class="crumb active">Review</span></div>
|
|
487
|
+
<div class="grow"></div>
|
|
488
|
+
<div class="seg"><button class="on">All</button><button>Code</button><button>Docs</button></div>
|
|
489
|
+
</div>
|
|
490
|
+
<div class="hub-body">
|
|
491
|
+
<div class="hub-bigsearch">
|
|
492
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4-4"/></svg>
|
|
493
|
+
<span class="ph">Search projects, worktrees, and documents…</span>
|
|
494
|
+
<div class="grow"></div>
|
|
495
|
+
<span class="kbd">⌘K</span>
|
|
496
|
+
</div>
|
|
497
|
+
<div class="hub-cols">
|
|
498
|
+
<div>
|
|
499
|
+
<div class="col-head"><h4>Changed Code</h4><span class="count">4 with changes</span></div>
|
|
500
|
+
|
|
501
|
+
<div class="proj-card">
|
|
502
|
+
<div class="icn"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7l9-4 9 4-9 4-9-4z"/><path d="M3 7v10l9 4 9-4V7"/></svg></div>
|
|
503
|
+
<div class="body">
|
|
504
|
+
<div class="name"><span class="star">★</span> tools <span class="branch-chip">⎇ perf-offload-onmain-git</span></div>
|
|
505
|
+
<div class="sub">~/ws/tools · worktree · updated 4m ago</div>
|
|
506
|
+
</div>
|
|
507
|
+
<div class="stat"><span class="filecount">12 files</span><span class="add">+486</span><span class="del">−171</span></div>
|
|
508
|
+
</div>
|
|
509
|
+
|
|
510
|
+
<div class="proj-card">
|
|
511
|
+
<div class="icn"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7l9-4 9 4-9 4-9-4z"/><path d="M3 7v10l9 4 9-4V7"/></svg></div>
|
|
512
|
+
<div class="body">
|
|
513
|
+
<div class="name">tools <span class="branch-chip">⎇ coding-2</span></div>
|
|
514
|
+
<div class="sub">~/ws/tools/.claude/worktrees/coding-2 · worktree</div>
|
|
515
|
+
</div>
|
|
516
|
+
<div class="stat"><span class="filecount">3 files</span><span class="add">+58</span><span class="del">−9</span></div>
|
|
517
|
+
</div>
|
|
518
|
+
|
|
519
|
+
<div class="proj-card">
|
|
520
|
+
<div class="icn"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7l9-4 9 4-9 4-9-4z"/><path d="M3 7v10l9 4 9-4V7"/></svg></div>
|
|
521
|
+
<div class="body">
|
|
522
|
+
<div class="name">wall-e <span class="branch-chip">⎇ slack-dedup-weather</span></div>
|
|
523
|
+
<div class="sub">~/ws/tools/wall-e · staged + working</div>
|
|
524
|
+
</div>
|
|
525
|
+
<div class="stat"><span class="filecount">7 files</span><span class="add">+203</span><span class="del">−44</span></div>
|
|
526
|
+
</div>
|
|
527
|
+
</div>
|
|
528
|
+
|
|
529
|
+
<div>
|
|
530
|
+
<div class="col-head"><h4>Documents</h4><span class="count">recent + in repo</span></div>
|
|
531
|
+
<div class="doc-row">
|
|
532
|
+
<span class="di"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg></span>
|
|
533
|
+
<div class="dn">architecture.md</div>
|
|
534
|
+
<span class="dp">wall-e/docs</span>
|
|
535
|
+
</div>
|
|
536
|
+
<div class="doc-row">
|
|
537
|
+
<span class="di"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg></span>
|
|
538
|
+
<div class="dn">review-redesign-proposal.md</div>
|
|
539
|
+
<span class="dp">ctm/docs</span>
|
|
540
|
+
</div>
|
|
541
|
+
<div class="doc-row">
|
|
542
|
+
<span class="di"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg></span>
|
|
543
|
+
<div class="dn">CLAUDE.md</div>
|
|
544
|
+
<span class="dp">ctm</span>
|
|
545
|
+
</div>
|
|
546
|
+
<div class="doc-row">
|
|
547
|
+
<span class="di"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg></span>
|
|
548
|
+
<div class="dn">README.md</div>
|
|
549
|
+
<span class="dp">create-walle</span>
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
</div>
|
|
555
|
+
</section>
|
|
556
|
+
|
|
557
|
+
<!-- ===================== MD REVIEWER ===================== -->
|
|
558
|
+
<section id="md">
|
|
559
|
+
<div class="sec-head"><span class="sec-num">03</span><h2>Markdown reviewer, rebuilt for reading</h2></div>
|
|
560
|
+
<p class="sec-sub">
|
|
561
|
+
A three-pane reading view: a parsed-heading <b>outline</b> with scroll-spy on the left, a comfortable
|
|
562
|
+
reading column with <b>syntax-highlighted code</b> and crisp inline-code in the middle, and a <b>comment rail</b> on the right.
|
|
563
|
+
Rendered / Source / Split toggle lives in the shared header.
|
|
564
|
+
</p>
|
|
565
|
+
<div class="mock">
|
|
566
|
+
<div class="mock-caption">
|
|
567
|
+
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
|
568
|
+
<span class="url">localhost:3456/#review&type=doc&path=wall-e/docs/architecture.md</span>
|
|
569
|
+
</div>
|
|
570
|
+
<div class="shell-header">
|
|
571
|
+
<div class="breadcrumb">
|
|
572
|
+
<span class="crumb">Review</span><span class="sep">›</span>
|
|
573
|
+
<span class="crumb">Documents</span><span class="sep">›</span>
|
|
574
|
+
<span class="crumb active">architecture.md</span>
|
|
575
|
+
</div>
|
|
576
|
+
<div class="grow"></div>
|
|
577
|
+
<div class="seg"><button class="on">Rendered</button><button>Source</button><button>Split</button></div>
|
|
578
|
+
<div class="pill-sel">3 comments</div>
|
|
579
|
+
</div>
|
|
580
|
+
<div class="md-layout">
|
|
581
|
+
<aside class="outline">
|
|
582
|
+
<div class="ol-title">Outline</div>
|
|
583
|
+
<span class="ol-item active">Architecture</span>
|
|
584
|
+
<span class="ol-item l2 active">The loops</span>
|
|
585
|
+
<span class="ol-item l3">Main loop</span>
|
|
586
|
+
<span class="ol-item l3">Scheduler</span>
|
|
587
|
+
<span class="ol-item l2">Brain DB</span>
|
|
588
|
+
<span class="ol-item l2">Skills & channels</span>
|
|
589
|
+
<span class="ol-item">Non-goals</span>
|
|
590
|
+
<span class="ol-item l2">Anti-patterns</span>
|
|
591
|
+
</aside>
|
|
592
|
+
<div class="md-reading">
|
|
593
|
+
<div class="doc">
|
|
594
|
+
<h1>Architecture</h1>
|
|
595
|
+
<p class="tagline">How Wall-E's loops, brain, and scheduler fit together.</p>
|
|
596
|
+
<h2>The loops</h2>
|
|
597
|
+
<p>Wall-E runs two cooperative loops. The <strong>main loop</strong> owns the database writes and never
|
|
598
|
+
blocks longer than a single bounded slice; long jobs are sliced via the cooperative scheduler so the
|
|
599
|
+
high lane (<code>checkpointWal</code>, telemetry) is never starved by a low-lane import.</p>
|
|
600
|
+
<div class="codeblock">
|
|
601
|
+
<div class="cb-head"><span>scheduler.js</span><span>javascript</span></div>
|
|
602
|
+
<pre><span class="k">async function</span> <span class="fn">runSlice</span>(job, <span class="t">budgetMs</span>) {
|
|
603
|
+
<span class="k">const</span> deadline = now() + <span class="t">budgetMs</span>;
|
|
604
|
+
<span class="k">while</span> (job.<span class="pr">hasWork</span>() && now() < deadline) {
|
|
605
|
+
<span class="k">await</span> job.<span class="fn">step</span>(); <span class="c">// one unit, then yield</span>
|
|
606
|
+
}
|
|
607
|
+
<span class="k">return</span> job.<span class="pr">done</span> ? <span class="n">'done'</span> : <span class="n">'reschedule'</span>;
|
|
608
|
+
}</pre>
|
|
609
|
+
</div>
|
|
610
|
+
<p>Coordinate through data, never a manager-of-managers — see <code>docs/architecture.md</code> "Non-goals".</p>
|
|
611
|
+
<ul>
|
|
612
|
+
<li>Single db-owner write worker; readers use a separate pool.</li>
|
|
613
|
+
<li>Cold/large imports defer row writes behind a watermark.</li>
|
|
614
|
+
</ul>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
<aside class="cm-rail">
|
|
618
|
+
<div class="cr-title">Comments</div>
|
|
619
|
+
<div class="cmt">
|
|
620
|
+
<div class="who">◆ You</div>
|
|
621
|
+
<div class="what">Should we name the slice budget per-lane instead of a global constant?</div>
|
|
622
|
+
<div class="anchor">¶ The loops · L14</div>
|
|
623
|
+
</div>
|
|
624
|
+
<div class="cmt">
|
|
625
|
+
<div class="who">◆ You</div>
|
|
626
|
+
<div class="what">Link the Non-goals section here so reviewers jump straight to it.</div>
|
|
627
|
+
<div class="anchor">¶ runSlice() · L21</div>
|
|
628
|
+
</div>
|
|
629
|
+
<div class="addcmt">
|
|
630
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
|
|
631
|
+
Add a comment on the selected block
|
|
632
|
+
</div>
|
|
633
|
+
</aside>
|
|
634
|
+
</div>
|
|
635
|
+
</div>
|
|
636
|
+
</section>
|
|
637
|
+
|
|
638
|
+
<!-- ===================== DIFF ===================== -->
|
|
639
|
+
<section id="diff">
|
|
640
|
+
<div class="sec-head"><span class="sec-num">04</span><h2>Source diff, brought to the surface</h2></div>
|
|
641
|
+
<p class="sec-sub">
|
|
642
|
+
The diff engine is good — it just needs navigation. The base-ref <code><select></code> becomes a
|
|
643
|
+
<b>breadcrumb switcher</b> (project ▸ worktree ▸ base), the file list becomes a <b>searchable tree</b> with
|
|
644
|
+
add/del badges and a tree/list toggle, diff lines get <b>syntax highlighting</b> and stronger colors, and
|
|
645
|
+
<b>keyboard nav</b> moves between files and hunks.
|
|
646
|
+
</p>
|
|
647
|
+
<div class="mock">
|
|
648
|
+
<div class="mock-caption">
|
|
649
|
+
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
|
650
|
+
<span class="url">localhost:3456/#review&project=~/ws/tools&base=--vs-main</span>
|
|
651
|
+
</div>
|
|
652
|
+
<div class="shell-header">
|
|
653
|
+
<div class="breadcrumb">
|
|
654
|
+
<span class="crumb">Review</span><span class="sep">›</span>
|
|
655
|
+
<span class="pill-sel">tools
|
|
656
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 9l6 6 6-6"/></svg>
|
|
657
|
+
</span>
|
|
658
|
+
<span class="sep">›</span>
|
|
659
|
+
<span class="pill-sel">⎇ perf-offload-onmain-git
|
|
660
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 9l6 6 6-6"/></svg>
|
|
661
|
+
</span>
|
|
662
|
+
<span class="sep">›</span>
|
|
663
|
+
<span class="pill-sel">vs main
|
|
664
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 9l6 6 6-6"/></svg>
|
|
665
|
+
</span>
|
|
666
|
+
</div>
|
|
667
|
+
<div class="grow"></div>
|
|
668
|
+
<div class="seg"><button class="on">Unified</button><button>Split</button></div>
|
|
669
|
+
</div>
|
|
670
|
+
<div class="diff-layout">
|
|
671
|
+
<aside class="ftree">
|
|
672
|
+
<div class="ftree-top">
|
|
673
|
+
<div class="searchbox">
|
|
674
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4-4"/></svg>
|
|
675
|
+
Filter files…
|
|
676
|
+
</div>
|
|
677
|
+
<div class="ftree-tools">
|
|
678
|
+
<div class="seg"><button class="on">Tree</button><button>List</button></div>
|
|
679
|
+
<div class="grow"></div>
|
|
680
|
+
<span>12 files · <span style="color:var(--green)">+486</span> <span style="color:var(--red)">−171</span></span>
|
|
681
|
+
</div>
|
|
682
|
+
</div>
|
|
683
|
+
<div class="ftree-list">
|
|
684
|
+
<div class="ftree-folder">claude-task-manager/</div>
|
|
685
|
+
<div class="ftree-file active">
|
|
686
|
+
<span class="fdot" style="background:var(--green)"></span>
|
|
687
|
+
<span class="fname">server.js</span>
|
|
688
|
+
<span class="fmini"><span class="a">+142</span><span class="d">−38</span></span>
|
|
689
|
+
</div>
|
|
690
|
+
<div class="ftree-file">
|
|
691
|
+
<span class="fdot" style="background:var(--accent)"></span>
|
|
692
|
+
<span class="fname">db.js</span>
|
|
693
|
+
<span class="fmini"><span class="a">+64</span><span class="d">−12</span></span>
|
|
694
|
+
</div>
|
|
695
|
+
<div class="ftree-file">
|
|
696
|
+
<span class="check"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"/></svg></span>
|
|
697
|
+
<span class="fname" style="opacity:.55">api-reviews.js</span>
|
|
698
|
+
<span class="fmini"><span class="a">+9</span></span>
|
|
699
|
+
</div>
|
|
700
|
+
<div class="ftree-folder">claude-task-manager/lib/</div>
|
|
701
|
+
<div class="ftree-file">
|
|
702
|
+
<span class="fdot" style="background:var(--green)"></span>
|
|
703
|
+
<span class="fname">db-owner-cooperative-scheduler.js</span>
|
|
704
|
+
<span class="fmini"><span class="a">+188</span></span>
|
|
705
|
+
</div>
|
|
706
|
+
<div class="ftree-folder">wall-e/</div>
|
|
707
|
+
<div class="ftree-file">
|
|
708
|
+
<span class="fdot" style="background:var(--accent)"></span>
|
|
709
|
+
<span class="fname">run.js</span>
|
|
710
|
+
<span class="fmini"><span class="a">+31</span><span class="d">−27</span></span>
|
|
711
|
+
</div>
|
|
712
|
+
<div class="ftree-file">
|
|
713
|
+
<span class="fdot" style="background:var(--red)"></span>
|
|
714
|
+
<span class="fname">legacy-dual-write.js</span>
|
|
715
|
+
<span class="fmini"><span class="d">−54</span></span>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
</aside>
|
|
719
|
+
<div class="diff-main">
|
|
720
|
+
<div class="diff-file-head">
|
|
721
|
+
<span class="fpath">claude-task-manager/server.js</span>
|
|
722
|
+
<span class="viewed-pill"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6L9 17l-5-5"/></svg> Viewed</span>
|
|
723
|
+
<span class="stat"><span class="add">+142</span><span class="del">−38</span></span>
|
|
724
|
+
</div>
|
|
725
|
+
<table class="diff-table">
|
|
726
|
+
<tr class="hunk"><td colspan="3">@@ -24098,7 +24098,9 @@ function buildSessionEnv(session)</td></tr>
|
|
727
|
+
<tr><td class="gutter old">24098</td><td class="gutter new">24098</td><td class="diff-code"><span class="c"> // prepend wall-e bin so wrapped CLIs win on PATH</span></td></tr>
|
|
728
|
+
<tr><td class="gutter old">24099</td><td class="gutter new">24099</td><td class="diff-code"> <span class="k">const</span> env = { ...<span class="pr">process</span>.<span class="pr">env</span> };</td></tr>
|
|
729
|
+
<tr class="del"><td class="gutter old">24100</td><td class="gutter new"></td><td class="diff-code"><span class="signm">-</span> env.<span class="pr">PATH</span> = <span class="pr">process</span>.<span class="pr">env</span>.<span class="pr">PATH</span>;</td></tr>
|
|
730
|
+
<tr class="add"><td class="gutter old"></td><td class="gutter new">24100</td><td class="diff-code"><span class="signp">+</span> <span class="k">const</span> walleBin = <span class="fn">join</span>(<span class="pr">os</span>.<span class="fn">homedir</span>(), <span class="s">'.walle/bin'</span>);</td></tr>
|
|
731
|
+
<tr class="add"><td class="gutter old"></td><td class="gutter new">24101</td><td class="diff-code"><span class="signp">+</span> env.<span class="pr">PATH</span> = <span class="s">`${walleBin}:${process.env.PATH}`</span>;</td></tr>
|
|
732
|
+
<tr><td class="gutter old">24101</td><td class="gutter new">24102</td><td class="diff-code"> <span class="k">return</span> env;</td></tr>
|
|
733
|
+
<tr><td class="gutter old">24102</td><td class="gutter new">24103</td><td class="diff-code">}</td></tr>
|
|
734
|
+
<tr class="hunk"><td colspan="3">@@ -24180,4 +24181,8 @@ async function spawnSessionPty(opts)</td></tr>
|
|
735
|
+
<tr><td class="gutter old">24180</td><td class="gutter new">24181</td><td class="diff-code"> <span class="k">const</span> pty = <span class="fn">spawn</span>(shell, args, { env });</td></tr>
|
|
736
|
+
<tr class="add"><td class="gutter old"></td><td class="gutter new">24182</td><td class="diff-code"><span class="signp">+</span> pty.<span class="fn">on</span>(<span class="s">'exit'</span>, () => <span class="fn">retireBlob</span>(opts.<span class="pr">id</span>));</td></tr>
|
|
737
|
+
<tr><td class="gutter old">24181</td><td class="gutter new">24183</td><td class="diff-code"> <span class="k">return</span> pty;</td></tr>
|
|
738
|
+
</table>
|
|
739
|
+
<div class="diff-foot">
|
|
740
|
+
<span><span class="kbd">j</span><span class="kbd">k</span> next / prev file</span>
|
|
741
|
+
<span><span class="kbd">n</span><span class="kbd">p</span> next / prev hunk</span>
|
|
742
|
+
<span><span class="kbd">v</span> mark viewed</span>
|
|
743
|
+
<span><span class="kbd">c</span> comment on line</span>
|
|
744
|
+
</div>
|
|
745
|
+
</div>
|
|
746
|
+
</div>
|
|
747
|
+
</div>
|
|
748
|
+
</section>
|
|
749
|
+
|
|
750
|
+
<!-- ===================== CLICKABLE FILES ===================== -->
|
|
751
|
+
<section id="click">
|
|
752
|
+
<div class="sec-head"><span class="sec-num">05</span><h2>Every file reference becomes a door</h2></div>
|
|
753
|
+
<p class="sec-sub">
|
|
754
|
+
CTM already linkifies <code>.md</code> in session output. We generalize that into a <b>file router</b>:
|
|
755
|
+
left-click opens by type, and right-click offers every destination explicitly. An <code>.html</code> file opens
|
|
756
|
+
in a new browser tab, a doc opens the markdown reviewer, and source code jumps to the diff focused on that file.
|
|
757
|
+
</p>
|
|
758
|
+
<div class="ck-layout">
|
|
759
|
+
<div>
|
|
760
|
+
<div class="mock">
|
|
761
|
+
<div class="mock-caption">
|
|
762
|
+
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
|
763
|
+
<span class="url">session summary · changed files are live</span>
|
|
764
|
+
</div>
|
|
765
|
+
<div class="terminal-out">
|
|
766
|
+
<div><span class="pfx">✓</span> Wrote design doc to <span class="flink">docs/review-redesign-proposal.html<span class="badge">html</span></span></div>
|
|
767
|
+
<div><span class="pfx">✓</span> Updated <span class="flink">claude-task-manager/server.js<span class="badge">diff</span></span> <span style="color:var(--green)">+142</span> <span style="color:var(--red)">−38</span></div>
|
|
768
|
+
<div><span class="pfx">✓</span> New module <span class="flink">public/js/file-context-menu.js<span class="badge">diff</span></span></div>
|
|
769
|
+
<div style="color:var(--fg-dim)"> See <span class="flink">wall-e/docs/architecture.md<span class="badge">md</span></span> for the loop contract.</div>
|
|
770
|
+
<div style="margin-top:8px;color:var(--fg-dim)">Right-click any path for all targets →</div>
|
|
771
|
+
</div>
|
|
772
|
+
</div>
|
|
773
|
+
<table class="route-table">
|
|
774
|
+
<thead><tr><th>File type</th><th>Left-click opens</th><th>Route</th></tr></thead>
|
|
775
|
+
<tbody>
|
|
776
|
+
<tr><td><span class="ext">.html</span></td><td><b>New browser tab</b></td><td class="mono" style="font-size:11px;color:var(--fg-dim)">/api/reviews/serve-html</td></tr>
|
|
777
|
+
<tr><td><span class="ext">.md .txt</span></td><td><b>Markdown reviewer</b></td><td class="mono" style="font-size:11px;color:var(--fg-dim)">#review&type=doc&path=…</td></tr>
|
|
778
|
+
<tr><td><span class="ext">.js .py .ts …</span></td><td><b>Source diff at that file</b></td><td class="mono" style="font-size:11px;color:var(--fg-dim)">#review&project=…&file=…</td></tr>
|
|
779
|
+
</tbody>
|
|
780
|
+
</table>
|
|
781
|
+
</div>
|
|
782
|
+
<div>
|
|
783
|
+
<div class="ctxmenu">
|
|
784
|
+
<div class="ctx-head">claude-task-manager/server.js</div>
|
|
785
|
+
<div class="ctx-item primary">
|
|
786
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3h7v7H3zM14 14h7v7h-7zM14 3h7v7h-7zM3 14h7v7H3z"/></svg>
|
|
787
|
+
Open in diff
|
|
788
|
+
<span class="meta">↵</span>
|
|
789
|
+
</div>
|
|
790
|
+
<div class="ctx-item">
|
|
791
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
|
|
792
|
+
Open raw file
|
|
793
|
+
</div>
|
|
794
|
+
<div class="ctx-item">
|
|
795
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 17L17 7M7 7h10v10"/></svg>
|
|
796
|
+
Open in new tab
|
|
797
|
+
</div>
|
|
798
|
+
<div class="ctx-sep"></div>
|
|
799
|
+
<div class="ctx-item">
|
|
800
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
|
|
801
|
+
Copy path
|
|
802
|
+
<span class="meta">⌘C</span>
|
|
803
|
+
</div>
|
|
804
|
+
<div class="ctx-item">
|
|
805
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7h5l2-3h4l2 3h5v13H3z"/></svg>
|
|
806
|
+
Reveal in Finder
|
|
807
|
+
</div>
|
|
808
|
+
</div>
|
|
809
|
+
<p class="ck-note">
|
|
810
|
+
The decision core is a <b>pure, unit-testable module</b> — exactly like the existing
|
|
811
|
+
<code class="mono" style="font-size:11px">screenshot-router.js</code>. A missing router degrades safely
|
|
812
|
+
to "open raw", so links never break.
|
|
813
|
+
</p>
|
|
814
|
+
</div>
|
|
815
|
+
</div>
|
|
816
|
+
</section>
|
|
817
|
+
|
|
818
|
+
<!-- ===================== ALTERNATIVE ===================== -->
|
|
819
|
+
<section id="alt">
|
|
820
|
+
<div class="sec-head"><span class="sec-num">06</span><h2>The structural choice</h2></div>
|
|
821
|
+
<p class="sec-sub">Both fix navigation. The recommendation is the Hub; the lighter option is kept here for comparison.</p>
|
|
822
|
+
<div class="alt-grid">
|
|
823
|
+
<div class="alt-card rec">
|
|
824
|
+
<h4>Unified Review Hub <span class="rectag">Recommended</span></h4>
|
|
825
|
+
<div class="sub">A real discovery home in front of both viewers.</div>
|
|
826
|
+
<ul>
|
|
827
|
+
<li>Fixes discovery <em>and</em> navigation at once</li>
|
|
828
|
+
<li>Markdown becomes browsable for the first time</li>
|
|
829
|
+
<li>Search across projects, worktrees, and docs</li>
|
|
830
|
+
<li class="con">Larger change — a new home view to build</li>
|
|
831
|
+
</ul>
|
|
832
|
+
</div>
|
|
833
|
+
<div class="alt-card">
|
|
834
|
+
<h4>Shared shell only</h4>
|
|
835
|
+
<div class="sub">Keep today's panels; add one consistent header.</div>
|
|
836
|
+
<ul>
|
|
837
|
+
<li>Lower risk, smaller diff</li>
|
|
838
|
+
<li>Breadcrumb + switcher fixes "where am I"</li>
|
|
839
|
+
<li class="con">Markdown still has no discovery</li>
|
|
840
|
+
<li class="con">No single place to start a review</li>
|
|
841
|
+
</ul>
|
|
842
|
+
</div>
|
|
843
|
+
</div>
|
|
844
|
+
</section>
|
|
845
|
+
|
|
846
|
+
<!-- ===================== PLAN ===================== -->
|
|
847
|
+
<section id="plan">
|
|
848
|
+
<div class="sec-head"><span class="sec-num">07</span><h2>How it ships</h2></div>
|
|
849
|
+
<p class="sec-sub">Front-end heavy, two small additive endpoints, validated on a /ctm-dev instance — never the primary.</p>
|
|
850
|
+
<div class="roadmap">
|
|
851
|
+
<div class="phase">
|
|
852
|
+
<div class="pn">A</div>
|
|
853
|
+
<div class="pbody"><h4>Hub + shared shell</h4><p>New <code>renderReviewHub()</code> home and a shared header wrapping both viewers in <code>reviews.js</code>. Transcript review untouched.</p></div>
|
|
854
|
+
</div>
|
|
855
|
+
<div class="phase">
|
|
856
|
+
<div class="pn">B</div>
|
|
857
|
+
<div class="pbody"><h4>Viewer quality</h4><p>Add <code>highlight.js</code> (alongside <code>marked</code>/<code>DOMPurify</code>); restyle diff + markdown in <code>reviews.css</code>; file-tree search + keyboard nav.</p></div>
|
|
858
|
+
</div>
|
|
859
|
+
<div class="phase">
|
|
860
|
+
<div class="pn">C</div>
|
|
861
|
+
<div class="pbody"><h4>Clickable files</h4><p>Generalize <code>document-review-links.js</code>; new pure <code>file-context-menu.js</code>; deep-link source via <code>&file=</code>.</p></div>
|
|
862
|
+
</div>
|
|
863
|
+
<div class="phase">
|
|
864
|
+
<div class="pn">D</div>
|
|
865
|
+
<div class="pbody"><h4>Backend (additive)</h4><p><code>api-reviews.js</code>: document-discovery list + path-validated HTML serve. No rewrite of the diff/document engines.</p></div>
|
|
866
|
+
</div>
|
|
867
|
+
</div>
|
|
868
|
+
</section>
|
|
869
|
+
|
|
870
|
+
<footer>
|
|
871
|
+
CTM Review redesign proposal · self-contained mock using the live app theme tokens ·
|
|
872
|
+
toggle <a href="javascript:toggleTheme()">dark / light</a> to preview both ·
|
|
873
|
+
next step → implement Phase A–D on <a href="javascript:void(0)">/ctm-dev</a>.
|
|
874
|
+
</footer>
|
|
875
|
+
</div>
|
|
876
|
+
|
|
877
|
+
<script>
|
|
878
|
+
function toggleTheme() {
|
|
879
|
+
const html = document.documentElement;
|
|
880
|
+
const next = html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
|
|
881
|
+
html.setAttribute('data-theme', next);
|
|
882
|
+
document.getElementById('themeLabel').textContent = next === 'dark' ? 'Dark' : 'Light';
|
|
883
|
+
}
|
|
884
|
+
// subtle staggered reveal on load
|
|
885
|
+
document.querySelectorAll('section, .hero').forEach((el, i) => {
|
|
886
|
+
el.style.opacity = '0'; el.style.transform = 'translateY(10px)';
|
|
887
|
+
el.style.transition = 'opacity .5s ease, transform .5s ease';
|
|
888
|
+
setTimeout(() => { el.style.opacity = '1'; el.style.transform = 'none'; }, 60 + i * 55);
|
|
889
|
+
});
|
|
890
|
+
</script>
|
|
891
|
+
</body>
|
|
892
|
+
</html>
|