@0x1f320.sh/why-did-you-render-mcp 1.0.0-dev.7 → 1.0.0-dev.8
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/dist/server/index.js +90 -36
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -123,11 +123,13 @@ function toResult(stored) {
|
|
|
123
123
|
//#endregion
|
|
124
124
|
//#region src/server/store/render-store.ts
|
|
125
125
|
const FLUSH_DELAY_MS = 200;
|
|
126
|
+
const NOCOMMIT = "nocommit";
|
|
126
127
|
var RenderStore = class {
|
|
127
128
|
dir;
|
|
128
129
|
buffers = /* @__PURE__ */ new Map();
|
|
129
130
|
timers = /* @__PURE__ */ new Map();
|
|
130
131
|
dicts = /* @__PURE__ */ new Map();
|
|
132
|
+
bufferMeta = /* @__PURE__ */ new Map();
|
|
131
133
|
constructor(dir) {
|
|
132
134
|
this.dir = dir ?? join(homedir(), ".wdyr-mcp", "renders");
|
|
133
135
|
mkdirSync(this.dir, { recursive: true });
|
|
@@ -138,46 +140,53 @@ var RenderStore = class {
|
|
|
138
140
|
projectId,
|
|
139
141
|
...commitId != null && { commitId }
|
|
140
142
|
};
|
|
141
|
-
|
|
143
|
+
const bk = this.bufferKey(projectId, commitId);
|
|
144
|
+
let buf = this.buffers.get(bk);
|
|
142
145
|
if (!buf) {
|
|
143
146
|
buf = [];
|
|
144
|
-
this.buffers.set(
|
|
147
|
+
this.buffers.set(bk, buf);
|
|
148
|
+
this.bufferMeta.set(bk, {
|
|
149
|
+
projectId,
|
|
150
|
+
commitId
|
|
151
|
+
});
|
|
145
152
|
}
|
|
146
153
|
buf.push(stored);
|
|
147
|
-
const existing = this.timers.get(
|
|
154
|
+
const existing = this.timers.get(bk);
|
|
148
155
|
if (existing) clearTimeout(existing);
|
|
149
|
-
this.timers.set(
|
|
150
|
-
this.flushAsync(projectId).catch((err) => console.error(`[wdyr-mcp] flush error for ${
|
|
156
|
+
this.timers.set(bk, setTimeout(() => {
|
|
157
|
+
this.flushAsync(projectId, commitId).catch((err) => console.error(`[wdyr-mcp] flush error for ${bk}:`, err));
|
|
151
158
|
}, FLUSH_DELAY_MS));
|
|
152
159
|
}
|
|
153
|
-
async flushAsync(projectId) {
|
|
160
|
+
async flushAsync(projectId, commitId) {
|
|
154
161
|
await ensureReady();
|
|
155
|
-
|
|
156
|
-
else for (const id of this.buffers.keys()) this.flushProject(id);
|
|
162
|
+
this.flush(projectId, commitId);
|
|
157
163
|
}
|
|
158
|
-
flush(projectId) {
|
|
159
|
-
if (projectId) this.
|
|
160
|
-
else for (const
|
|
164
|
+
flush(projectId, commitId) {
|
|
165
|
+
if (projectId != null && commitId !== void 0) this.flushBuffer(this.bufferKey(projectId, commitId));
|
|
166
|
+
else if (projectId != null) for (const bk of this.bufferKeysForProject(projectId)) this.flushBuffer(bk);
|
|
167
|
+
else for (const bk of [...this.buffers.keys()]) this.flushBuffer(bk);
|
|
161
168
|
}
|
|
162
|
-
|
|
163
|
-
const buf = this.buffers.get(
|
|
169
|
+
flushBuffer(bk) {
|
|
170
|
+
const buf = this.buffers.get(bk);
|
|
164
171
|
if (!buf || buf.length === 0) return;
|
|
165
|
-
|
|
172
|
+
const meta = this.bufferMeta.get(bk);
|
|
173
|
+
if (!meta) return;
|
|
174
|
+
let dict = this.dicts.get(bk);
|
|
166
175
|
if (!dict) {
|
|
167
176
|
dict = {};
|
|
168
|
-
this.dicts.set(
|
|
177
|
+
this.dicts.set(bk, dict);
|
|
169
178
|
}
|
|
170
179
|
const dehydrated = buf.map((r) => dehydrate(r, dict));
|
|
171
|
-
const file = this.
|
|
180
|
+
const file = this.commitFile(meta.projectId, meta.commitId);
|
|
172
181
|
const existingLines = this.readDataLines(file);
|
|
173
182
|
const newLines = dehydrated.map((r) => JSON.stringify(r));
|
|
174
183
|
const allDataLines = [...existingLines, ...newLines];
|
|
175
184
|
writeFileSync(file, `${(Object.keys(dict).length > 0 ? [JSON.stringify({ [DICT_KEY]: dict }), ...allDataLines] : allDataLines).join("\n")}\n`);
|
|
176
185
|
buf.length = 0;
|
|
177
|
-
const timer = this.timers.get(
|
|
186
|
+
const timer = this.timers.get(bk);
|
|
178
187
|
if (timer) {
|
|
179
188
|
clearTimeout(timer);
|
|
180
|
-
this.timers.delete(
|
|
189
|
+
this.timers.delete(bk);
|
|
181
190
|
}
|
|
182
191
|
}
|
|
183
192
|
readDataLines(file) {
|
|
@@ -190,7 +199,7 @@ var RenderStore = class {
|
|
|
190
199
|
}
|
|
191
200
|
getAllRenders(projectId) {
|
|
192
201
|
this.flush(projectId);
|
|
193
|
-
if (projectId) return
|
|
202
|
+
if (projectId) return this.projectFiles(projectId).flatMap((f) => readJsonl(join(this.dir, f)).map(toResult));
|
|
194
203
|
return this.jsonlFiles().flatMap((f) => readJsonl(join(this.dir, f)).map(toResult));
|
|
195
204
|
}
|
|
196
205
|
getRendersByComponent(componentName, projectId) {
|
|
@@ -198,44 +207,64 @@ var RenderStore = class {
|
|
|
198
207
|
}
|
|
199
208
|
clearRenders(projectId) {
|
|
200
209
|
if (projectId) {
|
|
201
|
-
this.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
for (const bk of this.bufferKeysForProject(projectId)) {
|
|
211
|
+
this.buffers.delete(bk);
|
|
212
|
+
this.dicts.delete(bk);
|
|
213
|
+
this.bufferMeta.delete(bk);
|
|
214
|
+
const timer = this.timers.get(bk);
|
|
215
|
+
if (timer) {
|
|
216
|
+
clearTimeout(timer);
|
|
217
|
+
this.timers.delete(bk);
|
|
218
|
+
}
|
|
207
219
|
}
|
|
208
|
-
const
|
|
209
|
-
if (existsSync(file)) unlinkSync(file);
|
|
220
|
+
for (const f of this.projectFiles(projectId)) unlinkSync(join(this.dir, f));
|
|
210
221
|
} else {
|
|
211
|
-
for (const [
|
|
222
|
+
for (const [, timer] of this.timers) clearTimeout(timer);
|
|
212
223
|
this.buffers.clear();
|
|
213
224
|
this.timers.clear();
|
|
214
225
|
this.dicts.clear();
|
|
226
|
+
this.bufferMeta.clear();
|
|
215
227
|
for (const f of this.jsonlFiles()) unlinkSync(join(this.dir, f));
|
|
216
228
|
}
|
|
217
229
|
}
|
|
218
230
|
getProjects() {
|
|
219
231
|
this.flush();
|
|
220
232
|
const projects = /* @__PURE__ */ new Set();
|
|
233
|
+
const seen = /* @__PURE__ */ new Set();
|
|
221
234
|
for (const f of this.jsonlFiles()) {
|
|
235
|
+
const parsed = this.parseFilename(f);
|
|
236
|
+
if (!parsed) continue;
|
|
237
|
+
if (seen.has(parsed.projectSanitized)) continue;
|
|
238
|
+
seen.add(parsed.projectSanitized);
|
|
222
239
|
const lines = readFileSync(join(this.dir, f), "utf-8").split("\n");
|
|
223
240
|
for (const line of lines) {
|
|
224
241
|
if (!line) continue;
|
|
225
|
-
const
|
|
226
|
-
if ("@@dict" in
|
|
227
|
-
projects.add(
|
|
242
|
+
const obj = JSON.parse(line);
|
|
243
|
+
if ("@@dict" in obj) continue;
|
|
244
|
+
projects.add(obj.projectId);
|
|
228
245
|
break;
|
|
229
246
|
}
|
|
230
247
|
}
|
|
231
248
|
return [...projects];
|
|
232
249
|
}
|
|
233
250
|
getCommitIds(projectId) {
|
|
234
|
-
|
|
235
|
-
|
|
251
|
+
this.flush(projectId);
|
|
252
|
+
const files = projectId ? this.projectFiles(projectId) : this.jsonlFiles();
|
|
253
|
+
const ids = /* @__PURE__ */ new Set();
|
|
254
|
+
for (const f of files) {
|
|
255
|
+
const parsed = this.parseFilename(f);
|
|
256
|
+
if (parsed?.commitId != null) ids.add(parsed.commitId);
|
|
257
|
+
}
|
|
258
|
+
return [...ids].sort((a, b) => a - b);
|
|
236
259
|
}
|
|
237
260
|
getRendersByCommit(commitId, projectId) {
|
|
238
|
-
|
|
261
|
+
if (projectId) {
|
|
262
|
+
this.flush(projectId, commitId);
|
|
263
|
+
return readJsonl(this.commitFile(projectId, commitId)).map(toResult);
|
|
264
|
+
}
|
|
265
|
+
this.flush();
|
|
266
|
+
const suffix = `_commit_${commitId}.jsonl`;
|
|
267
|
+
return this.jsonlFiles().filter((f) => f.endsWith(suffix)).flatMap((f) => readJsonl(join(this.dir, f)).map(toResult));
|
|
239
268
|
}
|
|
240
269
|
getSummary(projectId) {
|
|
241
270
|
const renders = this.getAllRenders(projectId);
|
|
@@ -247,8 +276,33 @@ var RenderStore = class {
|
|
|
247
276
|
}
|
|
248
277
|
return summary;
|
|
249
278
|
}
|
|
250
|
-
|
|
251
|
-
return
|
|
279
|
+
bufferKey(projectId, commitId) {
|
|
280
|
+
return `${projectId}\0${commitId ?? NOCOMMIT}`;
|
|
281
|
+
}
|
|
282
|
+
bufferKeysForProject(projectId) {
|
|
283
|
+
const prefix = `${projectId}\0`;
|
|
284
|
+
return [...this.buffers.keys()].filter((bk) => bk.startsWith(prefix));
|
|
285
|
+
}
|
|
286
|
+
commitFile(projectId, commitId) {
|
|
287
|
+
const sanitized = sanitizeProjectId(projectId);
|
|
288
|
+
const suffix = commitId != null ? `_commit_${commitId}` : `_${NOCOMMIT}`;
|
|
289
|
+
return join(this.dir, `${sanitized}${suffix}.jsonl`);
|
|
290
|
+
}
|
|
291
|
+
projectFiles(projectId) {
|
|
292
|
+
const prefix = sanitizeProjectId(projectId);
|
|
293
|
+
return readdirSync(this.dir).filter((f) => f.startsWith(prefix) && f.endsWith(".jsonl"));
|
|
294
|
+
}
|
|
295
|
+
parseFilename(filename) {
|
|
296
|
+
if (!filename.endsWith(".jsonl")) return null;
|
|
297
|
+
const base = filename.slice(0, -6);
|
|
298
|
+
const commitMatch = base.match(/^(.+)_commit_(\d+)$/);
|
|
299
|
+
if (commitMatch) return {
|
|
300
|
+
projectSanitized: commitMatch[1],
|
|
301
|
+
commitId: Number(commitMatch[2])
|
|
302
|
+
};
|
|
303
|
+
const nocommitMatch = base.match(/^(.+)_nocommit$/);
|
|
304
|
+
if (nocommitMatch) return { projectSanitized: nocommitMatch[1] };
|
|
305
|
+
return { projectSanitized: base };
|
|
252
306
|
}
|
|
253
307
|
jsonlFiles() {
|
|
254
308
|
return readdirSync(this.dir).filter((f) => f.endsWith(".jsonl"));
|
package/package.json
CHANGED