codeloop-mcp-server 0.1.4 → 0.1.6

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 (79) hide show
  1. package/dist/auth/usage_tracker.d.ts +1 -1
  2. package/dist/auth/usage_tracker.d.ts.map +1 -1
  3. package/dist/auth/usage_tracker.js.map +1 -1
  4. package/dist/index.js +978 -40
  5. package/dist/index.js.map +1 -1
  6. package/dist/project-discovery.d.ts +17 -0
  7. package/dist/project-discovery.d.ts.map +1 -0
  8. package/dist/project-discovery.js +109 -0
  9. package/dist/project-discovery.js.map +1 -0
  10. package/dist/runners/app_logger.d.ts +41 -0
  11. package/dist/runners/app_logger.d.ts.map +1 -0
  12. package/dist/runners/app_logger.js +276 -0
  13. package/dist/runners/app_logger.js.map +1 -0
  14. package/dist/runners/base.d.ts.map +1 -1
  15. package/dist/runners/base.js +4 -2
  16. package/dist/runners/base.js.map +1 -1
  17. package/dist/runners/browser_interaction.d.ts +27 -0
  18. package/dist/runners/browser_interaction.d.ts.map +1 -0
  19. package/dist/runners/browser_interaction.js +294 -0
  20. package/dist/runners/browser_interaction.js.map +1 -0
  21. package/dist/runners/flutter.d.ts +1 -0
  22. package/dist/runners/flutter.d.ts.map +1 -1
  23. package/dist/runners/flutter.js +29 -0
  24. package/dist/runners/flutter.js.map +1 -1
  25. package/dist/runners/maestro_generator.d.ts +11 -0
  26. package/dist/runners/maestro_generator.d.ts.map +1 -0
  27. package/dist/runners/maestro_generator.js +79 -0
  28. package/dist/runners/maestro_generator.js.map +1 -0
  29. package/dist/runners/platform_detect.d.ts +14 -0
  30. package/dist/runners/platform_detect.d.ts.map +1 -0
  31. package/dist/runners/platform_detect.js +102 -0
  32. package/dist/runners/platform_detect.js.map +1 -0
  33. package/dist/runners/screenshot.d.ts +3 -7
  34. package/dist/runners/screenshot.d.ts.map +1 -1
  35. package/dist/runners/screenshot.js +155 -28
  36. package/dist/runners/screenshot.js.map +1 -1
  37. package/dist/runners/video_recorder.d.ts +49 -0
  38. package/dist/runners/video_recorder.d.ts.map +1 -0
  39. package/dist/runners/video_recorder.js +489 -0
  40. package/dist/runners/video_recorder.js.map +1 -0
  41. package/dist/runners/video_validator.d.ts +16 -0
  42. package/dist/runners/video_validator.d.ts.map +1 -0
  43. package/dist/runners/video_validator.js +123 -0
  44. package/dist/runners/video_validator.js.map +1 -0
  45. package/dist/runners/win_accessibility.d.ts +12 -0
  46. package/dist/runners/win_accessibility.d.ts.map +1 -0
  47. package/dist/runners/win_accessibility.js +101 -0
  48. package/dist/runners/win_accessibility.js.map +1 -0
  49. package/dist/runners/window_manager.d.ts +81 -0
  50. package/dist/runners/window_manager.d.ts.map +1 -0
  51. package/dist/runners/window_manager.js +1010 -0
  52. package/dist/runners/window_manager.js.map +1 -0
  53. package/dist/tools/design_compare.d.ts +1 -1
  54. package/dist/tools/design_compare.d.ts.map +1 -1
  55. package/dist/tools/design_compare.js +1 -2
  56. package/dist/tools/design_compare.js.map +1 -1
  57. package/dist/tools/discover_screens.d.ts +3 -3
  58. package/dist/tools/discover_screens.d.ts.map +1 -1
  59. package/dist/tools/discover_screens.js +140 -157
  60. package/dist/tools/discover_screens.js.map +1 -1
  61. package/dist/tools/gate_check.d.ts.map +1 -1
  62. package/dist/tools/gate_check.js +100 -5
  63. package/dist/tools/gate_check.js.map +1 -1
  64. package/dist/tools/init-project.d.ts +15 -0
  65. package/dist/tools/init-project.d.ts.map +1 -0
  66. package/dist/tools/init-project.js +273 -0
  67. package/dist/tools/init-project.js.map +1 -0
  68. package/dist/tools/interaction_replay.d.ts +8 -1
  69. package/dist/tools/interaction_replay.d.ts.map +1 -1
  70. package/dist/tools/interaction_replay.js +78 -2
  71. package/dist/tools/interaction_replay.js.map +1 -1
  72. package/dist/tools/verify.d.ts.map +1 -1
  73. package/dist/tools/verify.js +204 -53
  74. package/dist/tools/verify.js.map +1 -1
  75. package/dist/tools/visual_review.d.ts +1 -1
  76. package/dist/tools/visual_review.d.ts.map +1 -1
  77. package/dist/tools/visual_review.js +1 -2
  78. package/dist/tools/visual_review.js.map +1 -1
  79. package/package.json +1 -1
