claude-plan-review 0.3.0 → 0.3.1

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 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.0",
3
+ "version": "0.3.1",
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": {
@@ -73,11 +73,13 @@ export function api(method, path, body) {
73
73
  }
74
74
  }
75
75
  const errText = `${r.stderr}${r.stdout}`.trim();
76
- // gh surfaces a "(HTTP 404)"/"(HTTP 403)" + scope hint when the token can't touch gists
77
- const needsGistScope =
78
- /gist/i.test(errText) && /(scope|HTTP 40[34]|Not Found|requires)/i.test(errText);
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
  };
@@ -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
- res.needsGistScope
52
- ? `GitHub rejected the gist write — your gh token likely lacks the 'gist' scope. Run: ${REFRESH_CMD}`
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 = res.needsGistScope ? REFRESH_CMD : null;
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
File without changes