claude-plan-review 0.3.0 → 0.3.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/README.md +0 -9
- package/package.json +1 -1
- package/src/channels/gh.js +5 -3
- package/src/channels/gist.js +10 -3
- package/src/cli.js +6 -5
package/README.md
CHANGED
|
@@ -60,15 +60,6 @@ npx claude-plan-review init --published # if you have Node
|
|
|
60
60
|
`--published` makes the hook run via the package runner (`bunx`/`npx`), so it works on
|
|
61
61
|
any machine — nothing to keep in your repo but the one settings entry.
|
|
62
62
|
|
|
63
|
-
### Option B — from a local clone (for hacking on it)
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
git clone https://github.com/pavlo-petrychenko/claude-plan-review
|
|
67
|
-
cd claude-plan-review
|
|
68
|
-
bun install # or: npm install
|
|
69
|
-
bun src/cli.js init /path/to/your/project # …or…
|
|
70
|
-
node src/cli.js init /path/to/your/project # writes an absolute-path hook command
|
|
71
|
-
```
|
|
72
63
|
|
|
73
64
|
### All projects at once (global)
|
|
74
65
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-plan-review",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.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/channels/gh.js
CHANGED
|
@@ -73,11 +73,13 @@ export function api(method, path, body) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
const errText = `${r.stderr}${r.stdout}`.trim();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
const httpStatus = Number(errText.match(/HTTP (\d{3})/)?.[1]) || null;
|
|
77
|
+
// A genuine missing-scope error names the scope explicitly ("requires the
|
|
78
|
+
// 'gist' scope"). A bare 404 just means the gist is gone — don't conflate them.
|
|
79
|
+
const needsGistScope = /gist/i.test(errText) && /scope|requires/i.test(errText);
|
|
79
80
|
return {
|
|
80
81
|
ok: false,
|
|
82
|
+
httpStatus,
|
|
81
83
|
error: errText || (r.spawnError ? String(r.spawnError.message || r.spawnError) : "gh failed"),
|
|
82
84
|
needsGistScope,
|
|
83
85
|
};
|
package/src/channels/gist.js
CHANGED
|
@@ -47,12 +47,15 @@ export function available() {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function ghError(res) {
|
|
50
|
+
// Only blame the scope when the token actually lacks it — otherwise surface
|
|
51
|
+
// gh's real error so a deleted gist / network failure isn't misdiagnosed.
|
|
52
|
+
const missingScope = res.needsGistScope && !gh.status().scopes.includes("gist");
|
|
50
53
|
const e = new Error(
|
|
51
|
-
|
|
52
|
-
? `GitHub rejected the gist write — your gh token
|
|
54
|
+
missingScope
|
|
55
|
+
? `GitHub rejected the gist write — your gh token lacks the 'gist' scope. Run: ${REFRESH_CMD}`
|
|
53
56
|
: res.error || "gh request failed",
|
|
54
57
|
);
|
|
55
|
-
e.fixCommand =
|
|
58
|
+
e.fixCommand = missingScope ? REFRESH_CMD : null;
|
|
56
59
|
return e;
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -87,6 +90,10 @@ export function update({ id: gistId, markdown, description, filename, oldFilenam
|
|
|
87
90
|
description: description ?? "",
|
|
88
91
|
files: { [fileKey]: filePatch },
|
|
89
92
|
});
|
|
93
|
+
// The bound gist was deleted on GitHub — recreate one and re-bind instead of failing.
|
|
94
|
+
if (!res.ok && res.httpStatus === 404) {
|
|
95
|
+
return create({ markdown, description, filename: newName });
|
|
96
|
+
}
|
|
90
97
|
if (!res.ok) throw ghError(res);
|
|
91
98
|
return {
|
|
92
99
|
id: res.data.id,
|
package/src/cli.js
CHANGED
|
@@ -35,12 +35,13 @@ function chooseRuntime(args) {
|
|
|
35
35
|
|
|
36
36
|
function hookCommand(args) {
|
|
37
37
|
const runtime = chooseRuntime(args);
|
|
38
|
-
// global install →
|
|
39
|
-
//
|
|
40
|
-
//
|
|
38
|
+
// global install → always route through the package runner (npx/bunx), never the bare
|
|
39
|
+
// `claude-plan-review` command. Version managers like fnm/nvm expose global bins only via a
|
|
40
|
+
// per-shell PATH set up by interactive shell init. `canRun` succeeds here (init runs in an
|
|
41
|
+
// interactive shell) but Claude Code fires hooks in a NON-interactive shell where that PATH
|
|
42
|
+
// is absent, so the bare command resolves at init time yet fails — silently — at hook time.
|
|
43
|
+
// `npx`/`bunx` are inherited reliably from Claude Code's launching env, so they work either way.
|
|
41
44
|
if (args.includes("--global")) {
|
|
42
|
-
if (canRun("claude-plan-review")) return "claude-plan-review hook";
|
|
43
|
-
// not on PATH → fall back to the package runner
|
|
44
45
|
return runtime === "node" ? "npx claude-plan-review hook" : "bunx claude-plan-review hook";
|
|
45
46
|
}
|
|
46
47
|
if (args.includes("--published") || args.includes("--bunx")) {
|