@@ -0,0 +1,102 @@
1
+ import { existsSync, readFileSync, readdirSync } from "fs";
2
+ import { join } from "path";
3
+ import { platform } from "os";
4
+ /**
5
+ * Auto-detect the target type for video recording and interaction based on
6
+ * the project structure and host OS.
7
+ *
8
+ * Detection priority:
9
+ * 1. Flutter project (pubspec.yaml) → check which platform is targeted
10
+ * 2. Xcode project (.xcodeproj) → ios_simulator (macOS only)
11
+ * 3. Android project (build.gradle) → android_emulator
12
+ * 4. Web project (package.json with web framework) → browser
13
+ * 5. Default → desktop
14
+ */
15
+ export async function detectTargetType(cwd) {
16
+ // Flutter project detection
17
+ const pubspecPath = join(cwd, "pubspec.yaml");
18
+ if (existsSync(pubspecPath)) {
19
+ return detectFlutterTargetType(cwd, pubspecPath);
20
+ }
21
+ // Xcode project (native iOS/macOS)
22
+ if (hasFileWithExtension(cwd, ".xcodeproj") || hasFileWithExtension(cwd, ".xcworkspace")) {
23
+ const os = platform();
24
+ if (os === "darwin") {
25
+ // Check if it's a macOS app (look for macOS target) or iOS app
26
+ if (existsSync(join(cwd, "macos")))
27
+ return "desktop";
28
+ return "ios_simulator";
29
+ }
30
+ return "desktop";
31
+ }
32
+ // Android project (native)
33
+ if (existsSync(join(cwd, "build.gradle")) || existsSync(join(cwd, "build.gradle.kts")) ||
34
+ existsSync(join(cwd, "app", "build.gradle")) || existsSync(join(cwd, "app", "build.gradle.kts"))) {
35
+ return "android_emulator";
36
+ }
37
+ // Web project
38
+ const packageJsonPath = join(cwd, "package.json");
39
+ if (existsSync(packageJsonPath)) {
40
+ try {
41
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
42
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
43
+ const webFrameworks = [
44
+ "react", "next", "vue", "nuxt", "svelte", "@sveltejs/kit",
45
+ "angular", "@angular/core", "gatsby", "remix", "astro", "vite",
46
+ ];
47
+ if (webFrameworks.some(fw => fw in deps)) {
48
+ return "browser";
49
+ }
50
+ }
51
+ catch { /* ignore parse errors */ }
52
+ }
53
+ return "desktop";
54
+ }
55
+ function detectFlutterTargetType(cwd, _pubspecPath) {
56
+ const os = platform();
57
+ // Check which platform directories exist in the Flutter project
58
+ const hasAndroid = existsSync(join(cwd, "android"));
59
+ const hasIos = existsSync(join(cwd, "ios"));
60
+ const hasMacos = existsSync(join(cwd, "macos"));
61
+ const hasWindows = existsSync(join(cwd, "windows"));
62
+ const hasLinux = existsSync(join(cwd, "linux"));
63
+ const hasWeb = existsSync(join(cwd, "web"));
64
+ // Prefer the platform that matches the host OS
65
+ if (os === "darwin") {
66
+ if (hasMacos)
67
+ return "desktop";
68
+ if (hasIos)
69
+ return "ios_simulator";
70
+ if (hasWeb)
71
+ return "browser";
72
+ if (hasAndroid)
73
+ return "android_emulator";
74
+ }
75
+ else if (os === "win32") {
76
+ if (hasWindows)
77
+ return "desktop";
78
+ if (hasAndroid)
79
+ return "android_emulator";
80
+ if (hasWeb)
81
+ return "browser";
82
+ }
83
+ else {
84
+ if (hasLinux)
85
+ return "desktop";
86
+ if (hasAndroid)
87
+ return "android_emulator";
88
+ if (hasWeb)
89
+ return "browser";
90
+ }
91
+ return "desktop";
92
+ }
93
+ function hasFileWithExtension(dir, ext) {
94
+ try {
95
+ const entries = readdirSync(dir);
96
+ return entries.some(e => e.endsWith(ext));
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ }
102
+ //# sourceMappingURL=platform_detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform_detect.js","sourceRoot":"","sources":["../../src/runners/platform_detect.ts"],"names":[],"mappings":"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"}
@@ -5,13 +5,9 @@ export interface ScreenshotResult {
5
5
  error?: string;
6
6
  }
7
7
  /**
8
- * Capture a screenshot of the current screen/display.
9
- * Cross-platform: macOS (screencapture), Windows (PowerShell), Linux (import/gnome-screenshot).
10
- * Falls back gracefully if no capture tool is available.
11
- */
12
- export declare function captureScreenshot(outputDir: string, label?: string): Promise<ScreenshotResult>;
13
- /**
14
- * List all PNG screenshots already present in a directory.
8
+ * Capture a screenshot. If appName is provided, brings the app to front,
9
+ * captures only that app's window, then restores the previous frontmost app.
15
10
  */
11
+ export declare function captureScreenshot(outputDir: string, label?: string, appName?: string, targetType?: string): Promise<ScreenshotResult>;
16
12
  export declare function listScreenshots(dir: string): string[];
17
13
  //# sourceMappingURL=screenshot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/runners/screenshot.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,MAAiB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAW3B;AAsFD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAMrD"}
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/runners/screenshot.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,MAAiB,EACxB,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,gBAAgB,CAAC,CAmB3B;AA0ND,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAMrD"}
@@ -1,32 +1,98 @@
1
- import { existsSync, readdirSync } from "fs";
1
+ import { existsSync, readdirSync, mkdirSync } from "fs";
2
2
  import { join } from "path";
3
3
  import { platform } from "os";
4
4
  import { runCommand, checkToolAvailable } from "./base.js";
5
+ import { findWindowId, bringAppToFront, restorePreviousApp } from "./window_manager.js";
5
6
  /**
6
- * Capture a screenshot of the current screen/display.
7
- * Cross-platform: macOS (screencapture), Windows (PowerShell), Linux (import/gnome-screenshot).
8
- * Falls back gracefully if no capture tool is available.
7
+ * Capture a screenshot. If appName is provided, brings the app to front,
8
+ * captures only that app's window, then restores the previous frontmost app.
9
9
  */
10
- export async function captureScreenshot(outputDir, label = "screen") {
10
+ export async function captureScreenshot(outputDir, label = "screen", appName, targetType) {
11
+ mkdirSync(outputDir, { recursive: true });
11
12
  const outputPath = join(outputDir, `${label}_${Date.now()}.png`);
12
13
  const os = platform();
14
+ if (targetType === "android_emulator") {
15
+ return captureAndroidEmulator(outputPath);
16
+ }
17
+ if (targetType === "ios_simulator") {
18
+ return captureiOSSimulator(outputPath);
19
+ }
13
20
  if (os === "darwin") {
14
- return captureMacOS(outputPath);
21
+ return captureMacOS(outputPath, appName);
15
22
  }
16
23
  else if (os === "win32") {
17
- return captureWindows(outputPath);
24
+ return captureWindows(outputPath, appName);
18
25
  }
19
26
  else {
20
- return captureLinux(outputPath);
27
+ return captureLinux(outputPath, appName);
28
+ }
29
+ }
30
+ async function captureAndroidEmulator(outputPath) {
31
+ if (!(await checkToolAvailable("adb"))) {
32
+ return { captured: false, paths: [], method: "adb", error: "adb not found" };
33
+ }
34
+ const result = await runCommand("adb", ["exec-out", "screencap", "-p"], process.cwd());
35
+ if (result.exit_code === 0) {
36
+ try {
37
+ const { writeFileSync: wf } = await import("fs");
38
+ wf(outputPath, Buffer.from(result.stdout, "binary"));
39
+ if (existsSync(outputPath)) {
40
+ return { captured: true, paths: [outputPath], method: "adb exec-out screencap" };
41
+ }
42
+ }
43
+ catch { /* fallthrough */ }
44
+ }
45
+ // Fallback: use adb shell screencap + pull
46
+ await runCommand("adb", ["shell", "screencap", "-p", "/sdcard/codeloop_ss.png"], process.cwd());
47
+ const pullResult = await runCommand("adb", ["pull", "/sdcard/codeloop_ss.png", outputPath], process.cwd());
48
+ await runCommand("adb", ["shell", "rm", "/sdcard/codeloop_ss.png"], process.cwd());
49
+ if (pullResult.exit_code === 0 && existsSync(outputPath)) {
50
+ return { captured: true, paths: [outputPath], method: "adb shell screencap + pull" };
21
51
  }
52
+ return { captured: false, paths: [], method: "adb", error: "Android screenshot capture failed" };
22
53
  }
23
- async function captureMacOS(outputPath) {
54
+ async function captureiOSSimulator(outputPath) {
55
+ if (!(await checkToolAvailable("xcrun"))) {
56
+ return { captured: false, paths: [], method: "xcrun", error: "xcrun not found" };
57
+ }
58
+ const result = await runCommand("xcrun", ["simctl", "io", "booted", "screenshot", outputPath], process.cwd());
59
+ if (result.exit_code === 0 && existsSync(outputPath)) {
60
+ return { captured: true, paths: [outputPath], method: "xcrun simctl io screenshot" };
61
+ }
62
+ return { captured: false, paths: [], method: "xcrun simctl", error: result.stderr || "iOS Simulator screenshot failed" };
63
+ }
64
+ async function captureMacOS(outputPath, appName) {
24
65
  if (!(await checkToolAvailable("screencapture"))) {
25
66
  return { captured: false, paths: [], method: "screencapture", error: "screencapture not found" };
26
67
  }
68
+ if (appName) {
69
+ const windowId = await findWindowId(appName);
70
+ if (windowId) {
71
+ const wResult = await runCommand("screencapture", ["-l", windowId, "-x", "-o", outputPath], process.cwd());
72
+ if (wResult.exit_code === 0 && existsSync(outputPath)) {
73
+ return { captured: true, paths: [outputPath], method: `screencapture -l ${windowId} (window: ${appName})` };
74
+ }
75
+ }
76
+ const previousApp = await bringAppToFront(appName);
77
+ const fResult = await runCommand("screencapture", ["-x", "-o", outputPath], process.cwd());
78
+ const captured = fResult.exit_code === 0 && existsSync(outputPath);
79
+ if (previousApp && previousApp !== appName) {
80
+ await restorePreviousApp(previousApp);
81
+ }
82
+ if (captured) {
83
+ const hint = windowId
84
+ ? ". Tip: Grant Screen Recording permission (System Settings > Privacy & Security > Screen Recording) for window-only capture"
85
+ : "";
86
+ return { captured: true, paths: [outputPath], method: `screencapture (app "${appName}" brought to front, then restored)${hint}` };
87
+ }
88
+ }
27
89
  const result = await runCommand("screencapture", ["-x", "-o", outputPath], process.cwd());
28
90
  if (result.exit_code === 0 && existsSync(outputPath)) {
29
- return { captured: true, paths: [outputPath], method: "screencapture" };
91
+ return {
92
+ captured: true,
93
+ paths: [outputPath],
94
+ method: appName ? `screencapture (full screen — could not find window "${appName}")` : "screencapture (full screen)",
95
+ };
30
96
  }
31
97
  return {
32
98
  captured: false,
@@ -35,8 +101,53 @@ async function captureMacOS(outputPath) {
35
101
  error: result.stderr || `screencapture exited with code ${result.exit_code}`,
36
102
  };
37
103
  }
38
- async function captureWindows(outputPath) {
39
- const script = `
104
+ async function captureWindows(outputPath, appName) {
105
+ const hasPowershell = await checkToolAvailable("powershell");
106
+ if (!hasPowershell) {
107
+ return { captured: false, paths: [], method: "powershell", error: "powershell not found" };
108
+ }
109
+ let previousApp = "";
110
+ if (appName) {
111
+ previousApp = await bringAppToFront(appName);
112
+ }
113
+ let script;
114
+ if (appName) {
115
+ script = `
116
+ Add-Type -AssemblyName System.Windows.Forms
117
+ Add-Type -AssemblyName System.Drawing
118
+ Add-Type @"
119
+ using System;
120
+ using System.Runtime.InteropServices;
121
+ public class Win32 {
122
+ [DllImport("user32.dll")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
123
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
124
+ [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
125
+ }
126
+ "@
127
+ $procs = Get-Process | Where-Object { $_.MainWindowTitle -match '${appName}' -and $_.MainWindowHandle -ne 0 }
128
+ if ($procs.Count -gt 0) {
129
+ $hwnd = $procs[0].MainWindowHandle
130
+ $rect = New-Object Win32+RECT
131
+ [Win32]::GetWindowRect($hwnd, [ref]$rect)
132
+ $w = $rect.Right - $rect.Left
133
+ $h = $rect.Bottom - $rect.Top
134
+ $bitmap = New-Object System.Drawing.Bitmap($w, $h)
135
+ $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
136
+ $graphics.CopyFromScreen($rect.Left, $rect.Top, 0, 0, (New-Object System.Drawing.Size($w, $h)))
137
+ $bitmap.Save('${outputPath.replace(/\\/g, "\\\\")}', [System.Drawing.Imaging.ImageFormat]::Png)
138
+ $graphics.Dispose(); $bitmap.Dispose()
139
+ } else {
140
+ $screen = [System.Windows.Forms.Screen]::PrimaryScreen
141
+ $bitmap = New-Object System.Drawing.Bitmap($screen.Bounds.Width, $screen.Bounds.Height)
142
+ $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
143
+ $graphics.CopyFromScreen($screen.Bounds.Location, [System.Drawing.Point]::Empty, $screen.Bounds.Size)
144
+ $bitmap.Save('${outputPath.replace(/\\/g, "\\\\")}', [System.Drawing.Imaging.ImageFormat]::Png)
145
+ $graphics.Dispose(); $bitmap.Dispose()
146
+ }
147
+ `;
148
+ }
149
+ else {
150
+ script = `
40
151
  Add-Type -AssemblyName System.Windows.Forms
41
152
  Add-Type -AssemblyName System.Drawing
42
153
  $screen = [System.Windows.Forms.Screen]::PrimaryScreen
@@ -44,16 +155,15 @@ $bitmap = New-Object System.Drawing.Bitmap($screen.Bounds.Width, $screen.Bounds.
44
155
  $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
45
156
  $graphics.CopyFromScreen($screen.Bounds.Location, [System.Drawing.Point]::Empty, $screen.Bounds.Size)
46
157
  $bitmap.Save('${outputPath.replace(/\\/g, "\\\\")}', [System.Drawing.Imaging.ImageFormat]::Png)
47
- $graphics.Dispose()
48
- $bitmap.Dispose()
158
+ $graphics.Dispose(); $bitmap.Dispose()
49
159
  `;
50
- const hasPowershell = await checkToolAvailable("powershell");
51
- if (!hasPowershell) {
52
- return { captured: false, paths: [], method: "powershell", error: "powershell not found" };
53
160
  }
54
161
  const result = await runCommand("powershell", ["-NoProfile", "-Command", script], process.cwd());
162
+ if (previousApp && previousApp !== appName) {
163
+ await restorePreviousApp(previousApp);
164
+ }
55
165
  if (result.exit_code === 0 && existsSync(outputPath)) {
56
- return { captured: true, paths: [outputPath], method: "powershell" };
166
+ return { captured: true, paths: [outputPath], method: appName ? `powershell (window: ${appName})` : "powershell (full screen)" };
57
167
  }
58
168
  return {
59
169
  captured: false,
@@ -62,25 +172,45 @@ $bitmap.Dispose()
62
172
  error: result.stderr || `powershell exited with code ${result.exit_code}`,
63
173
  };
64
174
  }
65
- async function captureLinux(outputPath) {
66
- if (await checkToolAvailable("import")) {
175
+ async function captureLinux(outputPath, appName) {
176
+ let previousApp = "";
177
+ if (appName) {
178
+ previousApp = await bringAppToFront(appName);
179
+ }
180
+ let captured = false;
181
+ if (appName && (await checkToolAvailable("xdotool")) && (await checkToolAvailable("import"))) {
182
+ const windowId = await findWindowId(appName);
183
+ if (windowId) {
184
+ const result = await runCommand("import", ["-window", windowId, outputPath], process.cwd());
185
+ if (result.exit_code === 0 && existsSync(outputPath)) {
186
+ captured = true;
187
+ }
188
+ }
189
+ }
190
+ if (!captured && (await checkToolAvailable("import"))) {
67
191
  const result = await runCommand("import", ["-window", "root", outputPath], process.cwd());
68
192
  if (result.exit_code === 0 && existsSync(outputPath)) {
69
- return { captured: true, paths: [outputPath], method: "import (ImageMagick)" };
193
+ captured = true;
70
194
  }
71
195
  }
72
- if (await checkToolAvailable("gnome-screenshot")) {
196
+ if (!captured && (await checkToolAvailable("gnome-screenshot"))) {
73
197
  const result = await runCommand("gnome-screenshot", ["-f", outputPath], process.cwd());
74
198
  if (result.exit_code === 0 && existsSync(outputPath)) {
75
- return { captured: true, paths: [outputPath], method: "gnome-screenshot" };
199
+ captured = true;
76
200
  }
77
201
  }
78
- if (await checkToolAvailable("scrot")) {
202
+ if (!captured && (await checkToolAvailable("scrot"))) {
79
203
  const result = await runCommand("scrot", [outputPath], process.cwd());
80
204
  if (result.exit_code === 0 && existsSync(outputPath)) {
81
- return { captured: true, paths: [outputPath], method: "scrot" };
205
+ captured = true;
82
206
  }
83
207
  }
208
+ if (previousApp && previousApp !== appName) {
209
+ await restorePreviousApp(previousApp);
210
+ }
211
+ if (captured) {
212
+ return { captured: true, paths: [outputPath], method: appName ? `screenshot (window: ${appName})` : "screenshot (full screen)" };
213
+ }
84
214
  return {
85
215
  captured: false,
86
216
  paths: [],
@@ -88,9 +218,6 @@ async function captureLinux(outputPath) {
88
218
  error: "No screenshot tool found (tried: import, gnome-screenshot, scrot)",
89
219
  };
90
220
  }
91
- /**
92
- * List all PNG screenshots already present in a directory.
93
- */
94
221
  export function listScreenshots(dir) {
95
222
  if (!existsSync(dir))
96
223
  return [];
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/runners/screenshot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/runners/screenshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { TargetType } from "./window_manager.js";
2
+ export interface VideoRecordResult {
3
+ recorded: boolean;
4
+ path: string;
5
+ duration_seconds: number;
6
+ method: string;
7
+ error?: string;
8
+ }
9
+ export interface BackgroundRecordingHandle {
10
+ recording_id: string;
11
+ output_path: string;
12
+ app_name: string;
13
+ previous_app: string;
14
+ started_at: number;
15
+ target_type: TargetType;
16
+ log_capture: boolean;
17
+ }
18
+ /**
19
+ * Blocking video recording. Brings app to front, records for a fixed
20
+ * duration, then restores the previous frontmost app.
21
+ */
22
+ export declare function recordVideo(outputDir: string, durationSeconds?: number, appName?: string): Promise<VideoRecordResult & {
23
+ log_path?: string;
24
+ }>;
25
+ /**
26
+ * Start recording in the background. Returns a handle immediately so the
27
+ * agent can interact with the app while recording is active.
28
+ * Call stopBackgroundRecording() when done.
29
+ *
30
+ * targetType selects the capture method:
31
+ * - "desktop": ffmpeg screen capture (macOS/Windows/Linux)
32
+ * - "android_emulator": adb shell screenrecord
33
+ * - "ios_simulator": xcrun simctl io booted recordVideo
34
+ * - "browser": ffmpeg or Playwright recordVideo
35
+ */
36
+ export declare function startBackgroundRecording(outputDir: string, appName: string, maxDurationSeconds?: number, targetType?: TargetType): Promise<BackgroundRecordingHandle | {
37
+ error: string;
38
+ }>;
39
+ /**
40
+ * Stop a background recording. Sends SIGINT to finalize the video file,
41
+ * then restores the previous frontmost app.
42
+ * For Android, pulls the recorded file from the device.
43
+ */
44
+ export declare function stopBackgroundRecording(recordingId: string): Promise<VideoRecordResult & {
45
+ log_path?: string;
46
+ }>;
47
+ /** List all active background recordings. */
48
+ export declare function listActiveRecordings(): string[];
49
+ //# sourceMappingURL=video_recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video_recorder.d.ts","sourceRoot":"","sources":["../../src/runners/video_recorder.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAgFtD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;CACtB;AAaD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,MAAW,EAC5B,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,iBAAiB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCpD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,kBAAkB,GAAE,MAAY,EAChC,UAAU,GAAE,UAAsB,GACjC,OAAO,CAAC,yBAAyB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA+LxD;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqFpD;AAED,6CAA6C;AAC7C,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C"}