claude-plan-review 0.5.0 → 0.5.2
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/src/mcp.js +2 -1
- package/src/ui/app.js +6 -27
- package/src/ui/index.html +0 -3
- package/src/ui/style.css +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-plan-review",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Review, comment on, and approve/reject Claude Code plans in a local GitHub-style web UI — with persistent comments, version history, and diffs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/mcp.js
CHANGED
|
@@ -25,12 +25,13 @@ import { getReview, recordPlan } from "./store.js";
|
|
|
25
25
|
|
|
26
26
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
27
27
|
const SERVER_SCRIPT = join(HERE, "server.js");
|
|
28
|
+
const pkg = JSON.parse(readFileSync(join(HERE, "..", "package.json"), "utf8"));
|
|
28
29
|
|
|
29
30
|
// Latest MCP protocol revision we implement. We echo the client's requested
|
|
30
31
|
// version back when it sends one (the compatible behaviour for a version-
|
|
31
32
|
// agnostic tools server), else advertise this.
|
|
32
33
|
const PROTOCOL_VERSION = "2025-06-18";
|
|
33
|
-
const SERVER_INFO = { name: "claude-plan-review", version:
|
|
34
|
+
const SERVER_INFO = { name: "claude-plan-review", version: pkg.version };
|
|
34
35
|
|
|
35
36
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
36
37
|
|
package/src/ui/app.js
CHANGED
|
@@ -35,7 +35,7 @@ const state = {
|
|
|
35
35
|
docCache: new Map(), // slug → {slug,title,parent,markdown,html}
|
|
36
36
|
manifestCache: new Map(), // version n → manifest|null (for the diff doc union)
|
|
37
37
|
allComments: [], // every comment on the version (each carries `doc`) — drives badges
|
|
38
|
-
viewAsTree:
|
|
38
|
+
viewAsTree: true, // single-doc display-only outline mode (always on for single-doc plans)
|
|
39
39
|
treeSection: -1, // selected outline section index (-1 = show all)
|
|
40
40
|
_sections: null, // cached outline sections for the current preview
|
|
41
41
|
// --- deletion ---
|
|
@@ -89,8 +89,6 @@ function showEmpty(msg) {
|
|
|
89
89
|
$("docSidebar").hidden = true;
|
|
90
90
|
$("reviewActions").hidden = true;
|
|
91
91
|
$("saveActions").hidden = true;
|
|
92
|
-
$("deleteVerBtn").hidden = true;
|
|
93
|
-
$("treeToggle").hidden = true;
|
|
94
92
|
}
|
|
95
93
|
|
|
96
94
|
async function loadProjects() {
|
|
@@ -123,7 +121,6 @@ async function selectProject(key, wantV) {
|
|
|
123
121
|
const fmt = (v) => `v${v.n} · ${new Date(v.createdAt).toLocaleString()}${v.n === latest ? " (current)" : ""}`;
|
|
124
122
|
$("versionSel").innerHTML = versions.map((v) => `<option value="${v.n}">${esc(fmt(v))}</option>`).join("");
|
|
125
123
|
$("versionSel").value = String(state.version);
|
|
126
|
-
$("deleteVerBtn").hidden = false;
|
|
127
124
|
|
|
128
125
|
// base = the version right before current, if any
|
|
129
126
|
state.baseVersion = versions.length > 1 ? versions[versions.findIndex((v) => v.n === state.version) - 1]?.n ?? versions[0].n : null;
|
|
@@ -139,7 +136,6 @@ async function selectProject(key, wantV) {
|
|
|
139
136
|
async function loadVersion(n) {
|
|
140
137
|
state.version = n;
|
|
141
138
|
hideSelPop();
|
|
142
|
-
state.viewAsTree = false;
|
|
143
139
|
state.treeSection = -1;
|
|
144
140
|
state.docCache = new Map();
|
|
145
141
|
state.data = await api(`/api/projects/${enc(state.key)}/versions/${n}`);
|
|
@@ -149,7 +145,9 @@ async function loadVersion(n) {
|
|
|
149
145
|
const isTree = docs.length > 1;
|
|
150
146
|
state.kind = state.data.kind || (isTree ? "tree" : "single");
|
|
151
147
|
$("diffCur").textContent = n;
|
|
152
|
-
|
|
148
|
+
// Tree view is always on for single-doc plans (heading outline); real multi-doc
|
|
149
|
+
// trees use the doc sidebar instead, so they don't also apply the outline view.
|
|
150
|
+
state.viewAsTree = !isTree;
|
|
153
151
|
|
|
154
152
|
if (isTree) {
|
|
155
153
|
// sidebar badge counts come from one unscoped fetch; threads filter it per doc.
|
|
@@ -431,15 +429,6 @@ function renderHeadingTree() {
|
|
|
431
429
|
return rows.join("");
|
|
432
430
|
}
|
|
433
431
|
|
|
434
|
-
function updateTreeToggle() {
|
|
435
|
-
const isTree = state.manifest && state.manifest.docs.length > 1;
|
|
436
|
-
const t = $("treeToggle");
|
|
437
|
-
t.hidden = isTree; // real doc trees get the sidebar automatically
|
|
438
|
-
if (isTree) state.viewAsTree = false;
|
|
439
|
-
t.classList.toggle("active", state.viewAsTree);
|
|
440
|
-
t.textContent = state.viewAsTree ? "Exit tree view" : "View as tree";
|
|
441
|
-
}
|
|
442
|
-
|
|
443
432
|
// ---------- comments ----------
|
|
444
433
|
async function addComment(line, lineEnd, body, quote) {
|
|
445
434
|
if (!body.trim()) return;
|
|
@@ -1025,15 +1014,6 @@ function wireUI() {
|
|
|
1025
1014
|
};
|
|
1026
1015
|
});
|
|
1027
1016
|
|
|
1028
|
-
// view-as-tree (single-doc, display-only)
|
|
1029
|
-
$("treeToggle").onclick = () => {
|
|
1030
|
-
state.viewAsTree = !state.viewAsTree;
|
|
1031
|
-
state.treeSection = -1;
|
|
1032
|
-
updateTreeToggle();
|
|
1033
|
-
renderPreview();
|
|
1034
|
-
renderSidebar();
|
|
1035
|
-
};
|
|
1036
|
-
|
|
1037
1017
|
// sidebar navigation — doc rows (tree) or outline sections (view-as-tree)
|
|
1038
1018
|
$("docSidebar").addEventListener("click", (e) => {
|
|
1039
1019
|
const row = e.target.closest("[data-doc]");
|
|
@@ -1106,8 +1086,8 @@ function wireUI() {
|
|
|
1106
1086
|
await resolve("reject");
|
|
1107
1087
|
};
|
|
1108
1088
|
|
|
1109
|
-
// deletion + manage —
|
|
1110
|
-
|
|
1089
|
+
// deletion + manage — header entry points are hidden for now, but the underlying
|
|
1090
|
+
// logic (deleteVersionNow / openManageModal / performDelete) is kept intact.
|
|
1111
1091
|
$("deleteCancel").onclick = async () => {
|
|
1112
1092
|
const pd = state.pendingDelete;
|
|
1113
1093
|
$("deleteModal").hidden = true;
|
|
@@ -1120,7 +1100,6 @@ function wireUI() {
|
|
|
1120
1100
|
};
|
|
1121
1101
|
$("deleteForce").onclick = () => performDelete(true);
|
|
1122
1102
|
|
|
1123
|
-
$("manageBtn").onclick = () => openManageModal();
|
|
1124
1103
|
$("manageClose").onclick = () => ($("manageModal").hidden = true);
|
|
1125
1104
|
$("manageList").addEventListener("click", (e) => {
|
|
1126
1105
|
const btn = e.target.closest("[data-mg]");
|
package/src/ui/index.html
CHANGED
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
<label>Version
|
|
25
25
|
<select id="versionSel"></select>
|
|
26
26
|
</label>
|
|
27
|
-
<button class="iconbtn" id="deleteVerBtn" title="Delete this version" aria-label="Delete this version" hidden>🗑</button>
|
|
28
27
|
</div>
|
|
29
28
|
<div class="saveActions" id="saveActions" hidden>
|
|
30
29
|
<button class="btn" id="saveBtn">Save to gist</button>
|
|
@@ -35,7 +34,6 @@
|
|
|
35
34
|
<button class="btn approve" id="approveBtn">Approve plan</button>
|
|
36
35
|
<button class="btn reject" id="rejectBtn">Request changes</button>
|
|
37
36
|
</div>
|
|
38
|
-
<button class="iconbtn" id="manageBtn" title="Manage & delete plans" aria-label="Manage plans">🗄</button>
|
|
39
37
|
<button class="iconbtn" id="themeToggle" title="Toggle light / dark theme" aria-label="Toggle theme">🌓</button>
|
|
40
38
|
</header>
|
|
41
39
|
|
|
@@ -49,7 +47,6 @@
|
|
|
49
47
|
<section class="panel active" id="panel-preview">
|
|
50
48
|
<div class="preview-toolbar">
|
|
51
49
|
<p class="selhint">Select any text in the plan to comment on it.</p>
|
|
52
|
-
<button class="btn tree-toggle" id="treeToggle" hidden>View as tree</button>
|
|
53
50
|
</div>
|
|
54
51
|
<div class="preview-layout">
|
|
55
52
|
<aside class="doc-sidebar" id="docSidebar" hidden></aside>
|
package/src/ui/style.css
CHANGED
|
@@ -200,9 +200,6 @@ textarea {
|
|
|
200
200
|
/* ---------- multi-document: sidebar + layout ---------- */
|
|
201
201
|
.preview-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 10px; }
|
|
202
202
|
.preview-toolbar .selhint { margin: 0; }
|
|
203
|
-
.tree-toggle { font-size: 12px; padding: 4px 10px; flex: none; }
|
|
204
|
-
.tree-toggle.active { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
205
|
-
.tree-toggle.active:hover { filter: brightness(1.08); }
|
|
206
203
|
|
|
207
204
|
.preview-layout { display: flex; align-items: flex-start; gap: 20px; }
|
|
208
205
|
.preview-main { flex: 1; min-width: 0; }
|