clipqa-mcp 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -0
  3. package/build/artifacts.d.ts +4 -0
  4. package/build/artifacts.d.ts.map +1 -0
  5. package/build/artifacts.js +24 -0
  6. package/build/artifacts.js.map +1 -0
  7. package/build/backends.d.ts +16 -0
  8. package/build/backends.d.ts.map +1 -0
  9. package/build/backends.js +48 -0
  10. package/build/backends.js.map +1 -0
  11. package/build/config.d.ts +7 -0
  12. package/build/config.d.ts.map +1 -0
  13. package/build/config.js +15 -0
  14. package/build/config.js.map +1 -0
  15. package/build/index.d.ts +3 -0
  16. package/build/index.d.ts.map +1 -0
  17. package/build/index.js +25 -0
  18. package/build/index.js.map +1 -0
  19. package/build/media.d.ts +13 -0
  20. package/build/media.d.ts.map +1 -0
  21. package/build/media.js +139 -0
  22. package/build/media.js.map +1 -0
  23. package/build/process-runner.d.ts +9 -0
  24. package/build/process-runner.d.ts.map +1 -0
  25. package/build/process-runner.js +25 -0
  26. package/build/process-runner.js.map +1 -0
  27. package/build/recorder.d.ts +42 -0
  28. package/build/recorder.d.ts.map +1 -0
  29. package/build/recorder.js +272 -0
  30. package/build/recorder.js.map +1 -0
  31. package/build/replay.d.ts +10 -0
  32. package/build/replay.d.ts.map +1 -0
  33. package/build/replay.js +39 -0
  34. package/build/replay.js.map +1 -0
  35. package/build/sampling.d.ts +13 -0
  36. package/build/sampling.d.ts.map +1 -0
  37. package/build/sampling.js +52 -0
  38. package/build/sampling.js.map +1 -0
  39. package/build/server.d.ts +5 -0
  40. package/build/server.d.ts.map +1 -0
  41. package/build/server.js +360 -0
  42. package/build/server.js.map +1 -0
  43. package/build/session-store.d.ts +16 -0
  44. package/build/session-store.d.ts.map +1 -0
  45. package/build/session-store.js +93 -0
  46. package/build/session-store.js.map +1 -0
  47. package/build/types.d.ts +46 -0
  48. package/build/types.d.ts.map +1 -0
  49. package/build/types.js +2 -0
  50. package/build/types.js.map +1 -0
  51. package/build/visual.d.ts +62 -0
  52. package/build/visual.d.ts.map +1 -0
  53. package/build/visual.js +145 -0
  54. package/build/visual.js.map +1 -0
  55. package/build/windows.d.ts +4 -0
  56. package/build/windows.d.ts.map +1 -0
  57. package/build/windows.js +60 -0
  58. package/build/windows.js.map +1 -0
  59. package/docs/assets/banner.png +0 -0
  60. package/package.json +67 -0
  61. package/scripts/install-wgc.ps1 +40 -0
