@web-remarq/mcp 0.3.0 → 0.4.0
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 +8 -1
- package/dist/server.js +140 -93
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,7 +97,10 @@ loop:
|
|
|
97
97
|
# do not wait for subagents - go straight back to watch_annotations
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
The server ships this recipe as an MCP prompt: in clients that support them
|
|
101
|
+
(Claude Code renders it as the `/mcp__web-remarq__watch` slash command) one
|
|
102
|
+
command puts the agent on duty - no copy-paste needed. For clients without
|
|
103
|
+
MCP-prompt support, paste this instead:
|
|
101
104
|
|
|
102
105
|
> You are on annotation duty for this project. Designers drop feedback via
|
|
103
106
|
> the web-remarq MCP server. Run this loop until I tell you to stop: call
|
|
@@ -119,6 +122,10 @@ via the MCP tools. Files appear when an annotation is submitted, update on
|
|
|
119
122
|
status changes, and disappear once it is verified or dismissed. The folder is
|
|
120
123
|
server-owned - never edit or commit it (`.remarq/` self-gitignores).
|
|
121
124
|
|
|
125
|
+
Caveat: with a custom `REMARQ_DATA_FILE` pointing outside `.remarq/`, the
|
|
126
|
+
`tasks/` folder is created next to your data file and is NOT auto-gitignored -
|
|
127
|
+
add it to your `.gitignore` yourself.
|
|
128
|
+
|
|
122
129
|
There is no mode switch:
|
|
123
130
|
|
|
124
131
|
- **Agent on duty** (watching via `watch_annotations`): the folder just mirrors
|
package/dist/server.js
CHANGED
|
@@ -145,89 +145,6 @@ var FileStorageAdapter = class {
|
|
|
145
145
|
|
|
146
146
|
// src/http-server.ts
|
|
147
147
|
import * as http from "http";
|
|
148
|
-
var CORS_HEADERS = {
|
|
149
|
-
"Access-Control-Allow-Origin": "*",
|
|
150
|
-
"Access-Control-Allow-Methods": "GET, PUT, DELETE, OPTIONS",
|
|
151
|
-
"Access-Control-Allow-Headers": "content-type"
|
|
152
|
-
};
|
|
153
|
-
var MAX_BODY_BYTES = 1024 * 1024;
|
|
154
|
-
function json(res, status, body) {
|
|
155
|
-
res.writeHead(status, { ...CORS_HEADERS, "content-type": "application/json" });
|
|
156
|
-
res.end(JSON.stringify(body));
|
|
157
|
-
}
|
|
158
|
-
function readBody(req) {
|
|
159
|
-
return new Promise((resolve, reject) => {
|
|
160
|
-
let size = 0;
|
|
161
|
-
const chunks = [];
|
|
162
|
-
req.on("data", (chunk) => {
|
|
163
|
-
size += chunk.length;
|
|
164
|
-
if (size > MAX_BODY_BYTES) {
|
|
165
|
-
reject(new Error("body too large"));
|
|
166
|
-
req.destroy();
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
chunks.push(chunk);
|
|
170
|
-
});
|
|
171
|
-
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
172
|
-
req.on("error", reject);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
async function handle(req, res, storage) {
|
|
176
|
-
if (req.method === "OPTIONS") {
|
|
177
|
-
res.writeHead(204, CORS_HEADERS);
|
|
178
|
-
res.end();
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
182
|
-
const annMatch = pathname.match(/^\/annotations\/([^/]+)$/);
|
|
183
|
-
try {
|
|
184
|
-
if (req.method === "GET" && pathname === "/store") {
|
|
185
|
-
const rev = storage.rev;
|
|
186
|
-
const store = await storage.load() ?? { version: 1, annotations: [] };
|
|
187
|
-
json(res, 200, { rev, store });
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
if (req.method === "PUT" && annMatch) {
|
|
191
|
-
const id = decodeURIComponent(annMatch[1]);
|
|
192
|
-
let annotation;
|
|
193
|
-
try {
|
|
194
|
-
annotation = JSON.parse(await readBody(req));
|
|
195
|
-
} catch {
|
|
196
|
-
json(res, 400, { error: "invalid JSON body" });
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
if (!annotation || annotation.id !== id) {
|
|
200
|
-
json(res, 400, { error: "annotation.id must match the URL id" });
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
await storage.save(annotation);
|
|
204
|
-
json(res, 200, { rev: storage.rev });
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
if (req.method === "DELETE" && annMatch) {
|
|
208
|
-
await storage.remove(decodeURIComponent(annMatch[1]));
|
|
209
|
-
json(res, 200, { rev: storage.rev });
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
if (req.method === "DELETE" && pathname === "/annotations") {
|
|
213
|
-
await storage.clear();
|
|
214
|
-
json(res, 200, { rev: storage.rev });
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
json(res, 404, { error: "not found" });
|
|
218
|
-
} catch (err) {
|
|
219
|
-
json(res, 500, { error: err instanceof Error ? err.message : String(err) });
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
function startHttpServer(storage, port) {
|
|
223
|
-
const server = http.createServer((req, res) => {
|
|
224
|
-
void handle(req, res, storage);
|
|
225
|
-
});
|
|
226
|
-
return new Promise((resolve, reject) => {
|
|
227
|
-
server.once("error", reject);
|
|
228
|
-
server.listen(port, "127.0.0.1", () => resolve(server));
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
148
|
|
|
232
149
|
// src/task-folder.ts
|
|
233
150
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -236,6 +153,9 @@ import { actionableOnly, generateAgentExport } from "web-remarq/core";
|
|
|
236
153
|
function yamlString(value) {
|
|
237
154
|
return JSON.stringify(value);
|
|
238
155
|
}
|
|
156
|
+
function isSafeAnnotationId(id) {
|
|
157
|
+
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id);
|
|
158
|
+
}
|
|
239
159
|
function renderTaskFile(annotation) {
|
|
240
160
|
const agent = generateAgentExport([annotation], annotation.viewportBucket).annotations[0];
|
|
241
161
|
const lines = [];
|
|
@@ -295,15 +215,31 @@ var TaskFolder = class {
|
|
|
295
215
|
async sync() {
|
|
296
216
|
const store = await this.storage.load();
|
|
297
217
|
const actionable = actionableOnly(store?.annotations ?? []);
|
|
298
|
-
const desired =
|
|
218
|
+
const desired = /* @__PURE__ */ new Map();
|
|
219
|
+
for (const a of actionable) {
|
|
220
|
+
if (!isSafeAnnotationId(a.id)) {
|
|
221
|
+
console.error(`[web-remarq-mcp] skipping annotation with unsafe id: ${JSON.stringify(a.id)}`);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
desired.set(`${a.id}.md`, renderTaskFile(a));
|
|
225
|
+
}
|
|
299
226
|
mkdirSync2(this.dir, { recursive: true });
|
|
300
|
-
for (const
|
|
301
|
-
if (name.endsWith(".md")
|
|
227
|
+
for (const entry of readdirSync(this.dir, { withFileTypes: true })) {
|
|
228
|
+
if (!entry.isFile() || !entry.name.endsWith(".md") || desired.has(entry.name)) continue;
|
|
229
|
+
try {
|
|
230
|
+
unlinkSync(join2(this.dir, entry.name));
|
|
231
|
+
} catch (err) {
|
|
232
|
+
console.error(`[web-remarq-mcp] failed to remove stale task file ${entry.name}:`, err);
|
|
233
|
+
}
|
|
302
234
|
}
|
|
303
235
|
for (const [name, content] of desired) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
236
|
+
try {
|
|
237
|
+
const path = join2(this.dir, name);
|
|
238
|
+
if (existsSync2(path) && readFileSync2(path, "utf8") === content) continue;
|
|
239
|
+
writeFileSync2(path, content);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error(`[web-remarq-mcp] failed to write task file ${name}:`, err);
|
|
242
|
+
}
|
|
307
243
|
}
|
|
308
244
|
}
|
|
309
245
|
/** Coalesces change bursts: at most one sync in flight, one more queued. Never throws. */
|
|
@@ -326,6 +262,115 @@ var TaskFolder = class {
|
|
|
326
262
|
}
|
|
327
263
|
};
|
|
328
264
|
|
|
265
|
+
// src/http-server.ts
|
|
266
|
+
var CORS_HEADERS = {
|
|
267
|
+
"Access-Control-Allow-Origin": "*",
|
|
268
|
+
"Access-Control-Allow-Methods": "GET, PUT, DELETE, OPTIONS",
|
|
269
|
+
"Access-Control-Allow-Headers": "content-type"
|
|
270
|
+
};
|
|
271
|
+
var MAX_BODY_BYTES = 1024 * 1024;
|
|
272
|
+
function json(res, status, body) {
|
|
273
|
+
res.writeHead(status, { ...CORS_HEADERS, "content-type": "application/json" });
|
|
274
|
+
res.end(JSON.stringify(body));
|
|
275
|
+
}
|
|
276
|
+
function readBody(req) {
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
let size = 0;
|
|
279
|
+
const chunks = [];
|
|
280
|
+
req.on("data", (chunk) => {
|
|
281
|
+
size += chunk.length;
|
|
282
|
+
if (size > MAX_BODY_BYTES) {
|
|
283
|
+
reject(new Error("body too large"));
|
|
284
|
+
req.destroy();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
chunks.push(chunk);
|
|
288
|
+
});
|
|
289
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
290
|
+
req.on("error", reject);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
async function handle(req, res, storage) {
|
|
294
|
+
if (req.method === "OPTIONS") {
|
|
295
|
+
res.writeHead(204, CORS_HEADERS);
|
|
296
|
+
res.end();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
300
|
+
const annMatch = pathname.match(/^\/annotations\/([^/]+)$/);
|
|
301
|
+
try {
|
|
302
|
+
if (req.method === "GET" && pathname === "/store") {
|
|
303
|
+
const rev = storage.rev;
|
|
304
|
+
const store = await storage.load() ?? { version: 1, annotations: [] };
|
|
305
|
+
json(res, 200, { rev, store });
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (req.method === "PUT" && annMatch) {
|
|
309
|
+
const id = decodeURIComponent(annMatch[1]);
|
|
310
|
+
if (!isSafeAnnotationId(id)) {
|
|
311
|
+
json(res, 400, { error: "invalid annotation id" });
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
let annotation;
|
|
315
|
+
try {
|
|
316
|
+
annotation = JSON.parse(await readBody(req));
|
|
317
|
+
} catch {
|
|
318
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (!annotation || annotation.id !== id) {
|
|
322
|
+
json(res, 400, { error: "annotation.id must match the URL id" });
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
await storage.save(annotation);
|
|
326
|
+
json(res, 200, { rev: storage.rev });
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (req.method === "DELETE" && annMatch) {
|
|
330
|
+
const id = decodeURIComponent(annMatch[1]);
|
|
331
|
+
if (!isSafeAnnotationId(id)) {
|
|
332
|
+
json(res, 400, { error: "invalid annotation id" });
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
await storage.remove(id);
|
|
336
|
+
json(res, 200, { rev: storage.rev });
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (req.method === "DELETE" && pathname === "/annotations") {
|
|
340
|
+
await storage.clear();
|
|
341
|
+
json(res, 200, { rev: storage.rev });
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
json(res, 404, { error: "not found" });
|
|
345
|
+
} catch (err) {
|
|
346
|
+
json(res, 500, { error: err instanceof Error ? err.message : String(err) });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function startHttpServer(storage, port) {
|
|
350
|
+
const server = http.createServer((req, res) => {
|
|
351
|
+
void handle(req, res, storage);
|
|
352
|
+
});
|
|
353
|
+
return new Promise((resolve, reject) => {
|
|
354
|
+
server.once("error", reject);
|
|
355
|
+
server.listen(port, "127.0.0.1", () => resolve(server));
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/prompts.ts
|
|
360
|
+
var DUTY_PROMPT = "You are on annotation duty for this project. Designers drop feedback via the web-remarq MCP server. Run this loop until told to stop: call watch_annotations (timeoutSeconds: 60); if it times out, call it again. For EACH annotation it returns, call acknowledge with its id first. Then, if you can run background subagents, dispatch one that applies the fix to the project files and calls claim_fix when done - do not fix anything yourself in the main loop and do not wait for subagents, go straight back to watch_annotations so new feedback is never missed. Without background subagents, apply the fix inline after acknowledging, then return to watch_annotations. If a comment is ambiguous or unactionable, dismiss it with a reason instead of guessing.";
|
|
361
|
+
function registerPrompts(server) {
|
|
362
|
+
server.registerPrompt(
|
|
363
|
+
"watch",
|
|
364
|
+
{
|
|
365
|
+
title: "Annotation duty (dispatcher loop)",
|
|
366
|
+
description: "Put this agent on annotation duty: loop on watch_annotations, acknowledge each annotation first, hand the fix to a background subagent that calls claim_fix, return to watching immediately."
|
|
367
|
+
},
|
|
368
|
+
() => ({
|
|
369
|
+
messages: [{ role: "user", content: { type: "text", text: DUTY_PROMPT } }]
|
|
370
|
+
})
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
329
374
|
// src/tools/list-annotations.ts
|
|
330
375
|
import { z } from "zod";
|
|
331
376
|
|
|
@@ -586,7 +631,7 @@ function registerTools(server, storage, opts) {
|
|
|
586
631
|
server.registerTool(
|
|
587
632
|
"list_annotations",
|
|
588
633
|
{
|
|
589
|
-
description: "List annotations in the project with optional filters (route, status, viewport, file). Each item carries a `quality` score (clear | ambiguous | unactionable) when an AI pre-flight check ran.",
|
|
634
|
+
description: "List annotations in the project with optional filters (route, status, viewport, file). Each item carries a `quality` score (clear | ambiguous | unactionable) when an AI pre-flight check ran. In local mode, actionable annotations (pending / in_progress) are also mirrored as ticket files in .remarq/tasks/.",
|
|
590
635
|
inputSchema: listAnnotationsInputSchema.shape
|
|
591
636
|
},
|
|
592
637
|
(input) => cast(handleListAnnotations(input, storage))
|
|
@@ -650,12 +695,13 @@ async function main() {
|
|
|
650
695
|
let waitForChange;
|
|
651
696
|
if (config.mode === "local") {
|
|
652
697
|
const adapter = new FileStorageAdapter(config.dataFile);
|
|
653
|
-
const
|
|
698
|
+
const tasksDir = join3(dirname2(config.dataFile), "tasks");
|
|
699
|
+
const taskFolder = new TaskFolder(adapter, tasksDir);
|
|
654
700
|
adapter.onChange(() => taskFolder.schedule());
|
|
655
701
|
taskFolder.schedule();
|
|
656
702
|
await startHttpServer(adapter, config.port);
|
|
657
703
|
console.error(
|
|
658
|
-
`[web-remarq-mcp] local mode \u2014 widget endpoint http://127.0.0.1:${config.port}, store ${config.dataFile}`
|
|
704
|
+
`[web-remarq-mcp] local mode \u2014 widget endpoint http://127.0.0.1:${config.port}, store ${config.dataFile}, tasks ${tasksDir}`
|
|
659
705
|
);
|
|
660
706
|
storage = adapter;
|
|
661
707
|
waitForChange = (ms) => adapter.waitForChange(ms);
|
|
@@ -665,9 +711,10 @@ async function main() {
|
|
|
665
711
|
}
|
|
666
712
|
const server = new McpServer({
|
|
667
713
|
name: "web-remarq",
|
|
668
|
-
version: "0.
|
|
714
|
+
version: "0.4.0"
|
|
669
715
|
});
|
|
670
716
|
registerTools(server, storage, { waitForChange });
|
|
717
|
+
registerPrompts(server);
|
|
671
718
|
const transport = new StdioServerTransport();
|
|
672
719
|
await server.connect(transport);
|
|
673
720
|
}
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts","../src/config.ts","../src/storage-factory.ts","../src/file-storage-adapter.ts","../src/http-server.ts","../src/task-folder.ts","../src/tools/list-annotations.ts","../src/errors.ts","../src/tools/get-annotation.ts","../src/tools/acknowledge.ts","../src/tools/claim-fix.ts","../src/tools/dismiss.ts","../src/tools/watch-annotations.ts","../src/tools/index.ts"],"sourcesContent":["import { dirname, join } from 'node:path'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport type { StorageAdapter } from 'web-remarq'\nimport { parseEnv, ConfigError } from './config.js'\nimport { createStorage } from './storage-factory.js'\nimport { FileStorageAdapter } from './file-storage-adapter.js'\nimport { startHttpServer } from './http-server.js'\nimport { TaskFolder } from './task-folder.js'\nimport { registerTools, type WaitForChange } from './tools/index.js'\n\nconst CLOUD_POLL_MS = 3000\n\nasync function main(): Promise<void> {\n let config\n try {\n config = parseEnv(process.env)\n } catch (err) {\n if (err instanceof ConfigError) {\n console.error(`[web-remarq-mcp] config error: ${err.message}`)\n process.exit(1)\n }\n throw err\n }\n\n let storage: StorageAdapter\n let waitForChange: WaitForChange\n\n if (config.mode === 'local') {\n const adapter = new FileStorageAdapter(config.dataFile)\n const taskFolder = new TaskFolder(adapter, join(dirname(config.dataFile), 'tasks'))\n adapter.onChange(() => taskFolder.schedule())\n taskFolder.schedule() // project existing annotations on startup\n await startHttpServer(adapter, config.port)\n console.error(\n `[web-remarq-mcp] local mode — widget endpoint http://127.0.0.1:${config.port}, store ${config.dataFile}`,\n )\n storage = adapter\n waitForChange = (ms) => adapter.waitForChange(ms)\n } else {\n storage = createStorage(config)\n waitForChange = (ms) =>\n new Promise((resolve) => setTimeout(() => resolve(false), Math.min(ms, CLOUD_POLL_MS)))\n }\n\n const server = new McpServer({\n name: 'web-remarq',\n version: '0.2.0',\n })\n\n registerTools(server, storage, { waitForChange })\n\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\nmain().catch((err) => {\n console.error('[web-remarq-mcp] fatal:', err)\n process.exit(1)\n})\n","export interface CloudConfig {\n mode: 'cloud'\n projectKey: string\n supabaseUrl: string\n supabaseAnonKey: string\n}\n\nexport interface LocalConfig {\n mode: 'local'\n port: number\n dataFile: string\n}\n\nexport type MCPConfig = CloudConfig | LocalConfig\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ConfigError'\n }\n}\n\nfunction require_(env: NodeJS.ProcessEnv, key: string): string {\n const v = env[key]\n if (!v || v.trim() === '') {\n throw new ConfigError(`Missing required env var: ${key}`)\n }\n return v\n}\n\nconst DEFAULT_PORT = 1817\nconst DEFAULT_DATA_FILE = '.remarq/annotations.json'\n\nexport function parseEnv(env: NodeJS.ProcessEnv): MCPConfig {\n const cloudRequested = Boolean(\n env.REMARQ_PROJECT_KEY || env.REMARQ_SUPABASE_URL || env.REMARQ_SUPABASE_ANON_KEY,\n )\n\n if (cloudRequested) {\n const projectKey = require_(env, 'REMARQ_PROJECT_KEY')\n const supabaseUrl = require_(env, 'REMARQ_SUPABASE_URL')\n const supabaseAnonKey = require_(env, 'REMARQ_SUPABASE_ANON_KEY')\n\n if (!projectKey.startsWith('pk_')) {\n throw new ConfigError('REMARQ_PROJECT_KEY must start with `pk_` (generated by `npx @web-remarq/cloud gen-key`)')\n }\n if (!supabaseUrl.startsWith('https://')) {\n throw new ConfigError('REMARQ_SUPABASE_URL must start with https://')\n }\n\n return { mode: 'cloud', projectKey, supabaseUrl, supabaseAnonKey }\n }\n\n const rawPort = env.REMARQ_PORT ?? String(DEFAULT_PORT)\n const port = Number(rawPort)\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new ConfigError(`REMARQ_PORT must be an integer between 1 and 65535, got \"${rawPort}\"`)\n }\n\n return { mode: 'local', port, dataFile: env.REMARQ_DATA_FILE ?? DEFAULT_DATA_FILE }\n}\n","import { createCloudStorage } from '@web-remarq/cloud'\nimport type { StorageAdapter } from 'web-remarq'\nimport type { CloudConfig } from './config'\n\nexport function createStorage(config: CloudConfig): StorageAdapter {\n return createCloudStorage({\n projectKey: config.projectKey,\n supabaseUrl: config.supabaseUrl,\n supabaseAnonKey: config.supabaseAnonKey,\n onError: 'throw',\n })\n}\n","import { EventEmitter } from 'node:events'\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\nimport type { Annotation, AnnotationStore, StorageAdapter } from 'web-remarq'\n\n/**\n * Local-mode StorageAdapter over a JSON file (default .remarq/annotations.json).\n * All mutations flow through this process (MCP tools + the local HTTP server),\n * so change notification is a plain in-memory emitter — no fs.watch needed.\n */\nexport class FileStorageAdapter implements StorageAdapter {\n /** Monotonic revision — bumps on every mutation. Exposed via GET /store. */\n rev = 0\n private emitter = new EventEmitter()\n /** Serializes mutations (save/remove/clear) so concurrent read-modify-write ops don't clobber each other. */\n private queue: Promise<void> = Promise.resolve()\n\n constructor(private filePath: string) {\n this.emitter.setMaxListeners(0)\n }\n\n async load(): Promise<AnnotationStore | null> {\n if (!existsSync(this.filePath)) return null\n let parsed: unknown\n try {\n parsed = JSON.parse(readFileSync(this.filePath, 'utf8'))\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`annotations store corrupted at ${this.filePath}: ${message}`)\n }\n const store = parsed as { annotations?: unknown }\n return {\n version: 1,\n annotations: Array.isArray(store.annotations) ? (store.annotations as Annotation[]) : [],\n }\n }\n\n async save(annotation: Annotation): Promise<void> {\n return this.enqueue(async () => {\n const store = (await this.load()) ?? { version: 1 as const, annotations: [] }\n const idx = store.annotations.findIndex((a) => a.id === annotation.id)\n if (idx === -1) store.annotations.push(annotation)\n else store.annotations[idx] = annotation\n this.persist(store)\n })\n }\n\n async remove(id: string): Promise<void> {\n return this.enqueue(async () => {\n const store = (await this.load()) ?? { version: 1 as const, annotations: [] }\n store.annotations = store.annotations.filter((a) => a.id !== id)\n this.persist(store)\n })\n }\n\n async clear(): Promise<void> {\n return this.enqueue(async () => {\n this.persist({ version: 1, annotations: [] })\n })\n }\n\n /** Chains `op` onto the mutation queue; a rejected op doesn't poison later ops. */\n private enqueue(op: () => Promise<void>): Promise<void> {\n const result = this.queue.then(op)\n // Swallow the rejection on the shared chain so the next enqueued op still runs;\n // the caller's own `result` promise still rejects with the original error.\n this.queue = result.catch(() => undefined)\n return result\n }\n\n /** Resolves true on the next mutation, false after timeoutMs. */\n waitForChange(timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n const onChange = (): void => {\n clearTimeout(timer)\n resolve(true)\n }\n const timer = setTimeout(() => {\n this.emitter.off('change', onChange)\n resolve(false)\n }, timeoutMs)\n this.emitter.once('change', onChange)\n })\n }\n\n /** Persistent listener for every mutation (save/remove/clear). */\n onChange(listener: () => void): void {\n this.emitter.on('change', listener)\n }\n\n private persist(store: AnnotationStore): void {\n const dir = dirname(this.filePath)\n mkdirSync(dir, { recursive: true })\n // Auto-ignore the store when it lives in the conventional .remarq dir.\n // NEVER write a wildcard .gitignore into an arbitrary user directory.\n if (basename(dir) === '.remarq') {\n const gitignore = join(dir, '.gitignore')\n if (!existsSync(gitignore)) writeFileSync(gitignore, '*\\n')\n }\n const tmp = `${this.filePath}.tmp`\n writeFileSync(tmp, JSON.stringify(store, null, 2))\n renameSync(tmp, this.filePath)\n this.rev++\n this.emitter.emit('change')\n }\n}\n","import * as http from 'node:http'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { FileStorageAdapter } from './file-storage-adapter.js'\n\nconst CORS_HEADERS: Record<string, string> = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'content-type',\n}\n\nconst MAX_BODY_BYTES = 1024 * 1024\n\nfunction json(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { ...CORS_HEADERS, 'content-type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let size = 0\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_BODY_BYTES) {\n reject(new Error('body too large'))\n req.destroy()\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))\n req.on('error', reject)\n })\n}\n\nasync function handle(req: IncomingMessage, res: ServerResponse, storage: FileStorageAdapter): Promise<void> {\n if (req.method === 'OPTIONS') {\n res.writeHead(204, CORS_HEADERS)\n res.end()\n return\n }\n\n const pathname = new URL(req.url ?? '/', 'http://localhost').pathname\n const annMatch = pathname.match(/^\\/annotations\\/([^/]+)$/)\n\n try {\n if (req.method === 'GET' && pathname === '/store') {\n // Capture rev before the await, not after: a concurrent mutation between\n // load() and reading storage.rev would pair a newer rev with the older\n // content this response body carries. Under-reporting is safe (the\n // client's next poll re-diffs); over-reporting is not.\n const rev = storage.rev\n const store = (await storage.load()) ?? { version: 1 as const, annotations: [] }\n json(res, 200, { rev, store })\n return\n }\n\n if (req.method === 'PUT' && annMatch) {\n const id = decodeURIComponent(annMatch[1])\n let annotation: { id?: unknown }\n try {\n annotation = JSON.parse(await readBody(req))\n } catch {\n json(res, 400, { error: 'invalid JSON body' })\n return\n }\n if (!annotation || annotation.id !== id) {\n json(res, 400, { error: 'annotation.id must match the URL id' })\n return\n }\n // The store is trusted local input from the widget; no schema validation.\n await storage.save(annotation as never)\n json(res, 200, { rev: storage.rev })\n return\n }\n\n if (req.method === 'DELETE' && annMatch) {\n await storage.remove(decodeURIComponent(annMatch[1]))\n json(res, 200, { rev: storage.rev })\n return\n }\n\n if (req.method === 'DELETE' && pathname === '/annotations') {\n await storage.clear()\n json(res, 200, { rev: storage.rev })\n return\n }\n\n json(res, 404, { error: 'not found' })\n } catch (err) {\n json(res, 500, { error: err instanceof Error ? err.message : String(err) })\n }\n}\n\n/** Starts the widget-facing endpoint on 127.0.0.1:port. Rejects on bind errors. */\nexport function startHttpServer(storage: FileStorageAdapter, port: number): Promise<http.Server> {\n const server = http.createServer((req, res) => {\n void handle(req, res, storage)\n })\n return new Promise((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, '127.0.0.1', () => resolve(server))\n })\n}\n","import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Annotation, StorageAdapter } from 'web-remarq'\nimport { actionableOnly, generateAgentExport } from 'web-remarq/core'\n\n/** Double-quoted YAML scalar; JSON string escaping is valid YAML. */\nfunction yamlString(value: string): string {\n return JSON.stringify(value)\n}\n\n/**\n * Renders one annotation as a ticket file for .remarq/tasks/.\n * Deterministic: TaskFolder diffs the output against the file on disk\n * to skip no-op rewrites.\n */\nexport function renderTaskFile(annotation: Annotation): string {\n // Reuse core agent-export for source resolution + search hints (same pattern as get_annotation).\n const agent = generateAgentExport([annotation], annotation.viewportBucket).annotations[0]\n const lines: string[] = []\n\n lines.push('---')\n lines.push(`id: ${yamlString(agent.id)}`)\n lines.push(`route: ${yamlString(agent.route)}`)\n lines.push(`status: ${agent.status}`)\n lines.push(`viewportBucket: ${annotation.viewportBucket}`)\n if (annotation.qualityCheck) lines.push(`quality: ${annotation.qualityCheck.score}`)\n lines.push('---', '')\n\n lines.push(`# web-remarq annotation ${agent.id}`, '')\n lines.push('## Comment', '', agent.comment.trim(), '')\n\n lines.push('## Element', '')\n lines.push(`- Tag: \\`${agent.searchHints.tagName}\\``)\n lines.push(`- DOM: \\`${agent.searchHints.domContext}\\``)\n if (agent.source) {\n const component = agent.source.component ? ` (component \\`${agent.source.component}\\`)` : ''\n lines.push(`- Source: \\`${agent.source.file}:${agent.source.line}:${agent.source.column}\\`${component}`)\n }\n if (agent.searchHints.classes.length) {\n lines.push(`- Classes: ${agent.searchHints.classes.map((c) => `\\`${c}\\``).join(' ')}`)\n }\n lines.push('')\n\n if (agent.searchHints.grepQueries.length) {\n lines.push('## Search hints', '')\n for (const q of agent.searchHints.grepQueries) {\n lines.push(`- [${q.confidence}] \\`${q.query}\\` in \\`${q.glob}\\``)\n }\n lines.push('')\n }\n\n const qc = annotation.qualityCheck\n if (qc && qc.score !== 'clear') {\n lines.push('## Quality check', '')\n lines.push(`Verdict: **${qc.score}** - this comment may need designer clarification; if you cannot act on it confidently, dismiss with a reason instead of guessing.`, '')\n for (const issue of qc.issues) lines.push(`- Issue: ${issue}`)\n for (const q of qc.clarifyingQuestions) lines.push(`- Open question: ${q}`)\n if (qc.suggestedRewrite) lines.push(`- Suggested rewrite: ${qc.suggestedRewrite}`)\n lines.push('')\n }\n\n lines.push('## Agent instructions', '')\n lines.push(`1. BEFORE touching code, call the web-remarq MCP tool \\`acknowledge\\` with \\`{ \"id\": ${yamlString(agent.id)} }\\`. If it errors, another agent already owns this task - skip this file.`)\n lines.push('2. Apply the fix described in the comment.')\n lines.push(`3. When the fix is committed to the working tree, call \\`claim_fix\\` with \\`{ \"id\": ${yamlString(agent.id)} }\\`. A human verifies afterwards - never mark anything as done yourself.`)\n lines.push('')\n lines.push('This file is a live projection maintained by the web-remarq MCP server: it updates when the annotation changes and disappears once the annotation is verified or dismissed. Do not edit or delete it.')\n lines.push('')\n\n return lines.join('\\n')\n}\n\n/**\n * Live projection of actionable annotations (pending/in_progress) into a\n * folder of <id>.md ticket files. The folder is server-owned: every *.md in\n * it is managed - stale ones are deleted on sync. Non-md files are ignored.\n */\nexport class TaskFolder {\n private syncing = false\n private dirty = false\n\n constructor(\n private storage: Pick<StorageAdapter, 'load'>,\n private dir: string,\n ) {}\n\n /** Full idempotent resync: folder contents converge to the actionable set. */\n async sync(): Promise<void> {\n const store = await this.storage.load()\n const actionable = actionableOnly(store?.annotations ?? [])\n const desired = new Map(actionable.map((a) => [`${a.id}.md`, renderTaskFile(a)]))\n\n mkdirSync(this.dir, { recursive: true })\n for (const name of readdirSync(this.dir)) {\n if (name.endsWith('.md') && !desired.has(name)) unlinkSync(join(this.dir, name))\n }\n for (const [name, content] of desired) {\n const path = join(this.dir, name)\n if (existsSync(path) && readFileSync(path, 'utf8') === content) continue\n writeFileSync(path, content)\n }\n }\n\n /** Coalesces change bursts: at most one sync in flight, one more queued. Never throws. */\n schedule(): void {\n this.dirty = true\n void this.run()\n }\n\n private async run(): Promise<void> {\n if (this.syncing) return\n this.syncing = true\n while (this.dirty) {\n this.dirty = false\n try {\n await this.sync()\n } catch (err) {\n console.error('[web-remarq-mcp] task folder sync failed:', err)\n }\n }\n this.syncing = false\n }\n}\n","import { z } from 'zod'\nimport type { Annotation, AnnotationStatus, QualityCheck, StorageAdapter } from 'web-remarq'\nimport { toolError, toolSuccess } from '../errors'\n\nconst STATUS_VALUES = ['draft', 'pending', 'in_progress', 'fixed_unverified', 'verified', 'dismissed'] as const\n\nexport const listAnnotationsInputSchema = z.object({\n route: z.string().optional(),\n status: z.union([z.enum(STATUS_VALUES), z.array(z.enum(STATUS_VALUES))]).optional(),\n viewportBucket: z.number().int().optional(),\n file: z.string().optional(),\n limit: z.number().int().min(1).max(200).optional(),\n})\n\nexport type ListAnnotationsInput = z.infer<typeof listAnnotationsInputSchema>\n\nexport interface ThinAnnotation {\n id: string\n route: string\n comment: string\n status: AnnotationStatus\n viewport: number\n timestamp: number\n source: { file: string; line: number; column: number; component?: string } | null\n quality?: QualityCheck['score']\n}\n\nfunction parseSource(annotation: Annotation): ThinAnnotation['source'] {\n const fp = annotation.fingerprint\n const raw = fp.sourceLocation ?? fp.detectedSource\n if (!raw) return null\n const parts = raw.split(':')\n if (parts.length < 2) return null\n const column = parseInt(parts.pop()!, 10)\n const line = parseInt(parts.pop()!, 10)\n const file = parts.join(':')\n if (!file || isNaN(line)) return null\n const component = fp.componentName ?? fp.detectedComponent ?? undefined\n return { file, line, column: isNaN(column) ? 0 : column, ...(component ? { component } : {}) }\n}\n\nexport function toThin(a: Annotation): ThinAnnotation {\n return {\n id: a.id,\n route: a.route,\n comment: a.comment,\n status: a.status,\n viewport: a.viewportBucket,\n timestamp: a.timestamp,\n source: parseSource(a),\n ...(a.qualityCheck ? { quality: a.qualityCheck.score } : {}),\n }\n}\n\nexport async function handleListAnnotations(input: ListAnnotationsInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const all = store?.annotations ?? []\n\n const statusFilter = Array.isArray(input.status)\n ? new Set(input.status)\n : input.status\n ? new Set([input.status])\n : null\n\n const filtered = all.filter((a) => {\n if (input.route !== undefined && a.route !== input.route) return false\n if (statusFilter && !statusFilter.has(a.status)) return false\n if (input.viewportBucket !== undefined && a.viewportBucket !== input.viewportBucket) return false\n if (input.file !== undefined) {\n const src = a.fingerprint.sourceLocation ?? a.fingerprint.detectedSource ?? ''\n if (!src.includes(input.file)) return false\n }\n return true\n })\n\n const limit = input.limit ?? 50\n const thinned = filtered.slice(0, limit).map(toThin)\n\n return toolSuccess({ annotations: thinned, total: filtered.length })\n}\n","export type ToolErrorCode =\n | 'annotation_not_found'\n | 'invalid_transition'\n | 'storage_error'\n | 'validation_error'\n\nexport interface ToolErrorPayload {\n code: ToolErrorCode\n message: string\n details?: Record<string, unknown>\n}\n\nexport interface ToolErrorResult {\n isError: true\n content: Array<{ type: 'text'; text: string }>\n}\n\nexport function toolError(code: ToolErrorCode, message: string, details?: Record<string, unknown>): ToolErrorResult {\n const payload: ToolErrorPayload = { code, message, details }\n return {\n isError: true,\n content: [{ type: 'text', text: JSON.stringify(payload) }],\n }\n}\n\nexport interface ToolSuccessResult {\n isError?: false\n content: Array<{ type: 'text'; text: string }>\n}\n\nexport function toolSuccess(value: unknown): ToolSuccessResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(value) }],\n }\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { generateAgentExport } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const getAnnotationInputSchema = z.object({\n id: z.string(),\n})\n\nexport type GetAnnotationInput = z.infer<typeof getAnnotationInputSchema>\n\nexport async function handleGetAnnotation(input: GetAnnotationInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n // Reuse core agent-export to build the rich shape (source + searchHints + lifecycle).\n // generateAgentExport takes an array — pass the single annotation, then extract.\n const agentExport = generateAgentExport([annotation], annotation.viewportBucket)\n const agentAnnotation = agentExport.annotations[0]\n\n return toolSuccess(agentAnnotation)\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { transition, InvalidTransitionError } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const acknowledgeInputSchema = z.object({\n id: z.string(),\n})\n\nexport type AcknowledgeInput = z.infer<typeof acknowledgeInputSchema>\n\nexport async function handleAcknowledge(input: AcknowledgeInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n let result\n try {\n result = transition(annotation, 'acknowledge', { actor: 'agent' })\n } catch (err) {\n if (err instanceof InvalidTransitionError) {\n return toolError('invalid_transition', err.message, {\n currentStatus: annotation.status,\n requestedTransition: 'acknowledge',\n })\n }\n throw err\n }\n\n const updated = {\n ...annotation,\n status: result.status,\n lifecycle: [...annotation.lifecycle, result.event],\n }\n\n try {\n await storage.save(updated)\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n return toolSuccess({ ok: true, status: result.status })\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { transition, InvalidTransitionError } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const claimFixInputSchema = z.object({\n id: z.string(),\n})\n\nexport type ClaimFixInput = z.infer<typeof claimFixInputSchema>\n\nexport async function handleClaimFix(input: ClaimFixInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n let result\n try {\n result = transition(annotation, 'claimFix', { actor: 'agent' })\n } catch (err) {\n if (err instanceof InvalidTransitionError) {\n return toolError('invalid_transition', err.message, {\n currentStatus: annotation.status,\n requestedTransition: 'claimFix',\n })\n }\n throw err\n }\n\n const updated = {\n ...annotation,\n status: result.status,\n lifecycle: [...annotation.lifecycle, result.event],\n }\n\n try {\n await storage.save(updated)\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n return toolSuccess({ ok: true, status: result.status })\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { transition, InvalidTransitionError } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const dismissInputSchema = z.object({\n id: z.string(),\n reason: z.string().optional(),\n})\n\nexport type DismissInput = z.infer<typeof dismissInputSchema>\n\nexport async function handleDismiss(input: DismissInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n let result\n try {\n result = transition(annotation, 'dismiss', { actor: 'agent', reason: input.reason })\n } catch (err) {\n if (err instanceof InvalidTransitionError) {\n return toolError('invalid_transition', err.message, {\n currentStatus: annotation.status,\n requestedTransition: 'dismiss',\n })\n }\n throw err\n }\n\n const updated = {\n ...annotation,\n status: result.status,\n lifecycle: [...annotation.lifecycle, result.event],\n }\n\n try {\n await storage.save(updated)\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n return toolSuccess({ ok: true, status: result.status })\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { toolError, toolSuccess } from '../errors'\nimport { toThin } from './list-annotations.js'\n\n/** Waits up to timeoutMs for a backend change. Local mode resolves early on\n * mutation events; cloud mode just sleeps a poll interval and returns false. */\nexport type WaitForChange = (timeoutMs: number) => Promise<boolean>\n\nconst DEFAULT_TIMEOUT_SECONDS = 25\n\nexport const watchAnnotationsInputSchema = z.object({\n timeoutSeconds: z.number().int().min(1).max(120).optional(),\n})\n\nexport type WatchAnnotationsInput = z.infer<typeof watchAnnotationsInputSchema>\n\nexport async function handleWatchAnnotations(\n input: WatchAnnotationsInput,\n storage: StorageAdapter,\n waitForChange: WaitForChange,\n) {\n const timeoutMs = (input.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS) * 1000\n const deadline = Date.now() + timeoutMs\n\n for (;;) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n const pending = (store?.annotations ?? []).filter((a) => a.status === 'pending')\n if (pending.length > 0) {\n return toolSuccess({ annotations: pending.map(toThin), total: pending.length, timedOut: false })\n }\n\n const remaining = deadline - Date.now()\n if (remaining <= 0) {\n return toolSuccess({ annotations: [], total: 0, timedOut: true })\n }\n\n await waitForChange(remaining)\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { StorageAdapter } from 'web-remarq'\n\nimport { listAnnotationsInputSchema, handleListAnnotations } from './list-annotations.js'\nimport { getAnnotationInputSchema, handleGetAnnotation } from './get-annotation.js'\nimport { acknowledgeInputSchema, handleAcknowledge } from './acknowledge.js'\nimport { claimFixInputSchema, handleClaimFix } from './claim-fix.js'\nimport { dismissInputSchema, handleDismiss } from './dismiss.js'\nimport { watchAnnotationsInputSchema, handleWatchAnnotations, type WaitForChange } from './watch-annotations.js'\n\nexport type { WaitForChange } from './watch-annotations.js'\n\n// Cast helper: our tool results satisfy CallToolResult at runtime; the SDK's\n// inferred type carries an index signature that our narrower types lack.\nfunction cast(p: Promise<{ isError?: boolean; content: Array<{ type: 'text'; text: string }> }>): Promise<CallToolResult> {\n return p as Promise<CallToolResult>\n}\n\nexport function registerTools(\n server: McpServer,\n storage: StorageAdapter,\n opts: { waitForChange: WaitForChange },\n): void {\n server.registerTool(\n 'list_annotations',\n {\n description: 'List annotations in the project with optional filters (route, status, viewport, file). Each item carries a `quality` score (clear | ambiguous | unactionable) when an AI pre-flight check ran.',\n inputSchema: listAnnotationsInputSchema.shape,\n },\n (input) => cast(handleListAnnotations(input, storage)),\n )\n\n server.registerTool(\n 'get_annotation',\n {\n description: 'Get full annotation details including source file:line:col, grep search hints, and the AI quality verdict (`qualityCheck`). If qualityCheck.score is \"ambiguous\" or \"unactionable\", the comment may need designer clarification before fixing — consider dismissing with a reason instead of guessing.',\n inputSchema: getAnnotationInputSchema.shape,\n },\n (input) => cast(handleGetAnnotation(input, storage)),\n )\n\n server.registerTool(\n 'acknowledge',\n {\n description: 'Mark an annotation as in-progress (pending → in_progress).',\n inputSchema: acknowledgeInputSchema.shape,\n },\n (input) => cast(handleAcknowledge(input, storage)),\n )\n\n server.registerTool(\n 'claim_fix',\n {\n description: 'Claim a fix for an annotation (→ fixed_unverified). Human verification still required.',\n inputSchema: claimFixInputSchema.shape,\n },\n (input) => cast(handleClaimFix(input, storage)),\n )\n\n server.registerTool(\n 'dismiss',\n {\n description: 'Dismiss an annotation with an optional reason (terminal state).',\n inputSchema: dismissInputSchema.shape,\n },\n (input) => cast(handleDismiss(input, storage)),\n )\n\n server.registerTool(\n 'watch_annotations',\n {\n description:\n 'Wait for pending annotations (long-poll). Returns immediately if pending annotations exist; otherwise blocks until one appears or timeoutSeconds (default 25) elapses, then returns {\"annotations\": [], \"timedOut\": true}. Call this in a loop to continuously pick up designer feedback. If your environment can run background subagents (e.g. a Task tool), act as a dispatcher: for each returned annotation call acknowledge first (so it stops being redelivered), hand the fix to a background subagent that will claim_fix when done, and return to watch_annotations immediately instead of fixing inline - new feedback must never wait on a fix in progress. Without subagents, acknowledge each annotation before you start fixing it.',\n inputSchema: watchAnnotationsInputSchema.shape,\n },\n (input) => cast(handleWatchAnnotations(input, storage, opts.waitForChange)),\n )\n}\n"],"mappings":"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","names":["dirname","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","z","generateAgentExport","z","generateAgentExport","z","z","z","transition","InvalidTransitionError","z","transition","InvalidTransitionError","z","transition","InvalidTransitionError","z","transition","InvalidTransitionError","z","z","join","dirname"]}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/config.ts","../src/storage-factory.ts","../src/file-storage-adapter.ts","../src/http-server.ts","../src/task-folder.ts","../src/prompts.ts","../src/tools/list-annotations.ts","../src/errors.ts","../src/tools/get-annotation.ts","../src/tools/acknowledge.ts","../src/tools/claim-fix.ts","../src/tools/dismiss.ts","../src/tools/watch-annotations.ts","../src/tools/index.ts"],"sourcesContent":["import { dirname, join } from 'node:path'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport type { StorageAdapter } from 'web-remarq'\nimport { parseEnv, ConfigError } from './config.js'\nimport { createStorage } from './storage-factory.js'\nimport { FileStorageAdapter } from './file-storage-adapter.js'\nimport { startHttpServer } from './http-server.js'\nimport { TaskFolder } from './task-folder.js'\nimport { registerPrompts } from './prompts.js'\nimport { registerTools, type WaitForChange } from './tools/index.js'\n\nconst CLOUD_POLL_MS = 3000\n\nasync function main(): Promise<void> {\n let config\n try {\n config = parseEnv(process.env)\n } catch (err) {\n if (err instanceof ConfigError) {\n console.error(`[web-remarq-mcp] config error: ${err.message}`)\n process.exit(1)\n }\n throw err\n }\n\n let storage: StorageAdapter\n let waitForChange: WaitForChange\n\n if (config.mode === 'local') {\n const adapter = new FileStorageAdapter(config.dataFile)\n const tasksDir = join(dirname(config.dataFile), 'tasks')\n const taskFolder = new TaskFolder(adapter, tasksDir)\n adapter.onChange(() => taskFolder.schedule())\n taskFolder.schedule() // project existing annotations on startup\n await startHttpServer(adapter, config.port)\n console.error(\n `[web-remarq-mcp] local mode — widget endpoint http://127.0.0.1:${config.port}, store ${config.dataFile}, tasks ${tasksDir}`,\n )\n storage = adapter\n waitForChange = (ms) => adapter.waitForChange(ms)\n } else {\n storage = createStorage(config)\n waitForChange = (ms) =>\n new Promise((resolve) => setTimeout(() => resolve(false), Math.min(ms, CLOUD_POLL_MS)))\n }\n\n const server = new McpServer({\n name: 'web-remarq',\n version: '0.4.0',\n })\n\n registerTools(server, storage, { waitForChange })\n registerPrompts(server)\n\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\nmain().catch((err) => {\n console.error('[web-remarq-mcp] fatal:', err)\n process.exit(1)\n})\n","export interface CloudConfig {\n mode: 'cloud'\n projectKey: string\n supabaseUrl: string\n supabaseAnonKey: string\n}\n\nexport interface LocalConfig {\n mode: 'local'\n port: number\n dataFile: string\n}\n\nexport type MCPConfig = CloudConfig | LocalConfig\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ConfigError'\n }\n}\n\nfunction require_(env: NodeJS.ProcessEnv, key: string): string {\n const v = env[key]\n if (!v || v.trim() === '') {\n throw new ConfigError(`Missing required env var: ${key}`)\n }\n return v\n}\n\nconst DEFAULT_PORT = 1817\nconst DEFAULT_DATA_FILE = '.remarq/annotations.json'\n\nexport function parseEnv(env: NodeJS.ProcessEnv): MCPConfig {\n const cloudRequested = Boolean(\n env.REMARQ_PROJECT_KEY || env.REMARQ_SUPABASE_URL || env.REMARQ_SUPABASE_ANON_KEY,\n )\n\n if (cloudRequested) {\n const projectKey = require_(env, 'REMARQ_PROJECT_KEY')\n const supabaseUrl = require_(env, 'REMARQ_SUPABASE_URL')\n const supabaseAnonKey = require_(env, 'REMARQ_SUPABASE_ANON_KEY')\n\n if (!projectKey.startsWith('pk_')) {\n throw new ConfigError('REMARQ_PROJECT_KEY must start with `pk_` (generated by `npx @web-remarq/cloud gen-key`)')\n }\n if (!supabaseUrl.startsWith('https://')) {\n throw new ConfigError('REMARQ_SUPABASE_URL must start with https://')\n }\n\n return { mode: 'cloud', projectKey, supabaseUrl, supabaseAnonKey }\n }\n\n const rawPort = env.REMARQ_PORT ?? String(DEFAULT_PORT)\n const port = Number(rawPort)\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new ConfigError(`REMARQ_PORT must be an integer between 1 and 65535, got \"${rawPort}\"`)\n }\n\n return { mode: 'local', port, dataFile: env.REMARQ_DATA_FILE ?? DEFAULT_DATA_FILE }\n}\n","import { createCloudStorage } from '@web-remarq/cloud'\nimport type { StorageAdapter } from 'web-remarq'\nimport type { CloudConfig } from './config'\n\nexport function createStorage(config: CloudConfig): StorageAdapter {\n return createCloudStorage({\n projectKey: config.projectKey,\n supabaseUrl: config.supabaseUrl,\n supabaseAnonKey: config.supabaseAnonKey,\n onError: 'throw',\n })\n}\n","import { EventEmitter } from 'node:events'\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\nimport type { Annotation, AnnotationStore, StorageAdapter } from 'web-remarq'\n\n/**\n * Local-mode StorageAdapter over a JSON file (default .remarq/annotations.json).\n * All mutations flow through this process (MCP tools + the local HTTP server),\n * so change notification is a plain in-memory emitter — no fs.watch needed.\n */\nexport class FileStorageAdapter implements StorageAdapter {\n /** Monotonic revision — bumps on every mutation. Exposed via GET /store. */\n rev = 0\n private emitter = new EventEmitter()\n /** Serializes mutations (save/remove/clear) so concurrent read-modify-write ops don't clobber each other. */\n private queue: Promise<void> = Promise.resolve()\n\n constructor(private filePath: string) {\n this.emitter.setMaxListeners(0)\n }\n\n async load(): Promise<AnnotationStore | null> {\n if (!existsSync(this.filePath)) return null\n let parsed: unknown\n try {\n parsed = JSON.parse(readFileSync(this.filePath, 'utf8'))\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`annotations store corrupted at ${this.filePath}: ${message}`)\n }\n const store = parsed as { annotations?: unknown }\n return {\n version: 1,\n annotations: Array.isArray(store.annotations) ? (store.annotations as Annotation[]) : [],\n }\n }\n\n async save(annotation: Annotation): Promise<void> {\n return this.enqueue(async () => {\n const store = (await this.load()) ?? { version: 1 as const, annotations: [] }\n const idx = store.annotations.findIndex((a) => a.id === annotation.id)\n if (idx === -1) store.annotations.push(annotation)\n else store.annotations[idx] = annotation\n this.persist(store)\n })\n }\n\n async remove(id: string): Promise<void> {\n return this.enqueue(async () => {\n const store = (await this.load()) ?? { version: 1 as const, annotations: [] }\n store.annotations = store.annotations.filter((a) => a.id !== id)\n this.persist(store)\n })\n }\n\n async clear(): Promise<void> {\n return this.enqueue(async () => {\n this.persist({ version: 1, annotations: [] })\n })\n }\n\n /** Chains `op` onto the mutation queue; a rejected op doesn't poison later ops. */\n private enqueue(op: () => Promise<void>): Promise<void> {\n const result = this.queue.then(op)\n // Swallow the rejection on the shared chain so the next enqueued op still runs;\n // the caller's own `result` promise still rejects with the original error.\n this.queue = result.catch(() => undefined)\n return result\n }\n\n /** Resolves true on the next mutation, false after timeoutMs. */\n waitForChange(timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n const onChange = (): void => {\n clearTimeout(timer)\n resolve(true)\n }\n const timer = setTimeout(() => {\n this.emitter.off('change', onChange)\n resolve(false)\n }, timeoutMs)\n this.emitter.once('change', onChange)\n })\n }\n\n /** Persistent listener for every mutation (save/remove/clear). */\n onChange(listener: () => void): void {\n this.emitter.on('change', listener)\n }\n\n private persist(store: AnnotationStore): void {\n const dir = dirname(this.filePath)\n mkdirSync(dir, { recursive: true })\n // Auto-ignore the store when it lives in the conventional .remarq dir.\n // NEVER write a wildcard .gitignore into an arbitrary user directory.\n if (basename(dir) === '.remarq') {\n const gitignore = join(dir, '.gitignore')\n if (!existsSync(gitignore)) writeFileSync(gitignore, '*\\n')\n }\n const tmp = `${this.filePath}.tmp`\n writeFileSync(tmp, JSON.stringify(store, null, 2))\n renameSync(tmp, this.filePath)\n this.rev++\n this.emitter.emit('change')\n }\n}\n","import * as http from 'node:http'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { FileStorageAdapter } from './file-storage-adapter.js'\nimport { isSafeAnnotationId } from './task-folder.js'\n\nconst CORS_HEADERS: Record<string, string> = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'content-type',\n}\n\nconst MAX_BODY_BYTES = 1024 * 1024\n\nfunction json(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { ...CORS_HEADERS, 'content-type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let size = 0\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_BODY_BYTES) {\n reject(new Error('body too large'))\n req.destroy()\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))\n req.on('error', reject)\n })\n}\n\nasync function handle(req: IncomingMessage, res: ServerResponse, storage: FileStorageAdapter): Promise<void> {\n if (req.method === 'OPTIONS') {\n res.writeHead(204, CORS_HEADERS)\n res.end()\n return\n }\n\n const pathname = new URL(req.url ?? '/', 'http://localhost').pathname\n const annMatch = pathname.match(/^\\/annotations\\/([^/]+)$/)\n\n try {\n if (req.method === 'GET' && pathname === '/store') {\n // Capture rev before the await, not after: a concurrent mutation between\n // load() and reading storage.rev would pair a newer rev with the older\n // content this response body carries. Under-reporting is safe (the\n // client's next poll re-diffs); over-reporting is not.\n const rev = storage.rev\n const store = (await storage.load()) ?? { version: 1 as const, annotations: [] }\n json(res, 200, { rev, store })\n return\n }\n\n if (req.method === 'PUT' && annMatch) {\n const id = decodeURIComponent(annMatch[1])\n if (!isSafeAnnotationId(id)) {\n json(res, 400, { error: 'invalid annotation id' })\n return\n }\n let annotation: { id?: unknown }\n try {\n annotation = JSON.parse(await readBody(req))\n } catch {\n json(res, 400, { error: 'invalid JSON body' })\n return\n }\n if (!annotation || annotation.id !== id) {\n json(res, 400, { error: 'annotation.id must match the URL id' })\n return\n }\n // The store is trusted local input from the widget; no schema validation.\n await storage.save(annotation as never)\n json(res, 200, { rev: storage.rev })\n return\n }\n\n if (req.method === 'DELETE' && annMatch) {\n const id = decodeURIComponent(annMatch[1])\n if (!isSafeAnnotationId(id)) {\n json(res, 400, { error: 'invalid annotation id' })\n return\n }\n await storage.remove(id)\n json(res, 200, { rev: storage.rev })\n return\n }\n\n if (req.method === 'DELETE' && pathname === '/annotations') {\n await storage.clear()\n json(res, 200, { rev: storage.rev })\n return\n }\n\n json(res, 404, { error: 'not found' })\n } catch (err) {\n json(res, 500, { error: err instanceof Error ? err.message : String(err) })\n }\n}\n\n/** Starts the widget-facing endpoint on 127.0.0.1:port. Rejects on bind errors. */\nexport function startHttpServer(storage: FileStorageAdapter, port: number): Promise<http.Server> {\n const server = http.createServer((req, res) => {\n void handle(req, res, storage)\n })\n return new Promise((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, '127.0.0.1', () => resolve(server))\n })\n}\n","import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Annotation, StorageAdapter } from 'web-remarq'\nimport { actionableOnly, generateAgentExport } from 'web-remarq/core'\n\n/** Double-quoted YAML scalar; JSON string escaping is valid YAML. */\nfunction yamlString(value: string): string {\n return JSON.stringify(value)\n}\n\n/**\n * Annotation ids become `<id>.md` filenames under a server-owned directory.\n * Ids normally come from core (filename-safe by construction) but the widget\n * HTTP endpoint accepts arbitrary strings, so both the file projection and\n * the HTTP layer must reject anything that isn't a plain filename segment\n * (no path separators, no leading dot, no traversal).\n */\nexport function isSafeAnnotationId(id: string): boolean {\n return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id)\n}\n\n/**\n * Renders one annotation as a ticket file for .remarq/tasks/.\n * Deterministic: TaskFolder diffs the output against the file on disk\n * to skip no-op rewrites.\n */\nexport function renderTaskFile(annotation: Annotation): string {\n // Reuse core agent-export for source resolution + search hints (same pattern as get_annotation).\n const agent = generateAgentExport([annotation], annotation.viewportBucket).annotations[0]\n const lines: string[] = []\n\n lines.push('---')\n lines.push(`id: ${yamlString(agent.id)}`)\n lines.push(`route: ${yamlString(agent.route)}`)\n lines.push(`status: ${agent.status}`)\n lines.push(`viewportBucket: ${annotation.viewportBucket}`)\n if (annotation.qualityCheck) lines.push(`quality: ${annotation.qualityCheck.score}`)\n lines.push('---', '')\n\n lines.push(`# web-remarq annotation ${agent.id}`, '')\n lines.push('## Comment', '', agent.comment.trim(), '')\n\n lines.push('## Element', '')\n lines.push(`- Tag: \\`${agent.searchHints.tagName}\\``)\n lines.push(`- DOM: \\`${agent.searchHints.domContext}\\``)\n if (agent.source) {\n const component = agent.source.component ? ` (component \\`${agent.source.component}\\`)` : ''\n lines.push(`- Source: \\`${agent.source.file}:${agent.source.line}:${agent.source.column}\\`${component}`)\n }\n if (agent.searchHints.classes.length) {\n lines.push(`- Classes: ${agent.searchHints.classes.map((c) => `\\`${c}\\``).join(' ')}`)\n }\n lines.push('')\n\n if (agent.searchHints.grepQueries.length) {\n lines.push('## Search hints', '')\n for (const q of agent.searchHints.grepQueries) {\n lines.push(`- [${q.confidence}] \\`${q.query}\\` in \\`${q.glob}\\``)\n }\n lines.push('')\n }\n\n const qc = annotation.qualityCheck\n if (qc && qc.score !== 'clear') {\n lines.push('## Quality check', '')\n lines.push(`Verdict: **${qc.score}** - this comment may need designer clarification; if you cannot act on it confidently, dismiss with a reason instead of guessing.`, '')\n for (const issue of qc.issues) lines.push(`- Issue: ${issue}`)\n for (const q of qc.clarifyingQuestions) lines.push(`- Open question: ${q}`)\n if (qc.suggestedRewrite) lines.push(`- Suggested rewrite: ${qc.suggestedRewrite}`)\n lines.push('')\n }\n\n lines.push('## Agent instructions', '')\n lines.push(`1. BEFORE touching code, call the web-remarq MCP tool \\`acknowledge\\` with \\`{ \"id\": ${yamlString(agent.id)} }\\`. If it errors, another agent already owns this task - skip this file.`)\n lines.push('2. Apply the fix described in the comment.')\n lines.push(`3. When the fix is committed to the working tree, call \\`claim_fix\\` with \\`{ \"id\": ${yamlString(agent.id)} }\\`. A human verifies afterwards - never mark anything as done yourself.`)\n lines.push('')\n lines.push('This file is a live projection maintained by the web-remarq MCP server: it updates when the annotation changes and disappears once the annotation is verified or dismissed. Do not edit or delete it.')\n lines.push('')\n\n return lines.join('\\n')\n}\n\n/**\n * Live projection of actionable annotations (pending/in_progress) into a\n * folder of <id>.md ticket files. The folder is server-owned: every *.md in\n * it is managed - stale ones are deleted on sync. Non-md files are ignored.\n */\nexport class TaskFolder {\n private syncing = false\n private dirty = false\n\n constructor(\n private storage: Pick<StorageAdapter, 'load'>,\n private dir: string,\n ) {}\n\n /** Full idempotent resync: folder contents converge to the actionable set. */\n async sync(): Promise<void> {\n const store = await this.storage.load()\n const actionable = actionableOnly(store?.annotations ?? [])\n const desired = new Map<string, string>()\n for (const a of actionable) {\n if (!isSafeAnnotationId(a.id)) {\n console.error(`[web-remarq-mcp] skipping annotation with unsafe id: ${JSON.stringify(a.id)}`)\n continue\n }\n desired.set(`${a.id}.md`, renderTaskFile(a))\n }\n\n mkdirSync(this.dir, { recursive: true })\n for (const entry of readdirSync(this.dir, { withFileTypes: true })) {\n if (!entry.isFile() || !entry.name.endsWith('.md') || desired.has(entry.name)) continue\n try {\n unlinkSync(join(this.dir, entry.name))\n } catch (err) {\n console.error(`[web-remarq-mcp] failed to remove stale task file ${entry.name}:`, err)\n }\n }\n for (const [name, content] of desired) {\n try {\n const path = join(this.dir, name)\n if (existsSync(path) && readFileSync(path, 'utf8') === content) continue\n writeFileSync(path, content)\n } catch (err) {\n console.error(`[web-remarq-mcp] failed to write task file ${name}:`, err)\n }\n }\n }\n\n /** Coalesces change bursts: at most one sync in flight, one more queued. Never throws. */\n schedule(): void {\n this.dirty = true\n void this.run()\n }\n\n private async run(): Promise<void> {\n if (this.syncing) return\n this.syncing = true\n while (this.dirty) {\n this.dirty = false\n try {\n await this.sync()\n } catch (err) {\n console.error('[web-remarq-mcp] task folder sync failed:', err)\n }\n }\n this.syncing = false\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\n/**\n * The \"agent on duty\" dispatcher prompt, exposed via MCP prompts so clients\n * that support them (Claude Code renders it as /mcp__web-remarq__watch)\n * don't need the copy-paste block from the README.\n * Keep the text in sync with the README's \"Parallel mode\" section.\n */\nexport const DUTY_PROMPT =\n 'You are on annotation duty for this project. Designers drop feedback via ' +\n 'the web-remarq MCP server. Run this loop until told to stop: call ' +\n 'watch_annotations (timeoutSeconds: 60); if it times out, call it again. ' +\n 'For EACH annotation it returns, call acknowledge with its id first. Then, ' +\n 'if you can run background subagents, dispatch one that applies the fix to ' +\n 'the project files and calls claim_fix when done - do not fix anything ' +\n 'yourself in the main loop and do not wait for subagents, go straight back ' +\n 'to watch_annotations so new feedback is never missed. Without background ' +\n 'subagents, apply the fix inline after acknowledging, then return to ' +\n 'watch_annotations. If a comment is ambiguous or unactionable, dismiss it ' +\n 'with a reason instead of guessing.'\n\nexport function registerPrompts(server: McpServer): void {\n server.registerPrompt(\n 'watch',\n {\n title: 'Annotation duty (dispatcher loop)',\n description:\n 'Put this agent on annotation duty: loop on watch_annotations, acknowledge each annotation first, hand the fix to a background subagent that calls claim_fix, return to watching immediately.',\n },\n () => ({\n messages: [{ role: 'user' as const, content: { type: 'text' as const, text: DUTY_PROMPT } }],\n }),\n )\n}\n","import { z } from 'zod'\nimport type { Annotation, AnnotationStatus, QualityCheck, StorageAdapter } from 'web-remarq'\nimport { toolError, toolSuccess } from '../errors'\n\nconst STATUS_VALUES = ['draft', 'pending', 'in_progress', 'fixed_unverified', 'verified', 'dismissed'] as const\n\nexport const listAnnotationsInputSchema = z.object({\n route: z.string().optional(),\n status: z.union([z.enum(STATUS_VALUES), z.array(z.enum(STATUS_VALUES))]).optional(),\n viewportBucket: z.number().int().optional(),\n file: z.string().optional(),\n limit: z.number().int().min(1).max(200).optional(),\n})\n\nexport type ListAnnotationsInput = z.infer<typeof listAnnotationsInputSchema>\n\nexport interface ThinAnnotation {\n id: string\n route: string\n comment: string\n status: AnnotationStatus\n viewport: number\n timestamp: number\n source: { file: string; line: number; column: number; component?: string } | null\n quality?: QualityCheck['score']\n}\n\nfunction parseSource(annotation: Annotation): ThinAnnotation['source'] {\n const fp = annotation.fingerprint\n const raw = fp.sourceLocation ?? fp.detectedSource\n if (!raw) return null\n const parts = raw.split(':')\n if (parts.length < 2) return null\n const column = parseInt(parts.pop()!, 10)\n const line = parseInt(parts.pop()!, 10)\n const file = parts.join(':')\n if (!file || isNaN(line)) return null\n const component = fp.componentName ?? fp.detectedComponent ?? undefined\n return { file, line, column: isNaN(column) ? 0 : column, ...(component ? { component } : {}) }\n}\n\nexport function toThin(a: Annotation): ThinAnnotation {\n return {\n id: a.id,\n route: a.route,\n comment: a.comment,\n status: a.status,\n viewport: a.viewportBucket,\n timestamp: a.timestamp,\n source: parseSource(a),\n ...(a.qualityCheck ? { quality: a.qualityCheck.score } : {}),\n }\n}\n\nexport async function handleListAnnotations(input: ListAnnotationsInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const all = store?.annotations ?? []\n\n const statusFilter = Array.isArray(input.status)\n ? new Set(input.status)\n : input.status\n ? new Set([input.status])\n : null\n\n const filtered = all.filter((a) => {\n if (input.route !== undefined && a.route !== input.route) return false\n if (statusFilter && !statusFilter.has(a.status)) return false\n if (input.viewportBucket !== undefined && a.viewportBucket !== input.viewportBucket) return false\n if (input.file !== undefined) {\n const src = a.fingerprint.sourceLocation ?? a.fingerprint.detectedSource ?? ''\n if (!src.includes(input.file)) return false\n }\n return true\n })\n\n const limit = input.limit ?? 50\n const thinned = filtered.slice(0, limit).map(toThin)\n\n return toolSuccess({ annotations: thinned, total: filtered.length })\n}\n","export type ToolErrorCode =\n | 'annotation_not_found'\n | 'invalid_transition'\n | 'storage_error'\n | 'validation_error'\n\nexport interface ToolErrorPayload {\n code: ToolErrorCode\n message: string\n details?: Record<string, unknown>\n}\n\nexport interface ToolErrorResult {\n isError: true\n content: Array<{ type: 'text'; text: string }>\n}\n\nexport function toolError(code: ToolErrorCode, message: string, details?: Record<string, unknown>): ToolErrorResult {\n const payload: ToolErrorPayload = { code, message, details }\n return {\n isError: true,\n content: [{ type: 'text', text: JSON.stringify(payload) }],\n }\n}\n\nexport interface ToolSuccessResult {\n isError?: false\n content: Array<{ type: 'text'; text: string }>\n}\n\nexport function toolSuccess(value: unknown): ToolSuccessResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(value) }],\n }\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { generateAgentExport } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const getAnnotationInputSchema = z.object({\n id: z.string(),\n})\n\nexport type GetAnnotationInput = z.infer<typeof getAnnotationInputSchema>\n\nexport async function handleGetAnnotation(input: GetAnnotationInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n // Reuse core agent-export to build the rich shape (source + searchHints + lifecycle).\n // generateAgentExport takes an array — pass the single annotation, then extract.\n const agentExport = generateAgentExport([annotation], annotation.viewportBucket)\n const agentAnnotation = agentExport.annotations[0]\n\n return toolSuccess(agentAnnotation)\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { transition, InvalidTransitionError } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const acknowledgeInputSchema = z.object({\n id: z.string(),\n})\n\nexport type AcknowledgeInput = z.infer<typeof acknowledgeInputSchema>\n\nexport async function handleAcknowledge(input: AcknowledgeInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n let result\n try {\n result = transition(annotation, 'acknowledge', { actor: 'agent' })\n } catch (err) {\n if (err instanceof InvalidTransitionError) {\n return toolError('invalid_transition', err.message, {\n currentStatus: annotation.status,\n requestedTransition: 'acknowledge',\n })\n }\n throw err\n }\n\n const updated = {\n ...annotation,\n status: result.status,\n lifecycle: [...annotation.lifecycle, result.event],\n }\n\n try {\n await storage.save(updated)\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n return toolSuccess({ ok: true, status: result.status })\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { transition, InvalidTransitionError } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const claimFixInputSchema = z.object({\n id: z.string(),\n})\n\nexport type ClaimFixInput = z.infer<typeof claimFixInputSchema>\n\nexport async function handleClaimFix(input: ClaimFixInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n let result\n try {\n result = transition(annotation, 'claimFix', { actor: 'agent' })\n } catch (err) {\n if (err instanceof InvalidTransitionError) {\n return toolError('invalid_transition', err.message, {\n currentStatus: annotation.status,\n requestedTransition: 'claimFix',\n })\n }\n throw err\n }\n\n const updated = {\n ...annotation,\n status: result.status,\n lifecycle: [...annotation.lifecycle, result.event],\n }\n\n try {\n await storage.save(updated)\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n return toolSuccess({ ok: true, status: result.status })\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { transition, InvalidTransitionError } from 'web-remarq/core'\nimport { toolError, toolSuccess } from '../errors'\n\nexport const dismissInputSchema = z.object({\n id: z.string(),\n reason: z.string().optional(),\n})\n\nexport type DismissInput = z.infer<typeof dismissInputSchema>\n\nexport async function handleDismiss(input: DismissInput, storage: StorageAdapter) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n const annotation = store?.annotations.find((a) => a.id === input.id)\n if (!annotation) {\n return toolError('annotation_not_found', `Annotation ${input.id} not found in this project`)\n }\n\n let result\n try {\n result = transition(annotation, 'dismiss', { actor: 'agent', reason: input.reason })\n } catch (err) {\n if (err instanceof InvalidTransitionError) {\n return toolError('invalid_transition', err.message, {\n currentStatus: annotation.status,\n requestedTransition: 'dismiss',\n })\n }\n throw err\n }\n\n const updated = {\n ...annotation,\n status: result.status,\n lifecycle: [...annotation.lifecycle, result.event],\n }\n\n try {\n await storage.save(updated)\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n return toolSuccess({ ok: true, status: result.status })\n}\n","import { z } from 'zod'\nimport type { StorageAdapter } from 'web-remarq'\nimport { toolError, toolSuccess } from '../errors'\nimport { toThin } from './list-annotations.js'\n\n/** Waits up to timeoutMs for a backend change. Local mode resolves early on\n * mutation events; cloud mode just sleeps a poll interval and returns false. */\nexport type WaitForChange = (timeoutMs: number) => Promise<boolean>\n\nconst DEFAULT_TIMEOUT_SECONDS = 25\n\nexport const watchAnnotationsInputSchema = z.object({\n timeoutSeconds: z.number().int().min(1).max(120).optional(),\n})\n\nexport type WatchAnnotationsInput = z.infer<typeof watchAnnotationsInputSchema>\n\nexport async function handleWatchAnnotations(\n input: WatchAnnotationsInput,\n storage: StorageAdapter,\n waitForChange: WaitForChange,\n) {\n const timeoutMs = (input.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS) * 1000\n const deadline = Date.now() + timeoutMs\n\n for (;;) {\n let store\n try {\n store = await storage.load()\n } catch (err) {\n return toolError('storage_error', err instanceof Error ? err.message : String(err))\n }\n\n const pending = (store?.annotations ?? []).filter((a) => a.status === 'pending')\n if (pending.length > 0) {\n return toolSuccess({ annotations: pending.map(toThin), total: pending.length, timedOut: false })\n }\n\n const remaining = deadline - Date.now()\n if (remaining <= 0) {\n return toolSuccess({ annotations: [], total: 0, timedOut: true })\n }\n\n await waitForChange(remaining)\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { StorageAdapter } from 'web-remarq'\n\nimport { listAnnotationsInputSchema, handleListAnnotations } from './list-annotations.js'\nimport { getAnnotationInputSchema, handleGetAnnotation } from './get-annotation.js'\nimport { acknowledgeInputSchema, handleAcknowledge } from './acknowledge.js'\nimport { claimFixInputSchema, handleClaimFix } from './claim-fix.js'\nimport { dismissInputSchema, handleDismiss } from './dismiss.js'\nimport { watchAnnotationsInputSchema, handleWatchAnnotations, type WaitForChange } from './watch-annotations.js'\n\nexport type { WaitForChange } from './watch-annotations.js'\n\n// Cast helper: our tool results satisfy CallToolResult at runtime; the SDK's\n// inferred type carries an index signature that our narrower types lack.\nfunction cast(p: Promise<{ isError?: boolean; content: Array<{ type: 'text'; text: string }> }>): Promise<CallToolResult> {\n return p as Promise<CallToolResult>\n}\n\nexport function registerTools(\n server: McpServer,\n storage: StorageAdapter,\n opts: { waitForChange: WaitForChange },\n): void {\n server.registerTool(\n 'list_annotations',\n {\n description: 'List annotations in the project with optional filters (route, status, viewport, file). Each item carries a `quality` score (clear | ambiguous | unactionable) when an AI pre-flight check ran. In local mode, actionable annotations (pending / in_progress) are also mirrored as ticket files in .remarq/tasks/.',\n inputSchema: listAnnotationsInputSchema.shape,\n },\n (input) => cast(handleListAnnotations(input, storage)),\n )\n\n server.registerTool(\n 'get_annotation',\n {\n description: 'Get full annotation details including source file:line:col, grep search hints, and the AI quality verdict (`qualityCheck`). If qualityCheck.score is \"ambiguous\" or \"unactionable\", the comment may need designer clarification before fixing — consider dismissing with a reason instead of guessing.',\n inputSchema: getAnnotationInputSchema.shape,\n },\n (input) => cast(handleGetAnnotation(input, storage)),\n )\n\n server.registerTool(\n 'acknowledge',\n {\n description: 'Mark an annotation as in-progress (pending → in_progress).',\n inputSchema: acknowledgeInputSchema.shape,\n },\n (input) => cast(handleAcknowledge(input, storage)),\n )\n\n server.registerTool(\n 'claim_fix',\n {\n description: 'Claim a fix for an annotation (→ fixed_unverified). Human verification still required.',\n inputSchema: claimFixInputSchema.shape,\n },\n (input) => cast(handleClaimFix(input, storage)),\n )\n\n server.registerTool(\n 'dismiss',\n {\n description: 'Dismiss an annotation with an optional reason (terminal state).',\n inputSchema: dismissInputSchema.shape,\n },\n (input) => cast(handleDismiss(input, storage)),\n )\n\n server.registerTool(\n 'watch_annotations',\n {\n description:\n 'Wait for pending annotations (long-poll). Returns immediately if pending annotations exist; otherwise blocks until one appears or timeoutSeconds (default 25) elapses, then returns {\"annotations\": [], \"timedOut\": true}. Call this in a loop to continuously pick up designer feedback. If your environment can run background subagents (e.g. a Task tool), act as a dispatcher: for each returned annotation call acknowledge first (so it stops being redelivered), hand the fix to a background subagent that will claim_fix when done, and return to watch_annotations immediately instead of fixing inline - new feedback must never wait on a fix in progress. Without subagents, acknowledge each annotation before you start fixing it.',\n inputSchema: watchAnnotationsInputSchema.shape,\n },\n (input) => cast(handleWatchAnnotations(input, storage, opts.waitForChange)),\n )\n}\n"],"mappings":";AAAA,SAAS,WAAAA,UAAS,QAAAC,aAAY;AAC9B,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;;;ACa9B,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,SAAS,SAAS,KAAwB,KAAqB;AAC7D,QAAM,IAAI,IAAI,GAAG;AACjB,MAAI,CAAC,KAAK,EAAE,KAAK,MAAM,IAAI;AACzB,UAAM,IAAI,YAAY,6BAA6B,GAAG,EAAE;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,IAAM,eAAe;AACrB,IAAM,oBAAoB;AAEnB,SAAS,SAAS,KAAmC;AAC1D,QAAM,iBAAiB;AAAA,IACrB,IAAI,sBAAsB,IAAI,uBAAuB,IAAI;AAAA,EAC3D;AAEA,MAAI,gBAAgB;AAClB,UAAM,aAAa,SAAS,KAAK,oBAAoB;AACrD,UAAM,cAAc,SAAS,KAAK,qBAAqB;AACvD,UAAM,kBAAkB,SAAS,KAAK,0BAA0B;AAEhE,QAAI,CAAC,WAAW,WAAW,KAAK,GAAG;AACjC,YAAM,IAAI,YAAY,yFAAyF;AAAA,IACjH;AACA,QAAI,CAAC,YAAY,WAAW,UAAU,GAAG;AACvC,YAAM,IAAI,YAAY,8CAA8C;AAAA,IACtE;AAEA,WAAO,EAAE,MAAM,SAAS,YAAY,aAAa,gBAAgB;AAAA,EACnE;AAEA,QAAM,UAAU,IAAI,eAAe,OAAO,YAAY;AACtD,QAAM,OAAO,OAAO,OAAO;AAC3B,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OAAO;AACvD,UAAM,IAAI,YAAY,4DAA4D,OAAO,GAAG;AAAA,EAC9F;AAEA,SAAO,EAAE,MAAM,SAAS,MAAM,UAAU,IAAI,oBAAoB,kBAAkB;AACpF;;;AC5DA,SAAS,0BAA0B;AAI5B,SAAS,cAAc,QAAqC;AACjE,SAAO,mBAAmB;AAAA,IACxB,YAAY,OAAO;AAAA,IACnB,aAAa,OAAO;AAAA,IACpB,iBAAiB,OAAO;AAAA,IACxB,SAAS;AAAA,EACX,CAAC;AACH;;;ACXA,SAAS,oBAAoB;AAC7B,SAAS,YAAY,WAAW,cAAc,YAAY,qBAAqB;AAC/E,SAAS,UAAU,SAAS,YAAY;AAQjC,IAAM,qBAAN,MAAmD;AAAA,EAOxD,YAAoB,UAAkB;AAAlB;AALpB;AAAA,eAAM;AACN,SAAQ,UAAU,IAAI,aAAa;AAEnC;AAAA,SAAQ,QAAuB,QAAQ,QAAQ;AAG7C,SAAK,QAAQ,gBAAgB,CAAC;AAAA,EAChC;AAAA,EAEA,MAAM,OAAwC;AAC5C,QAAI,CAAC,WAAW,KAAK,QAAQ,EAAG,QAAO;AACvC,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,aAAa,KAAK,UAAU,MAAM,CAAC;AAAA,IACzD,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,YAAM,IAAI,MAAM,kCAAkC,KAAK,QAAQ,KAAK,OAAO,EAAE;AAAA,IAC/E;AACA,UAAM,QAAQ;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa,MAAM,QAAQ,MAAM,WAAW,IAAK,MAAM,cAA+B,CAAC;AAAA,IACzF;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,YAAuC;AAChD,WAAO,KAAK,QAAQ,YAAY;AAC9B,YAAM,QAAS,MAAM,KAAK,KAAK,KAAM,EAAE,SAAS,GAAY,aAAa,CAAC,EAAE;AAC5E,YAAM,MAAM,MAAM,YAAY,UAAU,CAAC,MAAM,EAAE,OAAO,WAAW,EAAE;AACrE,UAAI,QAAQ,GAAI,OAAM,YAAY,KAAK,UAAU;AAAA,UAC5C,OAAM,YAAY,GAAG,IAAI;AAC9B,WAAK,QAAQ,KAAK;AAAA,IACpB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,WAAO,KAAK,QAAQ,YAAY;AAC9B,YAAM,QAAS,MAAM,KAAK,KAAK,KAAM,EAAE,SAAS,GAAY,aAAa,CAAC,EAAE;AAC5E,YAAM,cAAc,MAAM,YAAY,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC/D,WAAK,QAAQ,KAAK;AAAA,IACpB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAuB;AAC3B,WAAO,KAAK,QAAQ,YAAY;AAC9B,WAAK,QAAQ,EAAE,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,QAAQ,IAAwC;AACtD,UAAM,SAAS,KAAK,MAAM,KAAK,EAAE;AAGjC,SAAK,QAAQ,OAAO,MAAM,MAAM,MAAS;AACzC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAc,WAAqC;AACjD,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,WAAW,MAAY;AAC3B,qBAAa,KAAK;AAClB,gBAAQ,IAAI;AAAA,MACd;AACA,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,QAAQ,IAAI,UAAU,QAAQ;AACnC,gBAAQ,KAAK;AAAA,MACf,GAAG,SAAS;AACZ,WAAK,QAAQ,KAAK,UAAU,QAAQ;AAAA,IACtC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,SAAS,UAA4B;AACnC,SAAK,QAAQ,GAAG,UAAU,QAAQ;AAAA,EACpC;AAAA,EAEQ,QAAQ,OAA8B;AAC5C,UAAM,MAAM,QAAQ,KAAK,QAAQ;AACjC,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAGlC,QAAI,SAAS,GAAG,MAAM,WAAW;AAC/B,YAAM,YAAY,KAAK,KAAK,YAAY;AACxC,UAAI,CAAC,WAAW,SAAS,EAAG,eAAc,WAAW,KAAK;AAAA,IAC5D;AACA,UAAM,MAAM,GAAG,KAAK,QAAQ;AAC5B,kBAAc,KAAK,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACjD,eAAW,KAAK,KAAK,QAAQ;AAC7B,SAAK;AACL,SAAK,QAAQ,KAAK,QAAQ;AAAA,EAC5B;AACF;;;ACzGA,YAAY,UAAU;;;ACAtB,SAAS,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,aAAa,YAAY,iBAAAC,sBAAqB;AAC5F,SAAS,QAAAC,aAAY;AAErB,SAAS,gBAAgB,2BAA2B;AAGpD,SAAS,WAAW,OAAuB;AACzC,SAAO,KAAK,UAAU,KAAK;AAC7B;AASO,SAAS,mBAAmB,IAAqB;AACtD,SAAO,+BAA+B,KAAK,EAAE;AAC/C;AAOO,SAAS,eAAe,YAAgC;AAE7D,QAAM,QAAQ,oBAAoB,CAAC,UAAU,GAAG,WAAW,cAAc,EAAE,YAAY,CAAC;AACxF,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,OAAO,WAAW,MAAM,EAAE,CAAC,EAAE;AACxC,QAAM,KAAK,UAAU,WAAW,MAAM,KAAK,CAAC,EAAE;AAC9C,QAAM,KAAK,WAAW,MAAM,MAAM,EAAE;AACpC,QAAM,KAAK,mBAAmB,WAAW,cAAc,EAAE;AACzD,MAAI,WAAW,aAAc,OAAM,KAAK,YAAY,WAAW,aAAa,KAAK,EAAE;AACnF,QAAM,KAAK,OAAO,EAAE;AAEpB,QAAM,KAAK,2BAA2B,MAAM,EAAE,IAAI,EAAE;AACpD,QAAM,KAAK,cAAc,IAAI,MAAM,QAAQ,KAAK,GAAG,EAAE;AAErD,QAAM,KAAK,cAAc,EAAE;AAC3B,QAAM,KAAK,YAAY,MAAM,YAAY,OAAO,IAAI;AACpD,QAAM,KAAK,YAAY,MAAM,YAAY,UAAU,IAAI;AACvD,MAAI,MAAM,QAAQ;AAChB,UAAM,YAAY,MAAM,OAAO,YAAY,iBAAiB,MAAM,OAAO,SAAS,QAAQ;AAC1F,UAAM,KAAK,eAAe,MAAM,OAAO,IAAI,IAAI,MAAM,OAAO,IAAI,IAAI,MAAM,OAAO,MAAM,KAAK,SAAS,EAAE;AAAA,EACzG;AACA,MAAI,MAAM,YAAY,QAAQ,QAAQ;AACpC,UAAM,KAAK,cAAc,MAAM,YAAY,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE;AAAA,EACvF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,MAAM,YAAY,YAAY,QAAQ;AACxC,UAAM,KAAK,mBAAmB,EAAE;AAChC,eAAW,KAAK,MAAM,YAAY,aAAa;AAC7C,YAAM,KAAK,MAAM,EAAE,UAAU,OAAO,EAAE,KAAK,WAAW,EAAE,IAAI,IAAI;AAAA,IAClE;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,WAAW;AACtB,MAAI,MAAM,GAAG,UAAU,SAAS;AAC9B,UAAM,KAAK,oBAAoB,EAAE;AACjC,UAAM,KAAK,cAAc,GAAG,KAAK,sIAAsI,EAAE;AACzK,eAAW,SAAS,GAAG,OAAQ,OAAM,KAAK,YAAY,KAAK,EAAE;AAC7D,eAAW,KAAK,GAAG,oBAAqB,OAAM,KAAK,oBAAoB,CAAC,EAAE;AAC1E,QAAI,GAAG,iBAAkB,OAAM,KAAK,wBAAwB,GAAG,gBAAgB,EAAE;AACjF,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,yBAAyB,EAAE;AACtC,QAAM,KAAK,wFAAwF,WAAW,MAAM,EAAE,CAAC,4EAA4E;AACnM,QAAM,KAAK,4CAA4C;AACvD,QAAM,KAAK,uFAAuF,WAAW,MAAM,EAAE,CAAC,2EAA2E;AACjM,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,uMAAuM;AAClN,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;AAOO,IAAM,aAAN,MAAiB;AAAA,EAItB,YACU,SACA,KACR;AAFQ;AACA;AALV,SAAQ,UAAU;AAClB,SAAQ,QAAQ;AAAA,EAKb;AAAA;AAAA,EAGH,MAAM,OAAsB;AAC1B,UAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK;AACtC,UAAM,aAAa,eAAe,OAAO,eAAe,CAAC,CAAC;AAC1D,UAAM,UAAU,oBAAI,IAAoB;AACxC,eAAW,KAAK,YAAY;AAC1B,UAAI,CAAC,mBAAmB,EAAE,EAAE,GAAG;AAC7B,gBAAQ,MAAM,wDAAwD,KAAK,UAAU,EAAE,EAAE,CAAC,EAAE;AAC5F;AAAA,MACF;AACA,cAAQ,IAAI,GAAG,EAAE,EAAE,OAAO,eAAe,CAAC,CAAC;AAAA,IAC7C;AAEA,IAAAH,WAAU,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC,eAAW,SAAS,YAAY,KAAK,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAClE,UAAI,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,KAAK,SAAS,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,EAAG;AAC/E,UAAI;AACF,mBAAWG,MAAK,KAAK,KAAK,MAAM,IAAI,CAAC;AAAA,MACvC,SAAS,KAAK;AACZ,gBAAQ,MAAM,qDAAqD,MAAM,IAAI,KAAK,GAAG;AAAA,MACvF;AAAA,IACF;AACA,eAAW,CAAC,MAAM,OAAO,KAAK,SAAS;AACrC,UAAI;AACF,cAAM,OAAOA,MAAK,KAAK,KAAK,IAAI;AAChC,YAAIJ,YAAW,IAAI,KAAKE,cAAa,MAAM,MAAM,MAAM,QAAS;AAChE,QAAAC,eAAc,MAAM,OAAO;AAAA,MAC7B,SAAS,KAAK;AACZ,gBAAQ,MAAM,8CAA8C,IAAI,KAAK,GAAG;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,WAAiB;AACf,SAAK,QAAQ;AACb,SAAK,KAAK,IAAI;AAAA,EAChB;AAAA,EAEA,MAAc,MAAqB;AACjC,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,WAAO,KAAK,OAAO;AACjB,WAAK,QAAQ;AACb,UAAI;AACF,cAAM,KAAK,KAAK;AAAA,MAClB,SAAS,KAAK;AACZ,gBAAQ,MAAM,6CAA6C,GAAG;AAAA,MAChE;AAAA,IACF;AACA,SAAK,UAAU;AAAA,EACjB;AACF;;;ADhJA,IAAM,eAAuC;AAAA,EAC3C,+BAA+B;AAAA,EAC/B,gCAAgC;AAAA,EAChC,gCAAgC;AAClC;AAEA,IAAM,iBAAiB,OAAO;AAE9B,SAAS,KAAK,KAAqB,QAAgB,MAAqB;AACtE,MAAI,UAAU,QAAQ,EAAE,GAAG,cAAc,gBAAgB,mBAAmB,CAAC;AAC7E,MAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC9B;AAEA,SAAS,SAAS,KAAuC;AACvD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,UAAM,SAAmB,CAAC;AAC1B,QAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,cAAQ,MAAM;AACd,UAAI,OAAO,gBAAgB;AACzB,eAAO,IAAI,MAAM,gBAAgB,CAAC;AAClC,YAAI,QAAQ;AACZ;AAAA,MACF;AACA,aAAO,KAAK,KAAK;AAAA,IACnB,CAAC;AACD,QAAI,GAAG,OAAO,MAAM,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC,CAAC;AACnE,QAAI,GAAG,SAAS,MAAM;AAAA,EACxB,CAAC;AACH;AAEA,eAAe,OAAO,KAAsB,KAAqB,SAA4C;AAC3G,MAAI,IAAI,WAAW,WAAW;AAC5B,QAAI,UAAU,KAAK,YAAY;AAC/B,QAAI,IAAI;AACR;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB,EAAE;AAC7D,QAAM,WAAW,SAAS,MAAM,0BAA0B;AAE1D,MAAI;AACF,QAAI,IAAI,WAAW,SAAS,aAAa,UAAU;AAKjD,YAAM,MAAM,QAAQ;AACpB,YAAM,QAAS,MAAM,QAAQ,KAAK,KAAM,EAAE,SAAS,GAAY,aAAa,CAAC,EAAE;AAC/E,WAAK,KAAK,KAAK,EAAE,KAAK,MAAM,CAAC;AAC7B;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,SAAS,UAAU;AACpC,YAAM,KAAK,mBAAmB,SAAS,CAAC,CAAC;AACzC,UAAI,CAAC,mBAAmB,EAAE,GAAG;AAC3B,aAAK,KAAK,KAAK,EAAE,OAAO,wBAAwB,CAAC;AACjD;AAAA,MACF;AACA,UAAI;AACJ,UAAI;AACF,qBAAa,KAAK,MAAM,MAAM,SAAS,GAAG,CAAC;AAAA,MAC7C,QAAQ;AACN,aAAK,KAAK,KAAK,EAAE,OAAO,oBAAoB,CAAC;AAC7C;AAAA,MACF;AACA,UAAI,CAAC,cAAc,WAAW,OAAO,IAAI;AACvC,aAAK,KAAK,KAAK,EAAE,OAAO,sCAAsC,CAAC;AAC/D;AAAA,MACF;AAEA,YAAM,QAAQ,KAAK,UAAmB;AACtC,WAAK,KAAK,KAAK,EAAE,KAAK,QAAQ,IAAI,CAAC;AACnC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,YAAY,UAAU;AACvC,YAAM,KAAK,mBAAmB,SAAS,CAAC,CAAC;AACzC,UAAI,CAAC,mBAAmB,EAAE,GAAG;AAC3B,aAAK,KAAK,KAAK,EAAE,OAAO,wBAAwB,CAAC;AACjD;AAAA,MACF;AACA,YAAM,QAAQ,OAAO,EAAE;AACvB,WAAK,KAAK,KAAK,EAAE,KAAK,QAAQ,IAAI,CAAC;AACnC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,YAAY,aAAa,gBAAgB;AAC1D,YAAM,QAAQ,MAAM;AACpB,WAAK,KAAK,KAAK,EAAE,KAAK,QAAQ,IAAI,CAAC;AACnC;AAAA,IACF;AAEA,SAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AAAA,EACvC,SAAS,KAAK;AACZ,SAAK,KAAK,KAAK,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC;AAAA,EAC5E;AACF;AAGO,SAAS,gBAAgB,SAA6B,MAAoC;AAC/F,QAAM,SAAc,kBAAa,CAAC,KAAK,QAAQ;AAC7C,SAAK,OAAO,KAAK,KAAK,OAAO;AAAA,EAC/B,CAAC;AACD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAO,KAAK,SAAS,MAAM;AAC3B,WAAO,OAAO,MAAM,aAAa,MAAM,QAAQ,MAAM,CAAC;AAAA,EACxD,CAAC;AACH;;;AEzGO,IAAM,cACX;AAYK,SAAS,gBAAgB,QAAyB;AACvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,IACA,OAAO;AAAA,MACL,UAAU,CAAC,EAAE,MAAM,QAAiB,SAAS,EAAE,MAAM,QAAiB,MAAM,YAAY,EAAE,CAAC;AAAA,IAC7F;AAAA,EACF;AACF;;;ACjCA,SAAS,SAAS;;;ACiBX,SAAS,UAAU,MAAqB,SAAiB,SAAoD;AAClH,QAAM,UAA4B,EAAE,MAAM,SAAS,QAAQ;AAC3D,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,OAAO,EAAE,CAAC;AAAA,EAC3D;AACF;AAOO,SAAS,YAAY,OAAmC;AAC7D,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,KAAK,EAAE,CAAC;AAAA,EACzD;AACF;;;AD9BA,IAAM,gBAAgB,CAAC,SAAS,WAAW,eAAe,oBAAoB,YAAY,WAAW;AAE9F,IAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,QAAQ,EAAE,MAAM,CAAC,EAAE,KAAK,aAAa,GAAG,EAAE,MAAM,EAAE,KAAK,aAAa,CAAC,CAAC,CAAC,EAAE,SAAS;AAAA,EAClF,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAC1C,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AACnD,CAAC;AAeD,SAAS,YAAY,YAAkD;AACrE,QAAM,KAAK,WAAW;AACtB,QAAM,MAAM,GAAG,kBAAkB,GAAG;AACpC,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,SAAS,SAAS,MAAM,IAAI,GAAI,EAAE;AACxC,QAAM,OAAO,SAAS,MAAM,IAAI,GAAI,EAAE;AACtC,QAAM,OAAO,MAAM,KAAK,GAAG;AAC3B,MAAI,CAAC,QAAQ,MAAM,IAAI,EAAG,QAAO;AACjC,QAAM,YAAY,GAAG,iBAAiB,GAAG,qBAAqB;AAC9D,SAAO,EAAE,MAAM,MAAM,QAAQ,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC,EAAG;AAC/F;AAEO,SAAS,OAAO,GAA+B;AACpD,SAAO;AAAA,IACL,IAAI,EAAE;AAAA,IACN,OAAO,EAAE;AAAA,IACT,SAAS,EAAE;AAAA,IACX,QAAQ,EAAE;AAAA,IACV,UAAU,EAAE;AAAA,IACZ,WAAW,EAAE;AAAA,IACb,QAAQ,YAAY,CAAC;AAAA,IACrB,GAAI,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,MAAM,IAAI,CAAC;AAAA,EAC5D;AACF;AAEA,eAAsB,sBAAsB,OAA6B,SAAyB;AAChG,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,QAAQ,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AACA,QAAM,MAAM,OAAO,eAAe,CAAC;AAEnC,QAAM,eAAe,MAAM,QAAQ,MAAM,MAAM,IAC3C,IAAI,IAAI,MAAM,MAAM,IACpB,MAAM,SACN,oBAAI,IAAI,CAAC,MAAM,MAAM,CAAC,IACtB;AAEJ,QAAM,WAAW,IAAI,OAAO,CAAC,MAAM;AACjC,QAAI,MAAM,UAAU,UAAa,EAAE,UAAU,MAAM,MAAO,QAAO;AACjE,QAAI,gBAAgB,CAAC,aAAa,IAAI,EAAE,MAAM,EAAG,QAAO;AACxD,QAAI,MAAM,mBAAmB,UAAa,EAAE,mBAAmB,MAAM,eAAgB,QAAO;AAC5F,QAAI,MAAM,SAAS,QAAW;AAC5B,YAAM,MAAM,EAAE,YAAY,kBAAkB,EAAE,YAAY,kBAAkB;AAC5E,UAAI,CAAC,IAAI,SAAS,MAAM,IAAI,EAAG,QAAO;AAAA,IACxC;AACA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,UAAU,SAAS,MAAM,GAAG,KAAK,EAAE,IAAI,MAAM;AAEnD,SAAO,YAAY,EAAE,aAAa,SAAS,OAAO,SAAS,OAAO,CAAC;AACrE;;;AEpFA,SAAS,KAAAE,UAAS;AAElB,SAAS,uBAAAC,4BAA2B;AAG7B,IAAM,2BAA2BC,GAAE,OAAO;AAAA,EAC/C,IAAIA,GAAE,OAAO;AACf,CAAC;AAID,eAAsB,oBAAoB,OAA2B,SAAyB;AAC5F,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,QAAQ,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AACA,QAAM,aAAa,OAAO,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AACnE,MAAI,CAAC,YAAY;AACf,WAAO,UAAU,wBAAwB,cAAc,MAAM,EAAE,4BAA4B;AAAA,EAC7F;AAIA,QAAM,cAAcC,qBAAoB,CAAC,UAAU,GAAG,WAAW,cAAc;AAC/E,QAAM,kBAAkB,YAAY,YAAY,CAAC;AAEjD,SAAO,YAAY,eAAe;AACpC;;;AC7BA,SAAS,KAAAC,UAAS;AAElB,SAAS,YAAY,8BAA8B;AAG5C,IAAM,yBAAyBC,GAAE,OAAO;AAAA,EAC7C,IAAIA,GAAE,OAAO;AACf,CAAC;AAID,eAAsB,kBAAkB,OAAyB,SAAyB;AACxF,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,QAAQ,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AACA,QAAM,aAAa,OAAO,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AACnE,MAAI,CAAC,YAAY;AACf,WAAO,UAAU,wBAAwB,cAAc,MAAM,EAAE,4BAA4B;AAAA,EAC7F;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,WAAW,YAAY,eAAe,EAAE,OAAO,QAAQ,CAAC;AAAA,EACnE,SAAS,KAAK;AACZ,QAAI,eAAe,wBAAwB;AACzC,aAAO,UAAU,sBAAsB,IAAI,SAAS;AAAA,QAClD,eAAe,WAAW;AAAA,QAC1B,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AAEA,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,QAAQ,OAAO;AAAA,IACf,WAAW,CAAC,GAAG,WAAW,WAAW,OAAO,KAAK;AAAA,EACnD;AAEA,MAAI;AACF,UAAM,QAAQ,KAAK,OAAO;AAAA,EAC5B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AAEA,SAAO,YAAY,EAAE,IAAI,MAAM,QAAQ,OAAO,OAAO,CAAC;AACxD;;;ACjDA,SAAS,KAAAC,UAAS;AAElB,SAAS,cAAAC,aAAY,0BAAAC,+BAA8B;AAG5C,IAAM,sBAAsBC,GAAE,OAAO;AAAA,EAC1C,IAAIA,GAAE,OAAO;AACf,CAAC;AAID,eAAsB,eAAe,OAAsB,SAAyB;AAClF,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,QAAQ,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AACA,QAAM,aAAa,OAAO,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AACnE,MAAI,CAAC,YAAY;AACf,WAAO,UAAU,wBAAwB,cAAc,MAAM,EAAE,4BAA4B;AAAA,EAC7F;AAEA,MAAI;AACJ,MAAI;AACF,aAASC,YAAW,YAAY,YAAY,EAAE,OAAO,QAAQ,CAAC;AAAA,EAChE,SAAS,KAAK;AACZ,QAAI,eAAeC,yBAAwB;AACzC,aAAO,UAAU,sBAAsB,IAAI,SAAS;AAAA,QAClD,eAAe,WAAW;AAAA,QAC1B,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AAEA,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,QAAQ,OAAO;AAAA,IACf,WAAW,CAAC,GAAG,WAAW,WAAW,OAAO,KAAK;AAAA,EACnD;AAEA,MAAI;AACF,UAAM,QAAQ,KAAK,OAAO;AAAA,EAC5B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AAEA,SAAO,YAAY,EAAE,IAAI,MAAM,QAAQ,OAAO,OAAO,CAAC;AACxD;;;ACjDA,SAAS,KAAAC,UAAS;AAElB,SAAS,cAAAC,aAAY,0BAAAC,+BAA8B;AAG5C,IAAM,qBAAqBC,GAAE,OAAO;AAAA,EACzC,IAAIA,GAAE,OAAO;AAAA,EACb,QAAQA,GAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAID,eAAsB,cAAc,OAAqB,SAAyB;AAChF,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,QAAQ,KAAK;AAAA,EAC7B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AACA,QAAM,aAAa,OAAO,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AACnE,MAAI,CAAC,YAAY;AACf,WAAO,UAAU,wBAAwB,cAAc,MAAM,EAAE,4BAA4B;AAAA,EAC7F;AAEA,MAAI;AACJ,MAAI;AACF,aAASC,YAAW,YAAY,WAAW,EAAE,OAAO,SAAS,QAAQ,MAAM,OAAO,CAAC;AAAA,EACrF,SAAS,KAAK;AACZ,QAAI,eAAeC,yBAAwB;AACzC,aAAO,UAAU,sBAAsB,IAAI,SAAS;AAAA,QAClD,eAAe,WAAW;AAAA,QAC1B,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AAEA,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,QAAQ,OAAO;AAAA,IACf,WAAW,CAAC,GAAG,WAAW,WAAW,OAAO,KAAK;AAAA,EACnD;AAEA,MAAI;AACF,UAAM,QAAQ,KAAK,OAAO;AAAA,EAC5B,SAAS,KAAK;AACZ,WAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACpF;AAEA,SAAO,YAAY,EAAE,IAAI,MAAM,QAAQ,OAAO,OAAO,CAAC;AACxD;;;AClDA,SAAS,KAAAC,UAAS;AASlB,IAAM,0BAA0B;AAEzB,IAAM,8BAA8BC,GAAE,OAAO;AAAA,EAClD,gBAAgBA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAC5D,CAAC;AAID,eAAsB,uBACpB,OACA,SACA,eACA;AACA,QAAM,aAAa,MAAM,kBAAkB,2BAA2B;AACtE,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,aAAS;AACP,QAAI;AACJ,QAAI;AACF,cAAQ,MAAM,QAAQ,KAAK;AAAA,IAC7B,SAAS,KAAK;AACZ,aAAO,UAAU,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACpF;AAEA,UAAM,WAAW,OAAO,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS;AAC/E,QAAI,QAAQ,SAAS,GAAG;AACtB,aAAO,YAAY,EAAE,aAAa,QAAQ,IAAI,MAAM,GAAG,OAAO,QAAQ,QAAQ,UAAU,MAAM,CAAC;AAAA,IACjG;AAEA,UAAM,YAAY,WAAW,KAAK,IAAI;AACtC,QAAI,aAAa,GAAG;AAClB,aAAO,YAAY,EAAE,aAAa,CAAC,GAAG,OAAO,GAAG,UAAU,KAAK,CAAC;AAAA,IAClE;AAEA,UAAM,cAAc,SAAS;AAAA,EAC/B;AACF;;;AC9BA,SAAS,KAAK,GAA4G;AACxH,SAAO;AACT;AAEO,SAAS,cACd,QACA,SACA,MACM;AACN,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,2BAA2B;AAAA,IAC1C;AAAA,IACA,CAAC,UAAU,KAAK,sBAAsB,OAAO,OAAO,CAAC;AAAA,EACvD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,yBAAyB;AAAA,IACxC;AAAA,IACA,CAAC,UAAU,KAAK,oBAAoB,OAAO,OAAO,CAAC;AAAA,EACrD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,uBAAuB;AAAA,IACtC;AAAA,IACA,CAAC,UAAU,KAAK,kBAAkB,OAAO,OAAO,CAAC;AAAA,EACnD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,oBAAoB;AAAA,IACnC;AAAA,IACA,CAAC,UAAU,KAAK,eAAe,OAAO,OAAO,CAAC;AAAA,EAChD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,mBAAmB;AAAA,IAClC;AAAA,IACA,CAAC,UAAU,KAAK,cAAc,OAAO,OAAO,CAAC;AAAA,EAC/C;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MACF,aAAa,4BAA4B;AAAA,IAC3C;AAAA,IACA,CAAC,UAAU,KAAK,uBAAuB,OAAO,SAAS,KAAK,aAAa,CAAC;AAAA,EAC5E;AACF;;;AdlEA,IAAM,gBAAgB;AAEtB,eAAe,OAAsB;AACnC,MAAI;AACJ,MAAI;AACF,aAAS,SAAS,QAAQ,GAAG;AAAA,EAC/B,SAAS,KAAK;AACZ,QAAI,eAAe,aAAa;AAC9B,cAAQ,MAAM,kCAAkC,IAAI,OAAO,EAAE;AAC7D,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM;AAAA,EACR;AAEA,MAAI;AACJ,MAAI;AAEJ,MAAI,OAAO,SAAS,SAAS;AAC3B,UAAM,UAAU,IAAI,mBAAmB,OAAO,QAAQ;AACtD,UAAM,WAAWC,MAAKC,SAAQ,OAAO,QAAQ,GAAG,OAAO;AACvD,UAAM,aAAa,IAAI,WAAW,SAAS,QAAQ;AACnD,YAAQ,SAAS,MAAM,WAAW,SAAS,CAAC;AAC5C,eAAW,SAAS;AACpB,UAAM,gBAAgB,SAAS,OAAO,IAAI;AAC1C,YAAQ;AAAA,MACN,uEAAkE,OAAO,IAAI,WAAW,OAAO,QAAQ,WAAW,QAAQ;AAAA,IAC5H;AACA,cAAU;AACV,oBAAgB,CAAC,OAAO,QAAQ,cAAc,EAAE;AAAA,EAClD,OAAO;AACL,cAAU,cAAc,MAAM;AAC9B,oBAAgB,CAAC,OACf,IAAI,QAAQ,CAAC,YAAY,WAAW,MAAM,QAAQ,KAAK,GAAG,KAAK,IAAI,IAAI,aAAa,CAAC,CAAC;AAAA,EAC1F;AAEA,QAAM,SAAS,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAED,gBAAc,QAAQ,SAAS,EAAE,cAAc,CAAC;AAChD,kBAAgB,MAAM;AAEtB,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAChC;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,2BAA2B,GAAG;AAC5C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["dirname","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","z","generateAgentExport","z","generateAgentExport","z","z","z","transition","InvalidTransitionError","z","transition","InvalidTransitionError","z","transition","InvalidTransitionError","z","transition","InvalidTransitionError","z","z","join","dirname"]}
|
package/package.json
CHANGED