agent-vision-mcp 0.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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/dist/browser/cdp/browser-cdp-discovery-service.d.ts +10 -0
  4. package/dist/browser/cdp/browser-cdp-discovery-service.js +28 -0
  5. package/dist/browser/cdp/browser-live-tab-service.d.ts +16 -0
  6. package/dist/browser/cdp/browser-live-tab-service.js +42 -0
  7. package/dist/browser/cdp/browser-see-service.d.ts +33 -0
  8. package/dist/browser/cdp/browser-see-service.js +76 -0
  9. package/dist/browser/cdp/browser-tab-context-service.d.ts +23 -0
  10. package/dist/browser/cdp/browser-tab-context-service.js +90 -0
  11. package/dist/browser/cdp/browser-tab-resolution-service.d.ts +9 -0
  12. package/dist/browser/cdp/browser-tab-resolution-service.js +65 -0
  13. package/dist/browser/cdp/browser-tab-screenshot-service.d.ts +20 -0
  14. package/dist/browser/cdp/browser-tab-screenshot-service.js +59 -0
  15. package/dist/browser/cdp/cdp-websocket-session.d.ts +9 -0
  16. package/dist/browser/cdp/cdp-websocket-session.js +99 -0
  17. package/dist/browser/cdp/chrome-cdp-client.d.ts +12 -0
  18. package/dist/browser/cdp/chrome-cdp-client.js +141 -0
  19. package/dist/browser/cdp/live-browser-tab-registry.d.ts +12 -0
  20. package/dist/browser/cdp/live-browser-tab-registry.js +96 -0
  21. package/dist/browser/cdp/png-metadata.d.ts +5 -0
  22. package/dist/browser/cdp/png-metadata.js +16 -0
  23. package/dist/browser/cdp/tab-model.d.ts +33 -0
  24. package/dist/browser/cdp/tab-model.js +15 -0
  25. package/dist/browser/cdp/tab-resolution.d.ts +27 -0
  26. package/dist/browser/cdp/tab-resolution.js +48 -0
  27. package/dist/browser/cdp/types.d.ts +71 -0
  28. package/dist/browser/cdp/types.js +1 -0
  29. package/dist/capture/capture-pipeline.d.ts +5 -0
  30. package/dist/capture/capture-pipeline.js +1 -0
  31. package/dist/capture/create-screen-capture-provider.d.ts +3 -0
  32. package/dist/capture/create-screen-capture-provider.js +8 -0
  33. package/dist/capture/in-memory-capture-pipeline.d.ts +13 -0
  34. package/dist/capture/in-memory-capture-pipeline.js +52 -0
  35. package/dist/capture/in-memory-image-compositor.d.ts +5 -0
  36. package/dist/capture/in-memory-image-compositor.js +34 -0
  37. package/dist/capture/linux-portal-screenshot-provider.d.ts +8 -0
  38. package/dist/capture/linux-portal-screenshot-provider.js +181 -0
  39. package/dist/capture/mock-screen-capture-provider.d.ts +5 -0
  40. package/dist/capture/mock-screen-capture-provider.js +22 -0
  41. package/dist/capture/png-metadata.d.ts +5 -0
  42. package/dist/capture/png-metadata.js +18 -0
  43. package/dist/capture/screen-capture-provider.d.ts +4 -0
  44. package/dist/capture/screen-capture-provider.js +1 -0
  45. package/dist/capture/types.d.ts +38 -0
  46. package/dist/capture/types.js +1 -0
  47. package/dist/cdp-demo.d.ts +1 -0
  48. package/dist/cdp-demo.js +41 -0
  49. package/dist/demo.d.ts +1 -0
  50. package/dist/demo.js +54 -0
  51. package/dist/desktop/capture-now.d.ts +1 -0
  52. package/dist/desktop/capture-now.js +48 -0
  53. package/dist/desktop/controller.d.ts +25 -0
  54. package/dist/desktop/controller.js +77 -0
  55. package/dist/desktop/main.d.ts +1 -0
  56. package/dist/desktop/main.js +80 -0
  57. package/dist/desktop/preload.d.ts +1 -0
  58. package/dist/desktop/preload.js +26 -0
  59. package/dist/desktop/types.d.ts +31 -0
  60. package/dist/desktop/types.js +1 -0
  61. package/dist/errors/app-error.d.ts +7 -0
  62. package/dist/errors/app-error.js +11 -0
  63. package/dist/flow/types.d.ts +48 -0
  64. package/dist/flow/types.js +1 -0
  65. package/dist/flow/visual-capture-flow.d.ts +13 -0
  66. package/dist/flow/visual-capture-flow.js +196 -0
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.js +3 -0
  69. package/dist/logging/logger.d.ts +15 -0
  70. package/dist/logging/logger.js +28 -0
  71. package/dist/mcp/stdio-server.d.ts +19 -0
  72. package/dist/mcp/stdio-server.js +272 -0
  73. package/dist/mcp/tool-registry.d.ts +21 -0
  74. package/dist/mcp/tool-registry.js +33 -0
  75. package/dist/mcp-stdio.d.ts +2 -0
  76. package/dist/mcp-stdio.js +8 -0
  77. package/dist/overlay/local-overlay-agent.d.ts +46 -0
  78. package/dist/overlay/local-overlay-agent.js +551 -0
  79. package/dist/overlay/overlay-bundle-factory.d.ts +4 -0
  80. package/dist/overlay/overlay-bundle-factory.js +24 -0
  81. package/dist/overlay/types.d.ts +83 -0
  82. package/dist/overlay/types.js +1 -0
  83. package/dist/server.d.ts +19 -0
  84. package/dist/server.js +158 -0
  85. package/dist/session/capture-session-service.d.ts +21 -0
  86. package/dist/session/capture-session-service.js +50 -0
  87. package/dist/session/session-manager.d.ts +29 -0
  88. package/dist/session/session-manager.js +217 -0
  89. package/dist/session/session-store.d.ts +8 -0
  90. package/dist/session/session-store.js +15 -0
  91. package/dist/session/session-waiter.d.ts +14 -0
  92. package/dist/session/session-waiter.js +102 -0
  93. package/dist/types/annotation.d.ts +32 -0
  94. package/dist/types/annotation.js +1 -0
  95. package/dist/types/capture.d.ts +33 -0
  96. package/dist/types/capture.js +1 -0
  97. package/dist/types/session.d.ts +36 -0
  98. package/dist/types/session.js +1 -0
  99. package/package.json +38 -0
