@loupekit/mcp 0.10.7-next.52 → 0.10.8-next.53

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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +16 -10
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -51,10 +51,10 @@ element, its state, and the page.
51
51
 
52
52
  | Tool | Description |
53
53
  | --- | --- |
54
- | `list_comments(status?, url?)` | List comments, optionally filtered by status (`open` / `in_progress` / `done`) or page URL. |
54
+ | `list_comments(status?, url?)` | List comments, optionally filtered by stage (`queue` / `todo` / `in_progress` / `in_review` / `resolved`) or page URL. The legacy names `open` / `done` are accepted too. |
55
55
  | `get_comment(id)` | The full Claude-ready package for one comment: request + element HTML + computed styles + the **screenshot as an image** + any screen-recording URL. |
56
56
  | `propose_change(id, html, css?, notes?)` | Write your **modified HTML/CSS** back onto the comment. The dashboard renders it as code plus a live before/after preview for the dev team. |
57
- | `update_status(id, status)` | Move a comment across the workflow (`open` → `in_progress` → `done`) so triage state stays in sync. |
57
+ | `update_status(id, status)` | Move a comment along the board (`queue` → `todo` → `in_progress` → `in_review` → `resolved`) so triage state stays in sync. Move to `in_review` when a change is ready — only a person resolves. |
58
58
 
59
59
  ## Install
60
60
 
package/dist/index.js CHANGED
@@ -8,6 +8,8 @@ import { realpathSync } from "fs";
8
8
  import { argv } from "process";
9
9
  import { z } from "zod";
10
10
  import { Buffer } from "buffer";
11
+ import { COMMENT_STAGES, normalizeStatus, STAGE_LABELS } from "@loupekit/shared";
12
+ var STAGE_ARG = z.string().describe(`Stage: ${COMMENT_STAGES.join(" / ")}. Legacy "open" and "done" are accepted too.`);
11
13
  var API = (process.env.LOUPE_API || "http://localhost:8787").replace(/\/$/, "");
12
14
  var PROJECT_KEY = process.env.LOUPE_PROJECT_KEY || "pk_demo_acme";
13
15
  var ADMIN = process.env.LOUPE_ADMIN_KEY || "";
@@ -54,10 +56,13 @@ async function listComments({ status, url }) {
54
56
  const q = new URLSearchParams({ projectKey: PROJECT_KEY });
55
57
  if (url) q.set("url", url);
56
58
  let comments = await api(`/v1/comments?${q}`);
57
- if (status) comments = comments.filter((c) => c.status === status);
59
+ if (status) {
60
+ const want = normalizeStatus(status);
61
+ comments = comments.filter((c) => normalizeStatus(c.status) === want);
62
+ }
58
63
  if (!comments.length) return wrap("No comments match.");
59
64
  const lines = comments.map(
60
- (c) => `- [${c.status}] #${c.id} \u2014 ${titleOf(c)}: ${c.body}
65
+ (c) => `- [${STAGE_LABELS[normalizeStatus(c.status)]}] #${c.id} \u2014 ${titleOf(c)}: ${c.body}
61
66
  \u21B3 ${targetOf(c)} on ${c.url} (by ${c.author.name})`
62
67
  );
63
68
  return wrap(`${comments.length} comment(s):
@@ -70,7 +75,7 @@ async function getComment({ id }) {
70
75
  const c = await api(`/v1/comments/${encodeURIComponent(id)}`);
71
76
  if (c.kind === "free") {
72
77
  const text2 = [
73
- `# Feedback #${c.id} from ${c.author.name} (${c.status})`,
78
+ `# Feedback #${c.id} from ${c.author.name} (${STAGE_LABELS[normalizeStatus(c.status)]})`,
74
79
  ``,
75
80
  `**Title:** ${titleOf(c)}`,
76
81
  `**Note:** ${c.body}`,
@@ -82,7 +87,7 @@ async function getComment({ id }) {
82
87
  return wrap(text2, ...imgs.map((i) => ({ type: "image", data: i.data, mimeType: i.mimeType })));
83
88
  }
84
89
  const text = [
85
- `# Feedback #${c.id} from ${c.author.name} (${c.status})`,
90
+ `# Feedback #${c.id} from ${c.author.name} (${STAGE_LABELS[normalizeStatus(c.status)]})`,
86
91
  ``,
87
92
  `**Title:** ${titleOf(c)}`,
88
93
  `**Request:** ${c.body}`,
@@ -122,8 +127,9 @@ async function getComment({ id }) {
122
127
  return wrap(text, ...images.map((i) => ({ type: "image", data: i.data, mimeType: i.mimeType })));
123
128
  }
124
129
  async function updateStatus({ id, status }) {
125
- await api(`/v1/comments/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify({ status }) });
126
- return wrap(`#${id} \u2192 ${status}`);
130
+ const stage = normalizeStatus(status);
131
+ await api(`/v1/comments/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify({ status: stage }) });
132
+ return wrap(`#${id} \u2192 ${STAGE_LABELS[stage]}`);
127
133
  }
128
134
  async function proposeChange({ id, html, css, notes }) {
129
135
  const proposal = {
@@ -136,12 +142,12 @@ async function proposeChange({ id, html, css, notes }) {
136
142
  await api(`/v1/comments/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify({ proposal }) });
137
143
  return wrap(`Proposal saved for #${id}. The dev team can now review your modified HTML/CSS in the dashboard.`);
138
144
  }
139
- var server = new McpServer({ name: "loupe", version: "0.10.7" });
145
+ var server = new McpServer({ name: "loupe", version: "0.10.8" });
140
146
  server.tool(
141
147
  "list_comments",
142
148
  "List Loupe product-feedback comments for the project as a task backlog. Use this to see what a PM has flagged, then work through the items.",
143
149
  {
144
- status: z.enum(["open", "in_progress", "done"]).optional().describe("Filter by status. Omit for all."),
150
+ status: STAGE_ARG.optional().describe(`Filter by stage. Omit for all.`),
145
151
  url: z.string().optional().describe("Filter to a single page path, e.g. /checkout.")
146
152
  },
147
153
  listComments
@@ -154,8 +160,8 @@ server.tool(
154
160
  );
155
161
  server.tool(
156
162
  "update_status",
157
- "Update a comment's status. Set to in_progress when you start it and done when the change is shipped \u2014 this closes the loop back to the PM.",
158
- { id: z.string(), status: z.enum(["open", "in_progress", "done"]) },
163
+ "Move a comment along the board. Set In Progress when you start it, and In Review when the change is ready for a human \u2014 only a person resolves a comment, so never set Resolved yourself.",
164
+ { id: z.string(), status: STAGE_ARG },
159
165
  updateStatus
160
166
  );
161
167
  server.tool(
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "email": "m.ashraf.saed@gmail.com",
6
6
  "url": "https://www.linkedin.com/in/mohamedashrafelsaed/"
7
7
  },
8
- "version": "0.10.7-next.52",
8
+ "version": "0.10.8-next.53",
9
9
  "description": "MCP server that exposes Loupe comments to Claude Code as an actionable, fully-contextualized backlog.",
10
10
  "keywords": [
11
11
  "loupe",
@@ -46,6 +46,6 @@
46
46
  "zod": "^3.24.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@loupekit/shared": "0.10.7-next.52"
49
+ "@loupekit/shared": "0.10.8-next.53"
50
50
  }
51
51
  }