@vscode/component-explorer-cli 0.2.0 → 0.2.1-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.
Files changed (53) hide show
  1. package/dist/_virtual/_build-info.js +1 -1
  2. package/dist/browserPage.d.ts +11 -2
  3. package/dist/browserPage.d.ts.map +1 -1
  4. package/dist/browserPage.js +26 -8
  5. package/dist/browserPage.js.map +1 -1
  6. package/dist/commands/mcpCommand.d.ts.map +1 -1
  7. package/dist/commands/mcpCommand.js +20 -16
  8. package/dist/commands/mcpCommand.js.map +1 -1
  9. package/dist/commands/screenshotCommand.d.ts.map +1 -1
  10. package/dist/commands/screenshotCommand.js +4 -0
  11. package/dist/commands/screenshotCommand.js.map +1 -1
  12. package/dist/commands/serveCommand.d.ts +2 -0
  13. package/dist/commands/serveCommand.d.ts.map +1 -1
  14. package/dist/commands/serveCommand.js +75 -24
  15. package/dist/commands/serveCommand.js.map +1 -1
  16. package/dist/commands/watchCommand.js +9 -4
  17. package/dist/commands/watchCommand.js.map +1 -1
  18. package/dist/component-explorer-config.schema.json +166 -0
  19. package/dist/componentExplorer.d.ts +8 -1
  20. package/dist/componentExplorer.d.ts.map +1 -1
  21. package/dist/componentExplorer.js +34 -5
  22. package/dist/componentExplorer.js.map +1 -1
  23. package/dist/daemon/DaemonService.d.ts +25 -4
  24. package/dist/daemon/DaemonService.d.ts.map +1 -1
  25. package/dist/daemon/DaemonService.js +57 -16
  26. package/dist/daemon/DaemonService.js.map +1 -1
  27. package/dist/daemon/lifecycle.d.ts +2 -1
  28. package/dist/daemon/lifecycle.d.ts.map +1 -1
  29. package/dist/daemon/lifecycle.js +41 -6
  30. package/dist/daemon/lifecycle.js.map +1 -1
  31. package/dist/explorerSession.d.ts +3 -3
  32. package/dist/explorerSession.d.ts.map +1 -1
  33. package/dist/explorerSession.js +26 -9
  34. package/dist/explorerSession.js.map +1 -1
  35. package/dist/httpServer.d.ts +12 -6
  36. package/dist/httpServer.d.ts.map +1 -1
  37. package/dist/httpServer.js +104 -18
  38. package/dist/httpServer.js.map +1 -1
  39. package/dist/httpServer.test.d.ts +2 -0
  40. package/dist/httpServer.test.d.ts.map +1 -0
  41. package/dist/mcp/McpServer.d.ts +5 -0
  42. package/dist/mcp/McpServer.d.ts.map +1 -1
  43. package/dist/mcp/McpServer.js +218 -0
  44. package/dist/mcp/McpServer.js.map +1 -1
  45. package/dist/visualCache.d.ts +34 -0
  46. package/dist/visualCache.d.ts.map +1 -0
  47. package/dist/visualCache.js +90 -0
  48. package/dist/visualCache.js.map +1 -0
  49. package/dist/watchConfig.d.ts +50 -4
  50. package/dist/watchConfig.d.ts.map +1 -1
  51. package/dist/watchConfig.js +72 -23
  52. package/dist/watchConfig.js.map +1 -1
  53. package/package.json +1 -1
@@ -1,29 +1,116 @@
1
- import './external/vscode-observables/observables/dist/observableInternal/index.js';
2
- import { observableValue } from './external/vscode-observables/observables/dist/observableInternal/observables/observableValue.js';
3
- import './external/vscode-observables/observables/dist/observableInternal/debugLocation.js';
4
- import './external/vscode-observables/observables/dist/observableInternal/observables/derived.js';
5
- import './external/vscode-observables/observables/dist/observableInternal/utils/utils.js';
6
- import './external/vscode-observables/observables/dist/observableInternal/observables/observableFromEvent.js';
7
1
  import { nullLogger } from './logger.js';
