issuewatcher-mcp 0.2.0 → 0.2.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
@@ -48,7 +48,13 @@ Pick your app:
48
48
  claude mcp add issuewatcher -e GITHUB_TOKEN=github_pat_xxxxxxxx -- npx -y issuewatcher-mcp
49
49
  ```
50
50
 
51
- Then run `/mcp` inside Claude Code to see it connected.
51
+ Then run `/mcp` inside Claude Code to see it connected. The server is added for the current project folder; add `--scope user` to have it in every folder.
52
+
53
+ **Windows PowerShell** swallows the `--`, which makes Claude Code fail with `unknown option '-y'`. Put the `--` in quotes:
54
+
55
+ ```powershell
56
+ claude mcp add issuewatcher -e "GITHUB_TOKEN=github_pat_xxxxxxxx" '--' npx -y issuewatcher-mcp
57
+ ```
52
58
 
53
59
  </details>
54
60
 
@@ -32,15 +32,31 @@ function nonLatinShare(text) {
32
32
  }
33
33
  const LABEL_DISMISSED = /(duplicate|invalid|wontfix|won't fix|not a bug)/i;
34
34
  const VERSION_IN_TEXT = /\bv?(\d+)\.(\d+)\.(\d+)\b|\bv(\d+)\.(\d+)\b/g;
35
+ const WORKING_VERSION = /(worked|works|working|fine|as it did|did|passes|passed)\s+(in|on|with|until|before)\s+(version\s+)?$|(before|previously|prior to|until|downgrad\w*\s+to|rolled? back to|older than|earlier than)\s+(version\s+)?$/i;
35
36
  const clamp = (n) => Math.max(0, Math.min(100, Math.round(n)));
36
37
  /** Versions mentioned in free text, as {major, minor}. */
37
38
  function mentionedVersions(text) {
38
39
  const out = [];
39
40
  for (const m of text.matchAll(VERSION_IN_TEXT)) {
41
+ // "worked in 0.3.31" names the version that is fine, not the one that is broken.
42
+ const before = text.slice(Math.max(0, (m.index ?? 0) - 40), m.index ?? 0);
43
+ if (WORKING_VERSION.test(before))
44
+ continue;
40
45
  out.push({ major: Number(m[1] ?? m[4]), minor: Number(m[2] ?? m[5]) });
41
46
  }
42
47
  return out;
43
48
  }
49
+ /** Words that may come right before a version without it belonging to some other product. */
50
+ const VERSION_LEAD = new Set("in on since from after with to at for and the version v".split(" "));
51
+ /** Majors a title names ("1.x", "v2", "2.3.1"). "TS 7.0" or "Node 22.x" name another product and are skipped. */
52
+ function titleMajors(title) {
53
+ const out = [];
54
+ for (const m of title.matchAll(/(^|[^\w.])(?:([a-z][\w-]*)\s+)?v?(\d+)\.(?:x|\d+)/gi)) {
55
+ if (!m[2] || VERSION_LEAD.has(m[2].toLowerCase()))
56
+ out.push(Number(m[3]));
57
+ }
58
+ return out;
59
+ }
44
60
  /**
45
61
  * The user's dependencies that this issue is actually about. DefinitelyTyped holds the types
46
62
  * for every package, so only an issue about a @types package the user depends on is about
@@ -107,7 +123,16 @@ export function scoreIssueDetailed(issue, target, opts = {}) {
107
123
  // Does the report concern a version the user runs?
108
124
  const text = `${issue.title}\n${issue.body.slice(0, 4000)}`;
109
125
  const versions = mentionedVersions(text);
110
- if (consumer && versions.length) {
126
+ // A title about a newer major than you run (a "1.x regression", you use ^0.3) is probably not about
127
+ // you. Older versions in its body are then comparisons ("worked in 0.3.31"), not matches.
128
+ const titleVersions = titleMajors(issue.title);
129
+ const mineMajors = deps.map((d) => minVersion(d.range)).filter((v) => v !== null);
130
+ const newerMajor = consumer &&
131
+ !runtime?.range.includes("*") &&
132
+ titleVersions.length > 0 &&
133
+ mineMajors.length > 0 &&
134
+ titleVersions.every((m) => mineMajors.every((v) => m > v.major));
135
+ if (consumer && versions.length && !newerMajor) {
111
136
  let best = null;
112
137
  for (const dep of deps) {
113
138
  const mine = minVersion(dep.range);
@@ -135,6 +160,9 @@ export function scoreIssueDetailed(issue, target, opts = {}) {
135
160
  add(best.points, "version-match", best.reason);
136
161
  }
137
162
  }
163
+ if (newerMajor) {
164
+ add(-15, "newer-major", `title is about v${titleVersions[0]}, you use ${deps[0].range}`);
165
+ }
138
166
  // Severity signals. Each is recorded individually; the total is capped afterwards.
139
167
  let severity = 0;
140
168
  const sevParts = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issuewatcher-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "MCP server that ranks new GitHub issues for your AI assistant: what to pick up, and what may break your projects.",
5
5
  "mcpName": "io.github.mac146/issuewatcher",
6
6
  "license": "MIT",