@@ -0,0 +1,42 @@
1
+ import type { CommandRunner } from "./process-runner.js";
2
+ import type { CaptureTarget, RecordingSession } from "./types.js";
3
+ import { SessionStore } from "./session-store.js";
4
+ import { type Backend } from "./backends.js";
5
+ export type EncoderChoice = "auto" | "libx264" | "h264_nvenc" | "h264_qsv" | "h264_amf";
6
+ export interface StartRecordingOptions {
7
+ target: CaptureTarget;
8
+ fps: number;
9
+ maxSeconds: number;
10
+ drawMouse: boolean;
11
+ encoder: EncoderChoice;
12
+ backend?: Backend | "auto";
13
+ bufferSeconds?: number;
14
+ maxWidth?: number;
15
+ }
16
+ export declare function buildCaptureArgs(target: CaptureTarget, outputPath: string, options: Omit<StartRecordingOptions, "target" | "encoder"> & {
17
+ encoder: string;
18
+ }): string[];
19
+ export declare function selectEncoder(requested: EncoderChoice, ffmpegPath: string, runner: CommandRunner): Promise<string>;
20
+ export declare class Recorder {
21
+ private readonly store;
22
+ private readonly ffmpegPath;
23
+ private readonly runner;
24
+ private readonly ffprobePath;
25
+ private readonly active;
26
+ private readonly errors;
27
+ private readonly finished;
28
+ private starting;
29
+ private readonly fileQueues;
30
+ private withFiles;
31
+ constructor(store: SessionStore, ffmpegPath: string, runner: CommandRunner, ffprobePath?: string);
32
+ start(options: StartRecordingOptions): Promise<RecordingSession>;
33
+ stop(id: string): Promise<RecordingSession>;
34
+ shutdown(): Promise<void>;
35
+ preview(id: string, seconds: number): Promise<{
36
+ videoPath: string;
37
+ offset: number;
38
+ duration: number;
39
+ } | undefined>;
40
+ private markFailed;
41
+ }
42
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAA2C,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGtF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,CAAC;AAExF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,SAAS,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/E,MAAM,EAAE,CA4BV;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED,qBAAa,QAAQ;IAcjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAhB9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqD;IAC5E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;YAEpD,SAAS;IAMvB,YACmB,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,WAAW,SAAY,EACtC;IAEE,KAAK,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA0FrE;IAEK,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4BhD;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAyE;IAElG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAmBvH;YAEa,UAAU;CAQzB"}
@@ -0,0 +1,272 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import path from "node:path";
4
+ import fs from "node:fs/promises";
5
+ import { conciseError } from "./process-runner.js";
6
+ import { listWindows } from "./windows.js";
7
+ import { capabilities, captureInput, listScreens } from "./backends.js";
8
+ import { segmentArgs, pruneSegments, finalizeReplay, segmentFiles } from "./replay.js";
9
+ export function buildCaptureArgs(target, outputPath, options) {
10
+ const backend = options.backend === "auto" ? "gdigrab" : options.backend ?? "gdigrab";
11
+ const encoderArgs = {
12
+ libx264: ["-c:v", "libx264", "-preset", "ultrafast", "-crf", "24"],
13
+ h264_nvenc: ["-c:v", "h264_nvenc", "-preset", "p1", "-cq", "24"],
14
+ h264_qsv: ["-c:v", "h264_qsv", "-preset", "veryfast", "-global_quality", "24"],
15
+ h264_amf: ["-c:v", "h264_amf", "-quality", "speed", "-qp_i", "24", "-qp_p", "24"],
16
+ };
17
+ const input = captureInput(backend, target, options.fps, options.drawMouse);
18
+ if (backend === "gfxcapture" && options.maxWidth)
19
+ input[1] = input[1].replace(",pad=", `,scale='min(${options.maxWidth},iw)':-2,pad=`);
20
+ return [
21
+ "-hide_banner",
22
+ "-loglevel",
23
+ "warning",
24
+ "-nostats",
25
+ "-progress", "pipe:1", "-stats_period", "0.2",
26
+ "-y",
27
+ ...input,
28
+ "-t",
29
+ String(options.maxSeconds),
30
+ ...(backend === "gfxcapture" ? [] : ["-vf", `${options.maxWidth ? `scale='min(${options.maxWidth},iw)':-2,` : ""}pad=ceil(iw/2)*2:ceil(ih/2)*2`]),
31
+ "-an",
32
+ ...(encoderArgs[options.encoder] ?? encoderArgs.libx264),
33
+ "-pix_fmt",
34
+ "yuv420p",
35
+ ...segmentArgs(path.dirname(outputPath), options.fps),
36
+ ];
37
+ }
38
+ export async function selectEncoder(requested, ffmpegPath, runner) {
39
+ if (requested !== "auto")
40
+ return requested;
41
+ const result = await runner.run(ffmpegPath, ["-hide_banner", "-encoders"]);
42
+ const available = result.stdout + result.stderr;
43
+ for (const candidate of ["h264_nvenc", "h264_qsv", "h264_amf"]) {
44
+ if (!available.includes(candidate))
45
+ continue;
46
+ const probe = await runner.run(ffmpegPath, [
47
+ "-hide_banner",
48
+ "-loglevel",
49
+ "error",
50
+ "-f",
51
+ "lavfi",
52
+ "-i",
53
+ "color=c=black:s=64x64:d=0.1",
54
+ "-frames:v",
55
+ "1",
56
+ "-c:v",
57
+ candidate,
58
+ "-f",
59
+ "null",
60
+ "-",
61
+ ]);
62
+ if (probe.code === 0)
63
+ return candidate;
64
+ }
65
+ return "libx264";
66
+ }
67
+ export class Recorder {
68
+ store;
69
+ ffmpegPath;
70
+ runner;
71
+ ffprobePath;
72
+ active = new Map();
73
+ errors = new Map();
74
+ finished = new Map();
75
+ starting = false;
76
+ fileQueues = new Map();
77
+ async withFiles(id, action) {
78
+ const task = (this.fileQueues.get(id) ?? Promise.resolve()).catch(() => undefined).then(action);
79
+ this.fileQueues.set(id, task);
80
+ try {
81
+ return await task;
82
+ }
83
+ finally {
84
+ if (this.fileQueues.get(id) === task)
85
+ this.fileQueues.delete(id);
86
+ }
87
+ }
88
+ constructor(store, ffmpegPath, runner, ffprobePath = "ffprobe") {
89
+ this.store = store;
90
+ this.ffmpegPath = ffmpegPath;
91
+ this.runner = runner;
92
+ this.ffprobePath = ffprobePath;
93
+ }
94
+ async start(options) {
95
+ if (this.active.size || this.starting)
96
+ throw new Error("One recording at a time is supported to limit resource use.");
97
+ this.starting = true;
98
+ try {
99
+ const caps = await capabilities(this.ffmpegPath, this.runner);
100
+ const backend = !options.backend || options.backend === "auto" ? caps.recommended : options.backend;
101
+ if (!backend || !caps.available.includes(backend))
102
+ throw new Error(`Capture backend unavailable. ${caps.warnings.join(" ")}`);
103
+ let target = { ...options.target };
104
+ if (process.platform === "win32") {
105
+ const matches = (await listWindows(this.runner)).filter(window => target.hwnd ? window.hwnd === target.hwnd : window.title === target.title);
106
+ if (matches.length !== 1)
107
+ throw new Error("Select one existing window with a unique title or HWND.");
108
+ if (matches[0].minimized)
109
+ throw new Error("The target is minimized and may not render frames. Restore it before recording; ClipQA will not change window focus.");
110
+ target = { title: matches[0].title, hwnd: matches[0].hwnd };
111
+ }
112
+ if (backend === "x11grab" && !target.display && process.env.DISPLAY)
113
+ target.display = process.env.DISPLAY;
114
+ if (backend === "avfoundation" && !(await listScreens(this.ffmpegPath, this.runner)).some(screen => screen.screenIndex === target.screenIndex))
115
+ throw new Error("screenIndex must identify a display from list_sources, not a camera.");
116
+ captureInput(backend, target, options.fps, options.drawMouse);
117
+ const id = randomUUID();
118
+ const encoder = await selectEncoder(options.encoder, this.ffmpegPath, this.runner);
119
+ const directory = this.store.sessionDir(id);
120
+ const videoPath = path.join(directory, "recording.mp4");
121
+ const session = {
122
+ id,
123
+ state: "recording",
124
+ target,
125
+ startedAt: new Date().toISOString(),
126
+ fps: options.fps,
127
+ encoder,
128
+ drawMouse: options.drawMouse,
129
+ maxSeconds: options.maxSeconds,
130
+ videoPath,
131
+ events: [],
132
+ backend,
133
+ warnings: caps.warnings,
134
+ ownerPid: process.pid,
135
+ ...(options.bufferSeconds ? { bufferSeconds: options.bufferSeconds } : {}),
136
+ };
137
+ await this.store.create(session);
138
+ const args = buildCaptureArgs(target, videoPath, { ...options, backend, encoder });
139
+ const child = spawn(this.ffmpegPath, args, {
140
+ windowsHide: true,
141
+ stdio: ["pipe", "pipe", "pipe"],
142
+ });
143
+ this.active.set(id, child);
144
+ child.stdin.on("error", () => undefined);
145
+ let forceStop;
146
+ const wallTimer = setTimeout(() => { child.stdin.write("q\n"); forceStop = setTimeout(() => child.kill(), 5000); }, (options.maxSeconds + 5) * 1000);
147
+ let pruning = Promise.resolve();
148
+ const timer = options.bufferSeconds ? setInterval(() => {
149
+ pruning = pruning.then(() => this.withFiles(id, () => pruneSegments(directory, options.bufferSeconds))).catch(() => { child.kill(); });
150
+ }, 1000) : undefined;
151
+ child.stderr.setEncoding("utf8");
152
+ child.stderr.on("data", (chunk) => {
153
+ this.errors.set(id, `${this.errors.get(id) ?? ""}${chunk}`.slice(-8000));
154
+ });
155
+ child.once("error", (error) => { this.errors.set(id, error.message); });
156
+ const ready = new Promise((resolve, reject) => {
157
+ let progress = "";
158
+ const timeout = setTimeout(() => { child.kill(); reject(new Error("No frames received within 10 seconds. Check target rendering and capture permissions.")); }, 10000);
159
+ const onData = (chunk) => {
160
+ progress = (progress + chunk.toString()).slice(-4000);
161
+ if (/frame=\s*[1-9]\d*/.test(progress)) {
162
+ clearTimeout(timeout);
163
+ child.stdout.off("data", onData);
164
+ child.stdout.resume();
165
+ resolve();
166
+ }
167
+ };
168
+ child.stdout.on("data", onData);
169
+ child.once("close", () => { clearTimeout(timeout); reject(new Error(`Capture ended before producing frames: ${conciseError(this.errors.get(id) ?? "")}`)); });
170
+ });
171
+ this.finished.set(id, new Promise(resolve => child.once("close", (code) => {
172
+ clearTimeout(wallTimer);
173
+ if (forceStop)
174
+ clearTimeout(forceStop);
175
+ if (timer)
176
+ clearInterval(timer);
177
+ void (async () => {
178
+ await pruning;
179
+ if (code !== 0)
180
+ throw new Error(conciseError(this.errors.get(id) ?? `FFmpeg exited with code ${code}.`));
181
+ const replay = await this.withFiles(id, () => finalizeReplay(directory, videoPath, options.bufferSeconds ?? options.maxSeconds, this.ffmpegPath, this.ffprobePath, this.runner));
182
+ await this.store.update(id, current => ({ ...current, state: "stopped", stoppedAt: new Date().toISOString(),
183
+ ...(replay ? { timelineOffsetSeconds: replay.offset, events: current.events.filter(e => e.timestampMs >= replay.offset * 1000 && e.timestampMs <= (replay.offset + replay.duration) * 1000).map(e => ({ ...e, timestampMs: e.timestampMs - replay.offset * 1000 })) } : {}),
184
+ }));
185
+ })().catch(error => this.markFailed(id, String(error))).finally(() => {
186
+ this.active.delete(id);
187
+ this.errors.delete(id);
188
+ resolve();
189
+ });
190
+ })));
191
+ try {
192
+ await ready;
193
+ }
194
+ catch (error) {
195
+ await this.finished.get(id);
196
+ throw error;
197
+ }
198
+ const started = await this.store.read(id);
199
+ if (started.state === "failed") {
200
+ throw new Error(`Recording failed to start: ${started.error ?? "unknown FFmpeg error"}`);
201
+ }
202
+ return started;
203
+ }
204
+ finally {
205
+ this.starting = false;
206
+ }
207
+ }
208
+ async stop(id) {
209
+ const child = this.active.get(id);
210
+ if (!child) {
211
+ const session = await this.store.read(id);
212
+ if (session.state === "recording") {
213
+ throw new Error("This recording is not owned by the current MCP process.");
214
+ }
215
+ return session;
216
+ }
217
+ if (child.exitCode !== null || child.signalCode !== null) {
218
+ await this.finished.get(id);
219
+ return this.store.read(id);
220
+ }
221
+ child.stdin.write("q\n");
222
+ await new Promise((resolve) => {
223
+ const timeout = setTimeout(() => {
224
+ child.kill();
225
+ resolve();
226
+ }, 5000);
227
+ child.once("close", () => {
228
+ clearTimeout(timeout);
229
+ resolve();
230
+ });
231
+ });
232
+ await this.finished.get(id);
233
+ this.finished.delete(id);
234
+ return this.store.read(id);
235
+ }
236
+ async shutdown() { await Promise.all([...this.active.keys()].map(id => this.stop(id))); }
237
+ async preview(id, seconds) {
238
+ const current = await this.store.read(id);
239
+ if (current.state !== "recording")
240
+ return { videoPath: current.videoPath, offset: current.timelineOffsetSeconds ?? 0, duration: 0 };
241
+ if (!this.active.has(id))
242
+ throw new Error("Live previews must be requested from the MCP process that owns this recording.");
243
+ const directory = path.join(this.store.sessionDir(id), "previews", randomUUID());
244
+ const copied = await this.withFiles(id, async () => {
245
+ const session = await this.store.read(id);
246
+ if (session.state !== "recording")
247
+ return false;
248
+ // The newest segment may still be open. Only copy immutable completed segments.
249
+ const files = (await segmentFiles(this.store.sessionDir(id))).slice(0, -1).slice(-Math.ceil(seconds / 2) - 1);
250
+ if (!files.length)
251
+ return false;
252
+ await fs.mkdir(directory, { recursive: true });
253
+ for (const file of files)
254
+ await fs.copyFile(path.join(this.store.sessionDir(id), file), path.join(directory, file));
255
+ return true;
256
+ });
257
+ if (!copied)
258
+ return undefined;
259
+ const videoPath = path.join(directory, "preview.mp4");
260
+ const replay = await finalizeReplay(directory, videoPath, seconds, this.ffmpegPath, this.ffprobePath, this.runner);
261
+ return { videoPath, ...replay };
262
+ }
263
+ async markFailed(id, error) {
264
+ await this.store.update(id, (session) => ({
265
+ ...session,
266
+ state: "failed",
267
+ stoppedAt: new Date().toISOString(),
268
+ error,
269
+ })).catch(() => undefined);
270
+ }
271
+ }
272
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { CommandRunner } from "./process-runner.js";
2
+ export declare const SEGMENT_SECONDS = 2;
3
+ export declare function segmentArgs(directory: string, fps: number): string[];
4
+ export declare function segmentFiles(directory: string): Promise<string[]>;
5
+ export declare function pruneSegments(directory: string, seconds: number): Promise<void>;
6
+ export declare function finalizeReplay(directory: string, output: string, seconds: number, ffmpeg: string, ffprobe: string, runner: CommandRunner): Promise<{
7
+ offset: number;
8
+ duration: number;
9
+ }>;
10
+ //# sourceMappingURL=replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpE;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEvE;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrF;AAED,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB9L"}
@@ -0,0 +1,39 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { MediaProcessor } from "./media.js";
4
+ export const SEGMENT_SECONDS = 2;
5
+ export function segmentArgs(directory, fps) {
6
+ return ["-g", String(fps * SEGMENT_SECONDS), "-force_key_frames", `expr:gte(t,n_forced*${SEGMENT_SECONDS})`, "-f", "segment", "-segment_time", String(SEGMENT_SECONDS), "-reset_timestamps", "1", path.join(directory, "part-%08d.ts")];
7
+ }
8
+ export async function segmentFiles(directory) {
9
+ return (await fs.readdir(directory)).filter(name => /^part-\d{8}\.ts$/.test(name)).sort();
10
+ }
11
+ export async function pruneSegments(directory, seconds) {
12
+ const files = await segmentFiles(directory);
13
+ // Keep the open segment plus boundary slack. Never remove a file still being written.
14
+ const keep = Math.ceil(seconds / SEGMENT_SECONDS) + 2;
15
+ await Promise.all(files.slice(0, Math.max(0, files.length - keep)).map(name => fs.unlink(path.join(directory, name))));
16
+ }
17
+ export async function finalizeReplay(directory, output, seconds, ffmpeg, ffprobe, runner) {
18
+ const files = await segmentFiles(directory);
19
+ if (!files.length)
20
+ throw new Error("Replay buffer contains no video segments.");
21
+ const media = new MediaProcessor(ffmpeg, ffprobe, runner);
22
+ // Probe the concatenation: TS container duration may include timestamp offsets.
23
+ const list = path.join(directory, "concat.txt");
24
+ await fs.writeFile(list, files.map(name => `file '${name}'`).join("\n"));
25
+ const joined = path.join(directory, "joined.mp4");
26
+ let result = await runner.run(ffmpeg, ["-hide_banner", "-loglevel", "error", "-y", "-f", "concat", "-safe", "1", "-i", list, "-an", "-c:v", "copy", joined]);
27
+ if (result.code)
28
+ throw new Error(`Cannot join replay segments: ${result.stderr.slice(-800)}`);
29
+ const duration = await media.duration(joined);
30
+ const trim = Math.max(0, duration - seconds);
31
+ result = await runner.run(ffmpeg, ["-hide_banner", "-loglevel", "error", "-y", "-ss", String(trim), "-i", joined, "-t", String(seconds), "-an", ...(trim > 0 ? ["-c:v", "libx264", "-preset", "ultrafast", "-crf", "24"] : ["-c:v", "copy"]), "-movflags", "+faststart", output]);
32
+ if (result.code)
33
+ throw new Error(`Cannot save replay: ${result.stderr.slice(-800)}`);
34
+ const offset = Number(files[0].match(/\d+/)[0]) * SEGMENT_SECONDS + trim;
35
+ // Only remove known recorder artifacts after a successful final output.
36
+ await Promise.all([...files, "concat.txt", "joined.mp4"].map(name => fs.unlink(path.join(directory, name))));
37
+ return { offset, duration: Math.min(seconds, duration) };
38
+ }
39
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface InspectionSignals {
2
+ startSeconds: number;
3
+ endSeconds: number;
4
+ overviewSamples: number;
5
+ eventTimesSeconds?: number[];
6
+ visualChangeTimesSeconds?: number[];
7
+ neighborhoodSeconds?: number;
8
+ }
9
+ export declare function evenlySpaced(start: number, end: number, count: number): number[];
10
+ export declare function chooseInspectionTimestamps(signals: InspectionSignals): number[];
11
+ export declare function chooseBoundedInspectionTimestamps(signals: Omit<InspectionSignals, "overviewSamples">, maxSamples: number): number[];
12
+ export declare function hitsInterval(timestamp: number, start: number, end: number): boolean;
13
+ //# sourceMappingURL=sampling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sampling.d.ts","sourceRoot":"","sources":["../src/sampling.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAKhF;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAkB/E;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,EACnD,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CA8BV;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnF"}
@@ -0,0 +1,52 @@
1
+ function clamp(value, min, max) {
2
+ return Math.max(min, Math.min(max, value));
3
+ }
4
+ export function evenlySpaced(start, end, count) {
5
+ if (count <= 0 || end < start)
6
+ return [];
7
+ if (count === 1 || end === start)
8
+ return [start];
9
+ const step = (end - start) / (count - 1);
10
+ return Array.from({ length: count }, (_, index) => start + step * index);
11
+ }
12
+ export function chooseInspectionTimestamps(signals) {
13
+ const { startSeconds, endSeconds, overviewSamples, eventTimesSeconds = [], visualChangeTimesSeconds = [], neighborhoodSeconds = 0.2, } = signals;
14
+ const candidates = evenlySpaced(startSeconds, endSeconds, overviewSamples);
15
+ for (const time of [...eventTimesSeconds, ...visualChangeTimesSeconds]) {
16
+ candidates.push(time - neighborhoodSeconds, time, time + neighborhoodSeconds);
17
+ }
18
+ return [...new Set(candidates.map((time) => clamp(time, startSeconds, endSeconds).toFixed(3)))]
19
+ .map(Number)
20
+ .sort((a, b) => a - b);
21
+ }
22
+ export function chooseBoundedInspectionTimestamps(signals, maxSamples) {
23
+ if (maxSamples <= 0)
24
+ return [];
25
+ const { startSeconds, endSeconds, eventTimesSeconds = [], visualChangeTimesSeconds = [], neighborhoodSeconds = 0.2, } = signals;
26
+ const result = new Set();
27
+ const add = (time) => {
28
+ if (result.size >= maxSamples)
29
+ return;
30
+ result.add(clamp(time, startSeconds, endSeconds).toFixed(3));
31
+ };
32
+ add(startSeconds);
33
+ add(endSeconds);
34
+ const anchors = [...new Set([...eventTimesSeconds, ...visualChangeTimesSeconds])]
35
+ .filter((time) => time >= startSeconds && time <= endSeconds)
36
+ .sort((a, b) => a - b);
37
+ const slots = maxSamples - result.size;
38
+ const selected = anchors.length > slots ? evenlySpaced(0, anchors.length - 1, slots).map(i => anchors[Math.round(i)]) : anchors;
39
+ for (const time of selected)
40
+ add(time);
41
+ for (const time of anchors) {
42
+ add(time - neighborhoodSeconds);
43
+ add(time + neighborhoodSeconds);
44
+ }
45
+ for (const time of evenlySpaced(startSeconds, endSeconds, maxSamples))
46
+ add(time);
47
+ return [...result].map(Number).sort((a, b) => a - b);
48
+ }
49
+ export function hitsInterval(timestamp, start, end) {
50
+ return timestamp >= start && timestamp <= end;
51
+ }
52
+ //# sourceMappingURL=sampling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sampling.js","sourceRoot":"","sources":["../src/sampling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { McpServer } from "@modelcontextprotocol/server";
2
+ import type { ClipQaConfig } from "./config.js";
3
+ export declare function createServer(config: ClipQaConfig): Promise<McpServer>;
4
+ export declare function serve(config: ClipQaConfig): Promise<void>;
5
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAGzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoBhD,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAyU3E;AAED,wBAAsB,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/D"}