8
- import { SourceTreeId } from './sourceTreeId.js';
9
2
 
10
3
  class DefaultComponentExplorerHttpServerFactory {
11
4
  async createViteServer(project, options) {
12
5
  return ViteComponentExplorerHttpServer.create(project, options);
13
6
  }
14
- async createStaticServer(_distDir) {
15
- throw new Error('Static server not yet implemented');
7
+ async createHttpServer(url, options) {
8
+ return HttpComponentExplorerServer.create(url, options);
16
9
  }
17
10
  }
11
+ class HttpComponentExplorerServer {
12
+ url;
13
+ _process;
14
+ static async create(urlTemplate, options) {
15
+ let proc;
16
+ let vars = {};
17
+ if (options?.cmd) {
18
+ const log = options.logger ?? nullLogger;
19
+ log.debug(`Starting HTTP server: ${options.cmd}`);
20
+ log.debug(`HTTP server cwd: ${options.cwd ?? process.cwd()}`);
21
+ const { spawn } = await import('node:child_process');
22
+ proc = spawn(options.cmd, { shell: true, stdio: 'pipe', cwd: options.cwd });
23
+ proc.on('error', (e) => log.log(`HTTP server process error: ${e.message}`));
24
+ proc.on('exit', (code) => log.debug(`HTTP server process exited (code=${code})`));
25
+ if (options.wait?.stdout || options.wait?.stderr) {
26
+ vars = await waitForOutputPattern(proc, options.wait, log);
27
+ }
28
+ else {
29
+ proc.stdout?.on('data', (d) => log.trace(d.toString().trimEnd()));
30
+ proc.stderr?.on('data', (d) => log.trace(d.toString().trimEnd()));
31
+ }
32
+ }
33
+ const url = resolveUrlTemplate(urlTemplate, vars);
34
+ return new HttpComponentExplorerServer(url, proc);
35
+ }
36
+ constructor(url, _process) {
37
+ this.url = url;
38
+ this._process = _process;
39
+ }
40
+ async dispose() {
41
+ if (this._process && !this._process.killed) {
42
+ this._process.kill();
43
+ }
44
+ }
45
+ }
46
+ function resolveUrlTemplate(template, vars) {
47
+ return template.replace(/\$\{var:([^}]+)\}/g, (match, name) => {
48
+ if (!(name in vars)) {
49
+ throw new Error(`Unresolved variable \${var:${name}} in URL. Available: ${Object.keys(vars).join(', ') || '(none)'}`);
50
+ }
51
+ return vars[name];
52
+ });
53
+ }
54
+ const _stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '').replace(/\x1b\].*?\x07/g, '');
55
+ function waitForOutputPattern(proc, wait, log) {
56
+ return new Promise((resolve, reject) => {
57
+ let resolved = false;
58
+ const vars = {};
59
+ let pendingCount = (wait.stdout ? 1 : 0) + (wait.stderr ? 1 : 0);
60
+ const buffers = { stdout: '', stderr: '' };
61
+ const tryResolve = () => {
62
+ if (resolved || pendingCount > 0) {
63
+ return;
64
+ }
65
+ resolved = true;
66
+ proc.stdout?.on('data', (d) => log.trace(d.toString().trimEnd()));
67
+ proc.stderr?.on('data', (d) => log.trace(d.toString().trimEnd()));
68
+ resolve(vars);
69
+ };
70
+ const makeHandler = (stream, pattern) => {
71
+ const handler = (d) => {
72
+ const text = d.toString();
73
+ log.trace(text.trimEnd());
74
+ buffers[stream] += _stripAnsi(text);
75
+ const m = pattern.exec(buffers[stream]);
76
+ if (m) {
77
+ log.debug(`${stream} pattern matched: ${JSON.stringify(m.groups ?? {})}`);
78
+ proc[stream]?.off('data', handler);
79
+ Object.assign(vars, m.groups ?? {});
80
+ pendingCount--;
81
+ tryResolve();
82
+ }
83
+ };
84
+ return handler;
85
+ };
86
+ if (wait.stdout) {
87
+ proc.stdout?.on('data', makeHandler('stdout', wait.stdout));
88
+ }
89
+ else {
90
+ proc.stdout?.on('data', (d) => log.trace(d.toString().trimEnd()));
91
+ }
92
+ if (wait.stderr) {
93
+ proc.stderr?.on('data', makeHandler('stderr', wait.stderr));
94
+ }
95
+ else {
96
+ proc.stderr?.on('data', (d) => log.trace(d.toString().trimEnd()));
97
+ }
98
+ proc.on('exit', (code) => {
99
+ if (!resolved) {
100
+ const details = [wait.stdout ? `stdout buffer:\n${buffers.stdout}` : '', wait.stderr ? `stderr buffer:\n${buffers.stderr}` : ''].filter(Boolean).join('\n');
101
+ reject(new Error(`HTTP server process exited (code=${code}) before output matched wait patterns.\n${details}`));
102
+ }
103
+ });
104
+ });
105
+ }
18
106
  class ViteComponentExplorerHttpServer {
19
107
  _server;
20
108
  url;
21
- sourceTreeId;
22
- isStatic = false;
23
- constructor(_server, url, sourceTreeId) {
109
+ onSourceChange;
110
+ constructor(_server, url, onSourceChange) {
24
111
  this._server = _server;
25
112
  this.url = url;
26
- this.sourceTreeId = sourceTreeId;
113
+ this.onSourceChange = onSourceChange;
27
114
  }
28
115
  static async create(project, options) {
29
116
  const log = options?.logger ?? nullLogger;
@@ -116,11 +203,10 @@ class ViteComponentExplorerHttpServer {
116
203
  const resolvedUrls = server.resolvedUrls;
117
204
  const url = resolvedUrls?.local[0] ?? `http://localhost:${server.httpServer?.address()?.port}`;
118
205
  log.debug(`Vite server started: ${url}`);
119
- const treeId = observableValue('sourceTreeId', new SourceTreeId(Date.now().toString()));
120
- server.watcher.on('change', () => {
121
- treeId.set(new SourceTreeId(Date.now().toString()), undefined);
122
- });
123
- return new ViteComponentExplorerHttpServer(server, url.replace(/\/$/, ''), treeId);
206
+ const onSourceChange = (callback) => {
207
+ server.watcher.on('change', callback);
208
+ };
209
+ return new ViteComponentExplorerHttpServer(server, url.replace(/\/$/, ''), onSourceChange);
124
210
  }
125
211
  async dispose() {
126
212
  await this._server.close();
@@ -1 +1 @@
1
- {"version":3,"file":"httpServer.js","sources":["../src/httpServer.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"httpServer.js","sources":["../src/httpServer.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=httpServer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpServer.test.d.ts","sourceRoot":"","sources":["../src/httpServer.test.ts"],"names":[],"mappings":""}
@@ -18,6 +18,7 @@ export declare class ComponentExplorerMcpServer extends Disposable {
18
18
  static create(daemon: IObservable<DaemonConnection | undefined>, options?: McpServerOptions): Promise<ComponentExplorerMcpServer>;
19
19
  private readonly _mcp;
20
20
  private readonly _watchList;
21
+ private readonly _imageLru;
21
22
  private readonly _taskManager;
22
23
  private readonly _taskLastReportedIndex;
23
24
  private readonly _pollFn?;
@@ -50,6 +51,8 @@ export declare class ComponentExplorerMcpServer extends Disposable {
50
51
  private _registerScreenshot;
51
52
  private _registerCompareScreenshot;
52
53
  private _registerApproveDiff;
54
+ private _registerReviewVisual;
55
+ private _registerCheckVisuals;
53
56
  private _registerEvaluateJs;
54
57
  private _registerDebugReloadPage;
55
58
  private _registerWatchAdd;
@@ -67,5 +70,7 @@ export declare class ComponentExplorerMcpServer extends Disposable {
67
70
  private _registerCheckStability;
68
71
  private _registerCheckTask;
69
72
  private _registerCancelTask;
73
+ private _registerDebugGetImageByHash;
74
+ private _registerDebugSetBrowserVisibility;
70
75
  }
71
76
  //# sourceMappingURL=McpServer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpServer.d.ts","sourceRoot":"","sources":["../../src/mcp/McpServer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAW,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,4BAA4B,CAAC;AAqE7E,qBAAa,gBAAgB;IAEhB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC;IAD1D,OAAO,CAAC,MAAM,CAAS;gBACF,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC;IAC1D,IAAI,OAAO,IAAI,OAAO,CAAwB;IAC9C,SAAS,IAAI,IAAI;CACjB;AAWD,MAAM,WAAW,gBAAgB;IAChC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,qBAAa,0BAA2B,SAAQ,UAAU;IAsBxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB;WArBtB,MAAM,CAClB,MAAM,EAAE,WAAW,CAAC,gBAAgB,GAAG,SAAS,CAAC,EACjD,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,0BAA0B,CAAC;IAOtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA6B;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAwB;IAC3D,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,2BAA2B,CAA8B;IAEjE,OAAO;YAmBO,gBAAgB;IAqB9B,OAAO,CAAC,cAAc;YAMR,cAAc;IAkB5B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IAC1D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;YAE1B,WAAW;IA8BzB,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,2BAA2B;IAKnC,OAAO,CAAC,0BAA0B;IAKlC,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,0BAA0B;YAOpB,gBAAgB;IAmB9B,OAAO,CAAC,iCAAiC;YAW3B,oBAAoB;IAelC,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,qBAAqB;IA8B7B,OAAO,CAAC,mBAAmB;IAoF3B,OAAO,CAAC,0BAA0B;IA8FlC,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,mBAAmB;IAsC3B,OAAO,CAAC,wBAAwB;IAuBhC,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,qBAAqB;IA2E7B,OAAO,CAAC,sBAAsB;YAgEhB,oBAAoB;IA6ClC,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,yBAAyB;IAwBjC,OAAO,CAAC,eAAe;IAkFvB,OAAO,CAAC,uBAAuB;IA+F/B,OAAO,CAAC,kBAAkB;IAoD1B,OAAO,CAAC,mBAAmB;CAoB3B"}
1
+ {"version":3,"file":"McpServer.d.ts","sourceRoot":"","sources":["../../src/mcp/McpServer.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,35 @@ import { TaskManager } from './TaskManager.js';
14
14
  // ---------------------------------------------------------------------------
15
15
  // Client-local state
16
16
  // ---------------------------------------------------------------------------
17
+ class ImageLruCache {
18
+ _maxSize;
19
+ _entries = [];
20
+ constructor(_maxSize = 10) {
21
+ this._maxSize = _maxSize;
22
+ }
23
+ put(hash, image) {
24
+ const idx = this._entries.findIndex(e => e.hash === hash);
25
+ if (idx !== -1) {
26
+ this._entries.splice(idx, 1);
27
+ }
28
+ this._entries.unshift({ hash, image });
29
+ if (this._entries.length > this._maxSize) {
30
+ this._entries.length = this._maxSize;
31
+ }
32
+ }
33
+ get(hash) {
34
+ const idx = this._entries.findIndex(e => e.hash === hash);
35
+ if (idx === -1) {
36
+ return undefined;
37
+ }
38
+ const [entry] = this._entries.splice(idx, 1);
39
+ this._entries.unshift(entry);
40
+ return entry.image;
41
+ }
42
+ keys() {
43
+ return this._entries.map(e => e.hash);
44
+ }
45
+ }
17
46
  class WatchList {
18
47
  _fixtureIds = new Set();
19
48
  _hashes = new Map();
@@ -101,6 +130,7 @@ class ComponentExplorerMcpServer extends Disposable {
101
130
  }
102
131
  _mcp;
103
132
  _watchList = new WatchList();
133
+ _imageLru = new ImageLruCache(10);
104
134
  _taskManager = new TaskManager();
105
135
  _taskLastReportedIndex = new Map();
106
136
  _pollFn;
@@ -337,6 +367,8 @@ class ComponentExplorerMcpServer extends Disposable {
337
367
  this._registerScreenshot();
338
368
  this._registerCompareScreenshot();
339
369
  this._registerApproveDiff();
370
+ this._registerReviewVisual();
371
+ this._registerCheckVisuals();
340
372
  this._registerEvaluateJs();
341
373
  this._registerDebugReloadPage();
342
374
  this._registerWatchAdd();
@@ -353,6 +385,8 @@ class ComponentExplorerMcpServer extends Disposable {
353
385
  this._registerCheckStability();
354
386
  this._registerCheckTask();
355
387
  this._registerCancelTask();
388
+ this._registerDebugGetImageByHash();
389
+ this._registerDebugSetBrowserVisibility();
356
390
  }
357
391
  _registerListFixtures() {
358
392
  this._mcp.registerTool('list_fixtures', {
@@ -406,6 +440,10 @@ class ComponentExplorerMcpServer extends Disposable {
406
440
  });
407
441
  const r = result;
408
442
  this._updateSessionSourceTreeId(sessionName, r.sourceTreeId);
443
+ // Cache image for debug_get_image_by_hash
444
+ if (r.hash && r.image) {
445
+ this._imageLru.put(r.hash, r.image);
446
+ }
409
447
  const info = {
410
448
  hash: r.hash,
411
449
  sourceTreeId: r.sourceTreeId,
@@ -425,6 +463,23 @@ class ComponentExplorerMcpServer extends Disposable {
425
463
  if (r.isStable !== undefined) {
426
464
  info.isStable = r.isStable;
427
465
  }
466
+ // Visual review status
467
+ if (r.hash) {
468
+ try {
469
+ const allFixtures = await daemon.methods.fixtures.list({ sessionName, sourceTreeId });
470
+ const fixture = allFixtures.find(f => f.fixtureId === args.fixtureId);
471
+ const descriptions = fixture?.expectedVisualDescriptions ?? [];
472
+ const review = await daemon.methods.visualReview.getStatus({
473
+ fixtureId: args.fixtureId,
474
+ expectedVisualDescriptions: [...descriptions],
475
+ screenshotHash: r.hash,
476
+ });
477
+ info.review = review;
478
+ }
479
+ catch {
480
+ // Visual review not available — ignore
481
+ }
482
+ }
428
483
  const content = [];
429
484
  if (r.isStable === false && r.stabilityScreenshots) {
430
485
  // Not stable: return all distinct screenshots
@@ -545,6 +600,127 @@ class ComponentExplorerMcpServer extends Disposable {
545
600
  tool.disable();
546
601
  this._multiSessionTools.push(tool);
547
602
  }
603
+ _registerReviewVisual() {
604
+ this._mcp.registerTool('review_visual', {
605
+ description: 'Approve or reject a fixture\'s screenshot based on its expectedVisualDescriptions. ' +
606
+ 'You must take a screenshot first and pass the resulting hash. ' +
607
+ 'On approve, caches (expectedVisualDescriptions, screenshotHash) so future runs auto-approve.',
608
+ inputSchema: {
609
+ fixtureId: z.string().describe('The fixture ID'),
610
+ screenshotHash: z.string().describe('The screenshot hash (from a prior screenshot tool call)'),
611
+ verdict: z.enum(['approve', 'reject']).describe('Whether the visual matches expectations'),
612
+ comment: z.string().describe('Reason for the verdict'),
613
+ sessionName: z.string().optional().describe('Session name (defaults to first session)'),
614
+ sourceTreeId: z.string().optional().describe('Source tree ID (defaults to latest known)'),
615
+ },
616
+ }, async (args) => this._withDaemon(async (daemon) => {
617
+ const sessionName = args.sessionName ?? this._defaultSessionName();
618
+ this._log('debug', { type: 'tool-call', tool: 'review_visual', fixtureId: args.fixtureId, verdict: args.verdict });
619
+ return this._withSourceTreeRetry(async () => {
620
+ const sourceTreeId = args.sourceTreeId ?? this._sourceTreeId(sessionName);
621
+ // Get fixture descriptions
622
+ const allFixtures = await daemon.methods.fixtures.list({ sessionName, sourceTreeId });
623
+ const fixture = allFixtures.find(f => f.fixtureId === args.fixtureId);
624
+ if (!fixture) {
625
+ return { content: [{ type: 'text', text: `Fixture not found: ${args.fixtureId}` }], isError: true };
626
+ }
627
+ if (fixture.expectedVisualDescriptions.length === 0) {
628
+ return { content: [{ type: 'text', text: `Fixture ${args.fixtureId} has no expectedVisualDescriptions — nothing to review.` }], isError: true };
629
+ }
630
+ if (args.verdict === 'approve') {
631
+ await daemon.methods.visualReview.approve({
632
+ fixtureId: args.fixtureId,
633
+ expectedVisualDescriptions: [...fixture.expectedVisualDescriptions],
634
+ screenshotHash: args.screenshotHash,
635
+ comment: args.comment,
636
+ });
637
+ return {
638
+ content: [{ type: 'text', text: `Approved: ${args.fixtureId} (hash: ${args.screenshotHash})` }],
639
+ };
640
+ }
641
+ else {
642
+ return {
643
+ content: [{ type: 'text', text: JSON.stringify({
644
+ fixtureId: args.fixtureId,
645
+ verdict: 'rejected',
646
+ comment: args.comment,
647
+ screenshotHash: args.screenshotHash,
648
+ expectedVisualDescriptions: fixture.expectedVisualDescriptions,
649
+ }, null, 2) }],
650
+ };
651
+ }
652
+ });
653
+ }));
654
+ }
655
+ _registerCheckVisuals() {
656
+ this._mcp.registerTool('check_visuals', {
657
+ description: 'Batch check visual review status for fixtures that have expectedVisualDescription. ' +
658
+ 'Returns lists of approved, needs-review, and no-expectation fixtures.',
659
+ inputSchema: {
660
+ fixtureIdPattern: z.string().optional().describe('RegExp to filter fixtures by fixture ID'),
661
+ labelPattern: z.string().optional().describe('RegExp to filter fixtures by label'),
662
+ sessionName: z.string().optional().describe('Session name (defaults to first session)'),
663
+ sourceTreeId: z.string().optional().describe('Source tree ID (defaults to latest known)'),
664
+ },
665
+ annotations: { readOnlyHint: true },
666
+ }, async (args) => this._withDaemon(async (daemon) => {
667
+ const sessionName = args.sessionName ?? this._defaultSessionName();
668
+ this._log('debug', { type: 'tool-call', tool: 'check_visuals', sessionName });
669
+ return this._withSourceTreeRetry(async () => {
670
+ const sourceTreeId = args.sourceTreeId ?? this._sourceTreeId(sessionName);
671
+ const allFixtures = await daemon.methods.fixtures.list({ sessionName, sourceTreeId });
672
+ const filtered = this._filterFixtures(allFixtures, args.fixtureIdPattern, args.labelPattern);
673
+ if ('error' in filtered) {
674
+ return { content: [{ type: 'text', text: filtered.error }], isError: true };
675
+ }
676
+ const approved = [];
677
+ const needsReview = [];
678
+ const noExpectation = [];
679
+ // Take screenshots for all fixtures with expectations
680
+ const withExpectations = filtered.fixtures.filter(f => f.expectedVisualDescriptions.length > 0);
681
+ const withoutExpectations = filtered.fixtures.filter(f => f.expectedVisualDescriptions.length === 0);
682
+ for (const f of withoutExpectations) {
683
+ noExpectation.push(f.fixtureId);
684
+ }
685
+ for (const f of withExpectations) {
686
+ try {
687
+ const screenshotResult = await daemon.methods.screenshots.take({
688
+ fixtureId: f.fixtureId, sessionName, sourceTreeId, includeImage: true,
689
+ });
690
+ const hash = screenshotResult.hash;
691
+ const image = screenshotResult.image;
692
+ if (hash && image) {
693
+ this._imageLru.put(hash, image);
694
+ }
695
+ if (!hash) {
696
+ needsReview.push({ fixtureId: f.fixtureId, reason: 'screenshot-failed' });
697
+ continue;
698
+ }
699
+ const review = await daemon.methods.visualReview.getStatus({
700
+ fixtureId: f.fixtureId,
701
+ expectedVisualDescriptions: [...f.expectedVisualDescriptions],
702
+ screenshotHash: hash,
703
+ });
704
+ if (review === 'no-expectations') {
705
+ noExpectation.push(f.fixtureId);
706
+ }
707
+ else if (typeof review === 'object' && review.status === 'approved') {
708
+ approved.push({ fixtureId: f.fixtureId, screenshotHash: hash });
709
+ }
710
+ else {
711
+ needsReview.push({ fixtureId: f.fixtureId, screenshotHash: hash, reason: 'needs-review' });
712
+ }
713
+ }
714
+ catch {
715
+ needsReview.push({ fixtureId: f.fixtureId, reason: 'error' });
716
+ }
717
+ }
718
+ return {
719
+ content: [{ type: 'text', text: JSON.stringify({ approved, needsReview, noExpectation }, null, 2) }],
720
+ };
721
+ });
722
+ }));
723
+ }
548
724
  _registerEvaluateJs() {
549
725
  this._mcp.registerTool('evaluate_js', {
550
726
  description: 'Evaluate a JavaScript expression in the browser page where fixtures are rendered, for debugging purposes. ' +
@@ -1138,6 +1314,48 @@ class ComponentExplorerMcpServer extends Disposable {
1138
1314
  };
1139
1315
  });
1140
1316
  }
1317
+ _registerDebugGetImageByHash() {
1318
+ this._mcp.registerTool('debug_get_image_by_hash', {
1319
+ description: 'Retrieve a recently-taken screenshot image by its hash. ' +
1320
+ 'Keeps the last ~10 images in an LRU cache. ' +
1321
+ 'Useful for debugging when screenshot hashes behave unexpectedly.',
1322
+ inputSchema: {
1323
+ hash: z.string().describe('The screenshot hash to look up'),
1324
+ },
1325
+ annotations: { readOnlyHint: true },
1326
+ }, async (args) => {
1327
+ const image = this._imageLru.get(args.hash);
1328
+ if (!image) {
1329
+ return {
1330
+ content: [{ type: 'text', text: `No cached image for hash '${args.hash}'. Available hashes: ${this._imageLru.keys().join(', ') || '(none)'}` }],
1331
+ isError: true,
1332
+ };
1333
+ }
1334
+ return {
1335
+ content: [
1336
+ { type: 'text', text: `Image for hash: ${args.hash}` },
1337
+ { type: 'image', data: image, mimeType: 'image/png' },
1338
+ ],
1339
+ };
1340
+ });
1341
+ }
1342
+ _registerDebugSetBrowserVisibility() {
1343
+ this._mcp.registerTool('debug_set_browser_visibility', {
1344
+ description: 'Show or hide the browser window used for rendering fixtures. ' +
1345
+ 'Only use this tool when the user explicitly asks to show or hide the browser. ' +
1346
+ 'Do not call this tool automatically or as part of other workflows. ' +
1347
+ 'Note: changing visibility closes the current browser instance, so the next screenshot or evaluate_js call will relaunch it.',
1348
+ inputSchema: {
1349
+ visible: z.boolean().describe('true to show the browser window (headed mode), false to hide it (headless mode)'),
1350
+ },
1351
+ annotations: { destructiveHint: true },
1352
+ }, async (args) => this._withDaemon(async (daemon) => {
1353
+ await daemon.methods.setBrowserVisibility({ visible: args.visible });
1354
+ return {
1355
+ content: [{ type: 'text', text: `Browser is now ${args.visible ? 'visible (headed)' : 'hidden (headless)'}.` }],
1356
+ };
1357
+ }));
1358
+ }
1141
1359
  }
1142
1360
 
1143
1361
  export { ComponentExplorerMcpServer, DaemonConnection };