@@ -0,0 +1,80 @@
1
+ import { app, globalShortcut, screen } from "electron";
2
+ import { OverlayDesktopController } from "./controller.js";
3
+ const controller = new OverlayDesktopController();
4
+ const captureShortcut = "CommandOrControl+Shift+2";
5
+ // Electron's Wayland docs require Chromium's GlobalShortcutsPortal
6
+ // for globalShortcut support in Wayland sessions.
7
+ app.commandLine.appendSwitch("enable-features", "GlobalShortcutsPortal");
8
+ const getDefaultDisplaySelection = () => {
9
+ const display = screen.getPrimaryDisplay();
10
+ const { x, y, width, height } = display.workArea;
11
+ return {
12
+ x,
13
+ y,
14
+ width,
15
+ height,
16
+ displayId: String(display.id),
17
+ activeAppName: "Current Display",
18
+ activeWindowTitle: "Wayland portal capture"
19
+ };
20
+ };
21
+ const triggerActiveWindowCapture = async (payload) => {
22
+ const capturePayload = {
23
+ command: payload?.command ?? "see",
24
+ selection: payload?.selection ?? getDefaultDisplaySelection()
25
+ };
26
+ console.log("[desktop] capture requested", {
27
+ shortcut: captureShortcut,
28
+ command: capturePayload.command,
29
+ selection: capturePayload.selection
30
+ });
31
+ const result = await controller.captureActiveWindow(capturePayload);
32
+ console.log("[desktop] capture completed", {
33
+ stage: result.stage,
34
+ outcome: result.waitResult.outcome,
35
+ sessionId: result.sessionId
36
+ });
37
+ return result;
38
+ };
39
+ const registerShortcuts = () => {
40
+ const registered = globalShortcut.register(captureShortcut, () => {
41
+ console.log("[desktop] hotkey pressed", {
42
+ shortcut: captureShortcut,
43
+ at: new Date().toISOString()
44
+ });
45
+ void triggerActiveWindowCapture().catch((error) => {
46
+ console.error("[desktop] active-window capture failed:", {
47
+ shortcut: captureShortcut,
48
+ error: String(error?.message ?? error)
49
+ });
50
+ });
51
+ });
52
+ console.log("[desktop] shortcut registration", {
53
+ shortcut: captureShortcut,
54
+ registered,
55
+ isRegistered: globalShortcut.isRegistered(captureShortcut),
56
+ sessionType: process.env.XDG_SESSION_TYPE ?? "unknown",
57
+ waylandDisplay: process.env.WAYLAND_DISPLAY ?? "unset",
58
+ display: process.env.DISPLAY ?? "unset"
59
+ });
60
+ if (!registered) {
61
+ console.error("[desktop] shortcut registration failed", {
62
+ shortcut: captureShortcut,
63
+ hint: "On Wayland, this usually means the compositor or portal rejected the global shortcut."
64
+ });
65
+ }
66
+ };
67
+ app.whenReady().then(() => {
68
+ if (process.platform === "darwin") {
69
+ app.dock?.hide();
70
+ }
71
+ registerShortcuts();
72
+ console.log("[desktop] background capture hotkey armed", {
73
+ shortcut: captureShortcut,
74
+ platform: process.platform
75
+ });
76
+ });
77
+ app.on("will-quit", () => {
78
+ console.log("[desktop] unregistering shortcuts");
79
+ globalShortcut.unregisterAll();
80
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { contextBridge, ipcRenderer } from "electron";
2
+ const overlayDesktop = {
3
+ begin: (payload) => ipcRenderer.invoke("overlay:begin", payload),
4
+ getStatus: () => ipcRenderer.invoke("overlay:status"),
5
+ selectRegion: (bounds) => ipcRenderer.invoke("overlay:select-region", bounds),
6
+ setTool: (tool) => ipcRenderer.invoke("overlay:set-tool", tool),
7
+ addAnnotation: (annotation) => ipcRenderer.invoke("overlay:add-annotation", annotation),
8
+ clearAnnotations: () => ipcRenderer.invoke("overlay:clear-annotations"),
9
+ send: () => ipcRenderer.invoke("overlay:send"),
10
+ cancel: () => ipcRenderer.invoke("overlay:cancel"),
11
+ captureActiveWindow: (payload) => ipcRenderer.invoke("overlay:capture-active-window", payload)
12
+ };
13
+ const overlayDesktopEvents = {
14
+ onRefresh: (listener) => {
15
+ ipcRenderer.on("control:refresh", () => {
16
+ listener();
17
+ });
18
+ },
19
+ onError: (listener) => {
20
+ ipcRenderer.on("control:error", (_event, message) => {
21
+ listener(message);
22
+ });
23
+ }
24
+ };
25
+ contextBridge.exposeInMainWorld("overlayDesktop", overlayDesktop);
26
+ contextBridge.exposeInMainWorld("overlayDesktopEvents", overlayDesktopEvents);
@@ -0,0 +1,31 @@
1
+ import type { AwaitVisualCaptureResult, BeginVisualCaptureResult, VisualCaptureStatusResult } from "../flow/types.js";
2
+ import type { Annotation } from "../types/annotation.js";
3
+ import type { SelectionBounds } from "../types/capture.js";
4
+ import type { OverlayTool } from "../overlay/types.js";
5
+ export type OverlayBeginPayload = {
6
+ command?: "see" | "clip";
7
+ };
8
+ export type OverlaySelectRegionPayload = SelectionBounds & {
9
+ displayId?: string;
10
+ activeAppName?: string;
11
+ activeWindowTitle?: string;
12
+ };
13
+ export type ActiveWindowCapturePayload = {
14
+ command?: "see" | "clip";
15
+ selection: OverlaySelectRegionPayload;
16
+ };
17
+ export interface OverlayDesktopApi {
18
+ begin(payload?: OverlayBeginPayload): Promise<BeginVisualCaptureResult>;
19
+ getStatus(): Promise<VisualCaptureStatusResult>;
20
+ selectRegion(bounds: OverlaySelectRegionPayload): Promise<VisualCaptureStatusResult>;
21
+ setTool(tool: OverlayTool): Promise<VisualCaptureStatusResult>;
22
+ addAnnotation(annotation: Annotation): Promise<VisualCaptureStatusResult>;
23
+ clearAnnotations(): Promise<VisualCaptureStatusResult>;
24
+ send(): Promise<AwaitVisualCaptureResult>;
25
+ cancel(): Promise<VisualCaptureStatusResult>;
26
+ captureActiveWindow(payload: ActiveWindowCapturePayload): Promise<AwaitVisualCaptureResult>;
27
+ }
28
+ export interface OverlayDesktopEvents {
29
+ onRefresh(listener: () => void): void;
30
+ onError(listener: (message: string) => void): void;
31
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export type ErrorCode = "INVALID_ARGUMENT" | "NOT_FOUND" | "SESSION_EXPIRED" | "SESSION_CONFLICT" | "INTERNAL_ERROR";
2
+ export declare class AppError extends Error {
3
+ readonly code: ErrorCode;
4
+ readonly details?: Record<string, unknown>;
5
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
6
+ }
7
+ export declare const isAppError: (value: unknown) => value is AppError;
@@ -0,0 +1,11 @@
1
+ export class AppError extends Error {
2
+ code;
3
+ details;
4
+ constructor(code, message, details) {
5
+ super(message);
6
+ this.name = "AppError";
7
+ this.code = code;
8
+ this.details = details;
9
+ }
10
+ }
11
+ export const isAppError = (value) => value instanceof AppError;
@@ -0,0 +1,48 @@
1
+ import type { CaptureBundle, CaptureCommand } from "../types/capture.js";
2
+ import type { OverlaySession } from "../overlay/types.js";
3
+ import type { AwaitCaptureSessionResult, CaptureSession, CaptureSessionStatus } from "../types/session.js";
4
+ export type VisualCaptureStage = "armed" | "selecting" | "annotating" | "ready_to_send" | "completed" | "cancelled" | "failed" | "expired" | "timed_out";
5
+ export type VisualCaptureAction = "switch_to_target" | "select_region" | "annotate" | "send" | "wait" | "done" | "cancel" | "retry";
6
+ export type VisualCaptureGuidance = {
7
+ title: string;
8
+ message: string;
9
+ nextActions: VisualCaptureAction[];
10
+ primaryAction: VisualCaptureAction;
11
+ highlightedShortcut?: string;
12
+ footerHint?: string;
13
+ };
14
+ export type VisualCaptureClientHints = {
15
+ statusTone: "info" | "success" | "warning" | "error";
16
+ showToolbar: boolean;
17
+ showPreview: boolean;
18
+ allowInlineTips: boolean;
19
+ };
20
+ export type BeginVisualCaptureResult = {
21
+ sessionId: string;
22
+ command: CaptureCommand;
23
+ captureSession: CaptureSession;
24
+ overlaySession: OverlaySession;
25
+ stage: VisualCaptureStage;
26
+ guidance: VisualCaptureGuidance;
27
+ clientHints: VisualCaptureClientHints;
28
+ };
29
+ export type VisualCaptureStatusResult = {
30
+ sessionId: string;
31
+ command: CaptureCommand;
32
+ captureStatus: CaptureSessionStatus;
33
+ overlayStatus?: OverlaySession["status"];
34
+ stage: VisualCaptureStage;
35
+ guidance: VisualCaptureGuidance;
36
+ clientHints: VisualCaptureClientHints;
37
+ captureSession: CaptureSession;
38
+ overlaySession?: OverlaySession;
39
+ result?: CaptureBundle;
40
+ };
41
+ export type AwaitVisualCaptureResult = {
42
+ sessionId: string;
43
+ stage: VisualCaptureStage;
44
+ guidance: VisualCaptureGuidance;
45
+ clientHints: VisualCaptureClientHints;
46
+ waitResult: AwaitCaptureSessionResult;
47
+ result?: CaptureBundle;
48
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { LocalOverlayAgent } from "../overlay/local-overlay-agent.js";
2
+ import { CaptureSessionService } from "../session/capture-session-service.js";
3
+ import type { CaptureCommand } from "../types/capture.js";
4
+ import type { AwaitVisualCaptureResult, BeginVisualCaptureResult, VisualCaptureStatusResult } from "./types.js";
5
+ export declare class VisualCaptureFlow {
6
+ private readonly captureSessions;
7
+ private readonly overlayAgent;
8
+ constructor(captureSessions: CaptureSessionService, overlayAgent: LocalOverlayAgent);
9
+ begin(command: CaptureCommand, ttlMs?: number): BeginVisualCaptureResult;
10
+ getStatus(sessionId: string): VisualCaptureStatusResult;
11
+ awaitResult(sessionId: string, timeoutMs?: number): Promise<AwaitVisualCaptureResult>;
12
+ private safeGetOverlaySession;
13
+ }
@@ -0,0 +1,196 @@
1
+ const guidanceForStage = (stage, command, overlaySession) => {
2
+ switch (stage) {
3
+ case "armed":
4
+ return {
5
+ title: `${command} armed`,
6
+ message: "Capture mode is active. Switch to the target app, then start your selection.",
7
+ nextActions: ["switch_to_target", "select_region", "cancel"],
8
+ primaryAction: "switch_to_target",
9
+ footerHint: "The overlay stays armed until you select a region or cancel."
10
+ };
11
+ case "selecting":
12
+ return {
13
+ title: "Select the target area",
14
+ message: "Drag a region around the part of the screen you want the model to inspect.",
15
+ nextActions: ["select_region", "cancel"],
16
+ primaryAction: "select_region",
17
+ highlightedShortcut: overlaySession?.shortcuts.select,
18
+ footerHint: "A tighter crop gives better context and lower payload size."
19
+ };
20
+ case "annotating":
21
+ return {
22
+ title: command === "see" ? "Add guidance for the model" : "Optional markup",
23
+ message: command === "see"
24
+ ? "Use boxes, arrows, text, or redaction to show the model exactly what matters."
25
+ : "You can send now, or add quick annotations if a highlight would help.",
26
+ nextActions: ["annotate", "send", "cancel"],
27
+ primaryAction: command === "see" ? "annotate" : "send",
28
+ highlightedShortcut: overlaySession?.shortcuts[overlaySession?.activeTool ?? "select"],
29
+ footerHint: "Press the tool shortcut once to switch tools quickly."
30
+ };
31
+ case "ready_to_send":
32
+ return {
33
+ title: "Ready to send",
34
+ message: "The selection is ready. Send it back to the LLM when you are satisfied with the preview.",
35
+ nextActions: ["send", "cancel"],
36
+ primaryAction: "send",
37
+ footerHint: "If needed, you can still reposition the selection before sending."
38
+ };
39
+ case "completed":
40
+ return {
41
+ title: "Capture delivered",
42
+ message: "The visual bundle is complete and ready to attach to the current LLM interaction.",
43
+ nextActions: ["done"],
44
+ primaryAction: "done",
45
+ footerHint: "The image remained in memory only and was not persisted by default."
46
+ };
47
+ case "cancelled":
48
+ return {
49
+ title: "Capture cancelled",
50
+ message: "The visual capture flow was cancelled before send.",
51
+ nextActions: ["retry", "done"],
52
+ primaryAction: "retry"
53
+ };
54
+ case "failed":
55
+ return {
56
+ title: "Capture failed",
57
+ message: "The capture flow failed. Review the session error details and retry if needed.",
58
+ nextActions: ["retry", "done"],
59
+ primaryAction: "retry"
60
+ };
61
+ case "expired":
62
+ return {
63
+ title: "Capture expired",
64
+ message: "The capture session expired before completion. Start a new one to continue.",
65
+ nextActions: ["retry", "done"],
66
+ primaryAction: "retry"
67
+ };
68
+ case "timed_out":
69
+ return {
70
+ title: "Still waiting",
71
+ message: "The client-side wait timed out, but the capture session may still be active.",
72
+ nextActions: ["wait", "cancel", "done"],
73
+ primaryAction: "wait",
74
+ footerHint: "Use getVisualCaptureStatus to refresh the UI without losing progress."
75
+ };
76
+ }
77
+ };
78
+ const clientHintsForStage = (stage) => {
79
+ switch (stage) {
80
+ case "completed":
81
+ return { statusTone: "success", showToolbar: false, showPreview: true, allowInlineTips: false };
82
+ case "failed":
83
+ return { statusTone: "error", showToolbar: false, showPreview: false, allowInlineTips: true };
84
+ case "cancelled":
85
+ case "expired":
86
+ return { statusTone: "warning", showToolbar: false, showPreview: false, allowInlineTips: true };
87
+ case "timed_out":
88
+ return { statusTone: "warning", showToolbar: true, showPreview: true, allowInlineTips: true };
89
+ case "armed":
90
+ case "selecting":
91
+ return { statusTone: "info", showToolbar: true, showPreview: false, allowInlineTips: true };
92
+ case "annotating":
93
+ case "ready_to_send":
94
+ return { statusTone: "info", showToolbar: true, showPreview: true, allowInlineTips: true };
95
+ }
96
+ };
97
+ const deriveStage = (command, captureSession, overlaySession) => {
98
+ if (captureSession.status === "completed") {
99
+ return "completed";
100
+ }
101
+ if (captureSession.status === "cancelled") {
102
+ return "cancelled";
103
+ }
104
+ if (captureSession.status === "failed") {
105
+ return "failed";
106
+ }
107
+ if (captureSession.status === "expired") {
108
+ return "expired";
109
+ }
110
+ if (!overlaySession) {
111
+ return "armed";
112
+ }
113
+ if (overlaySession.status === "armed") {
114
+ return "selecting";
115
+ }
116
+ if (overlaySession.status === "selected") {
117
+ const hasAnnotations = overlaySession.annotationSummary.total > 0;
118
+ return hasAnnotations || command === "see" ? "annotating" : "ready_to_send";
119
+ }
120
+ if (overlaySession.status === "sent") {
121
+ return "completed";
122
+ }
123
+ if (overlaySession.status === "cancelled") {
124
+ return "cancelled";
125
+ }
126
+ if (overlaySession.status === "failed") {
127
+ return "failed";
128
+ }
129
+ if (overlaySession.status === "expired") {
130
+ return "expired";
131
+ }
132
+ return "armed";
133
+ };
134
+ export class VisualCaptureFlow {
135
+ captureSessions;
136
+ overlayAgent;
137
+ constructor(captureSessions, overlayAgent) {
138
+ this.captureSessions = captureSessions;
139
+ this.overlayAgent = overlayAgent;
140
+ }
141
+ begin(command, ttlMs) {
142
+ const captureSession = this.captureSessions.startSession({ command, ttlMs });
143
+ const overlaySession = this.overlayAgent.launch(captureSession.id);
144
+ const stage = deriveStage(command, captureSession, overlaySession);
145
+ return {
146
+ sessionId: captureSession.id,
147
+ command,
148
+ captureSession,
149
+ overlaySession,
150
+ stage,
151
+ guidance: guidanceForStage(stage, command, overlaySession),
152
+ clientHints: clientHintsForStage(stage)
153
+ };
154
+ }
155
+ getStatus(sessionId) {
156
+ const captureSession = this.captureSessions.getSession(sessionId);
157
+ const overlaySession = this.safeGetOverlaySession(sessionId);
158
+ const stage = deriveStage(captureSession.command, captureSession, overlaySession);
159
+ return {
160
+ sessionId,
161
+ command: captureSession.command,
162
+ captureStatus: captureSession.status,
163
+ overlayStatus: overlaySession?.status,
164
+ stage,
165
+ guidance: guidanceForStage(stage, captureSession.command, overlaySession),
166
+ clientHints: clientHintsForStage(stage),
167
+ captureSession,
168
+ overlaySession,
169
+ result: captureSession.result
170
+ };
171
+ }
172
+ async awaitResult(sessionId, timeoutMs) {
173
+ const waitResult = await this.captureSessions.awaitSession({ sessionId, timeoutMs });
174
+ const command = waitResult.session.command;
175
+ const overlaySession = this.safeGetOverlaySession(sessionId);
176
+ const stage = waitResult.outcome === "timed_out"
177
+ ? "timed_out"
178
+ : deriveStage(command, waitResult.session, overlaySession);
179
+ return {
180
+ sessionId,
181
+ stage,
182
+ guidance: guidanceForStage(stage, command, overlaySession),
183
+ clientHints: clientHintsForStage(stage),
184
+ waitResult,
185
+ result: waitResult.outcome === "completed" ? waitResult.result : undefined
186
+ };
187
+ }
188
+ safeGetOverlaySession(sessionId) {
189
+ try {
190
+ return this.overlayAgent.get(sessionId);
191
+ }
192
+ catch {
193
+ return undefined;
194
+ }
195
+ }
196
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { VisualContextServer } from "./server.js";
2
+ const server = new VisualContextServer();
3
+ server.start();
@@ -0,0 +1,15 @@
1
+ export interface Logger {
2
+ debug(message: string, context?: Record<string, unknown>): void;
3
+ info(message: string, context?: Record<string, unknown>): void;
4
+ warn(message: string, context?: Record<string, unknown>): void;
5
+ error(message: string, context?: Record<string, unknown>): void;
6
+ }
7
+ export declare class ConsoleLogger implements Logger {
8
+ private readonly scope;
9
+ constructor(scope: string);
10
+ debug(message: string, context?: Record<string, unknown>): void;
11
+ info(message: string, context?: Record<string, unknown>): void;
12
+ warn(message: string, context?: Record<string, unknown>): void;
13
+ error(message: string, context?: Record<string, unknown>): void;
14
+ private write;
15
+ }
@@ -0,0 +1,28 @@
1
+ export class ConsoleLogger {
2
+ scope;
3
+ constructor(scope) {
4
+ this.scope = scope;
5
+ }
6
+ debug(message, context) {
7
+ this.write("debug", message, context);
8
+ }
9
+ info(message, context) {
10
+ this.write("info", message, context);
11
+ }
12
+ warn(message, context) {
13
+ this.write("warn", message, context);
14
+ }
15
+ error(message, context) {
16
+ this.write("error", message, context);
17
+ }
18
+ write(level, message, context) {
19
+ const payload = {
20
+ time: new Date().toISOString(),
21
+ level,
22
+ scope: this.scope,
23
+ message,
24
+ ...(context ? { context } : {})
25
+ };
26
+ process.stderr.write(`${JSON.stringify(payload)}\n`);
27
+ }
28
+ }
@@ -0,0 +1,19 @@
1
+ import type { Logger } from "../logging/logger.js";
2
+ import type { VisualContextServer } from "../server.js";
3
+ export declare class McpStdioServer {
4
+ private readonly app;
5
+ private readonly logger;
6
+ private readonly input;
7
+ private readonly output;
8
+ private buffer;
9
+ private initialized;
10
+ constructor(app: VisualContextServer, logger: Logger, input?: NodeJS.ReadStream & {
11
+ fd: 0;
12
+ }, output?: NodeJS.WriteStream & {
13
+ fd: 1;
14
+ });
15
+ start(): void;
16
+ private processBuffer;
17
+ private handleMessage;
18
+ private writeMessage;
19
+ }