@tantawowa/hosanna-tools 3.10.0 → 3.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -8
- package/dist/build-info.json +3 -3
- package/dist/capture/index.d.ts +2 -0
- package/dist/capture/index.js +16 -0
- package/dist/capture/index.js.map +1 -0
- package/dist/capture/mcp-tools.d.ts +6 -0
- package/dist/capture/mcp-tools.js +106 -0
- package/dist/capture/mcp-tools.js.map +1 -0
- package/dist/capture/video-capture.d.ts +160 -0
- package/dist/capture/video-capture.js +546 -0
- package/dist/capture/video-capture.js.map +1 -0
- package/dist/cli.js +118 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/run/android-emulator.js +1 -0
- package/dist/run/android-emulator.js.map +1 -1
- package/dist/run/run-controller.js +1 -0
- package/dist/run/run-controller.js.map +1 -1
- package/dist/support-tools/mcp-server/index.js +3 -0
- package/dist/support-tools/mcp-server/index.js.map +1 -1
- package/dist/support-tools/mcp-server/tools.js +2 -0
- package/dist/support-tools/mcp-server/tools.js.map +1 -1
- package/dist/testing/client.js +8 -0
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/global-setup.js +4 -1
- package/dist/testing/global-setup.js.map +1 -1
- package/dist/testing/launcher.d.ts +1 -0
- package/dist/testing/launcher.js +155 -22
- package/dist/testing/launcher.js.map +1 -1
- package/dist/testing/native-simulator.d.ts +41 -0
- package/dist/testing/native-simulator.js +202 -0
- package/dist/testing/native-simulator.js.map +1 -0
- package/dist/testing/types.d.ts +25 -6
- package/dist/testing/vitest-reporter.d.mts +1 -1
- package/dist/testing/vitest-reporter.mjs +36 -3
- package/dist/testing/vitest-reporter.mjs.map +1 -1
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
## Documentation
|
|
4
4
|
|
|
5
5
|
- **[MCP debugger](src/support-tools/mcp-server/README.md)** — `hst mcp:start`, debugger tools, commands by use case, examples, and RASP certification capture.
|
|
6
|
+
- **[Video capture](docs/video-capture.md)** — standalone, agent-driven, and test-run recording for Apple simulators, Roku capture cards, and macOS windows.
|
|
6
7
|
- **[docs/README.md](docs/README.md)** — index of docs in this repo (MCP + source-map note).
|
|
7
8
|
- **hosanna-ui** (separate repo): `docs/README.md` for agentic debugging and links back to this README.
|
|
8
9
|
|
|
@@ -64,7 +65,7 @@ symlink. Granular flavours and platform subsets are deliberately rejected with
|
|
|
64
65
|
Hosanna Tools can also be imported by app build chains. The CLI remains available as `hst`, but package imports are library-safe and do not parse CLI arguments or call `process.exit` during import. Public wrappers for process-oriented commands use no-exit mode where supported, so API callers receive structured results or thrown errors instead of forced process termination.
|
|
65
66
|
|
|
66
67
|
```ts
|
|
67
|
-
import { buildConfig, compiler, env, generate, roku, secrets } from '@tantawowa/hosanna-tools';
|
|
68
|
+
import { buildConfig, capture, compiler, env, generate, roku, secrets } from '@tantawowa/hosanna-tools';
|
|
68
69
|
|
|
69
70
|
await generate.all({
|
|
70
71
|
rootFolder: './src',
|
|
@@ -80,6 +81,10 @@ await buildConfig.resolve({
|
|
|
80
81
|
|
|
81
82
|
await compiler.install({ version: '0.33.7' });
|
|
82
83
|
await roku.package({ env: 'prod', prebuild: 'npm run roku:build:prod' });
|
|
84
|
+
|
|
85
|
+
const recording = await capture.start({ platform: 'ios', device: 'iPhone 17 Pro' });
|
|
86
|
+
// Drive the app manually, through MCP, or through another automation API.
|
|
87
|
+
await recording.stop();
|
|
83
88
|
```
|
|
84
89
|
|
|
85
90
|
Common build-script replacements:
|
|
@@ -91,6 +96,7 @@ Common build-script replacements:
|
|
|
91
96
|
| `npx hst build-config:resolve --env dev --platform roku --out assets/meta/build-config.json` | `await buildConfig.resolve({ env: 'dev', platform: 'roku', out: 'assets/meta/build-config.json' })` |
|
|
92
97
|
| `npx hst compiler:install 0.33.7` | `await compiler.install({ version: '0.33.7' })` |
|
|
93
98
|
| `npx hst roku:package --env prod --prebuild 'npm run roku:build:prod'` | `await roku.package({ env: 'prod', prebuild: 'npm run roku:build:prod' })` |
|
|
99
|
+
| `npx hst capture ios --device 'iPhone 17 Pro'` | `await capture.start({ platform: 'ios', device: 'iPhone 17 Pro' })` |
|
|
94
100
|
| `npx hst secrets:check` | `await secrets.check({ cwd: process.cwd() })` |
|
|
95
101
|
| `npx hst env check` | `await env.check({ cwd: process.cwd() })` |
|
|
96
102
|
|
|
@@ -190,6 +196,7 @@ The CLI commands are organized into logical groups using colon-separated namespa
|
|
|
190
196
|
|
|
191
197
|
### Development Commands
|
|
192
198
|
- `run` - Canonical cross-platform app launcher. Bare interactive runs show one destination picker; explicit platform options support web, Roku, iOS, Apple TV, Android, and Android TV launch targets.
|
|
199
|
+
- `capture` - Record an Apple simulator, Roku capture-card input, or macOS screen/window. The default timeout is 180 seconds; use `--timeout` to override it.
|
|
193
200
|
- `target:list` - List launch targets for humans or agents, including web emulators, sims, and physical devices.
|
|
194
201
|
- `dev:start` - Run dev processes: vite, generator watch, and optional debugger
|
|
195
202
|
- `debugger:start` - Start the command debugger WebSocket proxy (only one debugger is needed for multiple apps; if the port is already in use, a friendly message is shown instead of crashing)
|
|
@@ -392,21 +399,25 @@ Applications own regular Vitest suites. Global setup comes from `@tantawowa/hosa
|
|
|
392
399
|
|
|
393
400
|
Add `createHosannaReporter(config)` from `@tantawowa/hosanna-tools/testing/vitest/reporter` to the application's Vitest reporters. Every run then writes a self-contained JSON and HTML report under `test-results/<testRunId>/`, updates `test-results/latest.json` and `test-results/latest.html`, and includes every Vitest result plus any named visual proofs captured by the tests.
|
|
394
401
|
|
|
395
|
-
|
|
402
|
+
Tests can record the complete owned browser, supported Apple simulator, or
|
|
403
|
+
Roku device run:
|
|
396
404
|
|
|
397
405
|
```ts
|
|
398
406
|
defineHosannaTestConfig({
|
|
399
407
|
// ...
|
|
400
408
|
video: true,
|
|
401
|
-
//
|
|
409
|
+
// Browser: video: { size: { width: 1280, height: 720 } },
|
|
410
|
+
// Native/device: video: { timeoutSeconds: 300, videoDevice: 'USB Video' },
|
|
402
411
|
});
|
|
403
412
|
```
|
|
404
413
|
|
|
405
|
-
The finalized recording is written
|
|
406
|
-
`test-results/<testRunId>/<platform
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
414
|
+
The finalized recording is written below
|
|
415
|
+
`test-results/<testRunId>/<platform>-<target>/` and embedded in the HTML report.
|
|
416
|
+
Browser targets use Playwright WebM. iOS/Apple TV simulators use `simctl` MP4.
|
|
417
|
+
Physical Roku targets use AVFoundation or a configured macOS screen/window
|
|
418
|
+
source. Native/device capture defaults to 180 seconds; override it with
|
|
419
|
+
`timeoutSeconds`. This is a review artifact, not a replay format or executable
|
|
420
|
+
test source.
|
|
410
421
|
|
|
411
422
|
```ts
|
|
412
423
|
import { defineConfig } from 'vitest/config';
|
package/dist/build-info.json
CHANGED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS, VideoCaptureManager, VideoCaptureSession, defaultCaptureOutputPath, listAvFoundationDevices, parseAvFoundationDevices, resolveMacWindowId, resolveVideoCapturePlan, resolveVideoCaptureSource, startVideoCapture, videoCaptureManager, } from './video-capture.js';
|
|
2
|
+
export type { AvFoundationDeviceList, ResolvedVideoCapturePlan, StartVideoCaptureOptions, VideoCaptureDependencies, VideoCaptureMarker, VideoCapturePlatform, VideoCaptureRect, VideoCaptureResult, VideoCaptureSource, VideoCaptureState, VideoCaptureStatus, VideoCaptureStopReason, } from './video-capture.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.videoCaptureManager = exports.startVideoCapture = exports.resolveVideoCaptureSource = exports.resolveVideoCapturePlan = exports.resolveMacWindowId = exports.parseAvFoundationDevices = exports.listAvFoundationDevices = exports.defaultCaptureOutputPath = exports.VideoCaptureSession = exports.VideoCaptureManager = exports.DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS = void 0;
|
|
4
|
+
var video_capture_js_1 = require("./video-capture.js");
|
|
5
|
+
Object.defineProperty(exports, "DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS", { enumerable: true, get: function () { return video_capture_js_1.DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS; } });
|
|
6
|
+
Object.defineProperty(exports, "VideoCaptureManager", { enumerable: true, get: function () { return video_capture_js_1.VideoCaptureManager; } });
|
|
7
|
+
Object.defineProperty(exports, "VideoCaptureSession", { enumerable: true, get: function () { return video_capture_js_1.VideoCaptureSession; } });
|
|
8
|
+
Object.defineProperty(exports, "defaultCaptureOutputPath", { enumerable: true, get: function () { return video_capture_js_1.defaultCaptureOutputPath; } });
|
|
9
|
+
Object.defineProperty(exports, "listAvFoundationDevices", { enumerable: true, get: function () { return video_capture_js_1.listAvFoundationDevices; } });
|
|
10
|
+
Object.defineProperty(exports, "parseAvFoundationDevices", { enumerable: true, get: function () { return video_capture_js_1.parseAvFoundationDevices; } });
|
|
11
|
+
Object.defineProperty(exports, "resolveMacWindowId", { enumerable: true, get: function () { return video_capture_js_1.resolveMacWindowId; } });
|
|
12
|
+
Object.defineProperty(exports, "resolveVideoCapturePlan", { enumerable: true, get: function () { return video_capture_js_1.resolveVideoCapturePlan; } });
|
|
13
|
+
Object.defineProperty(exports, "resolveVideoCaptureSource", { enumerable: true, get: function () { return video_capture_js_1.resolveVideoCaptureSource; } });
|
|
14
|
+
Object.defineProperty(exports, "startVideoCapture", { enumerable: true, get: function () { return video_capture_js_1.startVideoCapture; } });
|
|
15
|
+
Object.defineProperty(exports, "videoCaptureManager", { enumerable: true, get: function () { return video_capture_js_1.videoCaptureManager; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":";;;AAAA,uDAY4B;AAX1B,yIAAA,qCAAqC,OAAA;AACrC,uHAAA,mBAAmB,OAAA;AACnB,uHAAA,mBAAmB,OAAA;AACnB,4HAAA,wBAAwB,OAAA;AACxB,2HAAA,uBAAuB,OAAA;AACvB,4HAAA,wBAAwB,OAAA;AACxB,sHAAA,kBAAkB,OAAA;AAClB,2HAAA,uBAAuB,OAAA;AACvB,6HAAA,yBAAyB,OAAA;AACzB,qHAAA,iBAAiB,OAAA;AACjB,uHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type VideoCaptureManager } from './video-capture.js';
|
|
3
|
+
export declare function registerVideoCaptureTools(server: McpServer, options?: {
|
|
4
|
+
cwd?: string;
|
|
5
|
+
manager?: VideoCaptureManager;
|
|
6
|
+
}): void;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerVideoCaptureTools = registerVideoCaptureTools;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const video_capture_js_1 = require("./video-capture.js");
|
|
10
|
+
function registerVideoCaptureTools(server, options = {}) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
const cwd = node_path_1.default.resolve((_a = options.cwd) !== null && _a !== void 0 ? _a : process.cwd());
|
|
13
|
+
const manager = (_b = options.manager) !== null && _b !== void 0 ? _b : video_capture_js_1.videoCaptureManager;
|
|
14
|
+
server.tool('start_video_capture', `Start an independent video capture session for an agent-driven scenario, manual demonstration, or test.
|
|
15
|
+
|
|
16
|
+
The capture stops and finalizes automatically after ${video_capture_js_1.DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS} seconds by default. Override timeoutSeconds for a shorter or longer recording. Only one capture can be active in this MCP process at a time.`, {
|
|
17
|
+
platform: zod_1.z.enum(['ios', 'apple-tv', 'roku', 'macos']).describe('Platform being recorded'),
|
|
18
|
+
source: zod_1.z.enum(['apple-simulator', 'avfoundation', 'macos-screen', 'macos-window']).optional()
|
|
19
|
+
.describe('Capture source. Defaults from platform and supplied window/screen options.'),
|
|
20
|
+
outputPath: zod_1.z.string().optional().describe('Output video path, relative to the project when not absolute'),
|
|
21
|
+
timeoutSeconds: zod_1.z.number().int().positive().optional()
|
|
22
|
+
.describe(`Automatic stop timeout in seconds. Defaults to ${video_capture_js_1.DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS}.`),
|
|
23
|
+
device: zod_1.z.string().optional().describe('Booted Apple simulator name or UDID'),
|
|
24
|
+
codec: zod_1.z.enum(['h264', 'hevc']).optional().describe('Apple simulator video codec'),
|
|
25
|
+
videoDevice: zod_1.z.string().optional().describe('AVFoundation video device name or index'),
|
|
26
|
+
audioDevice: zod_1.z.string().optional().describe('Optional AVFoundation audio device name or index'),
|
|
27
|
+
frameRate: zod_1.z.number().int().positive().optional().describe('AVFoundation frame rate. Defaults to 30.'),
|
|
28
|
+
videoBitrate: zod_1.z.string().optional().describe('ffmpeg video bitrate. Defaults to 12M.'),
|
|
29
|
+
display: zod_1.z.number().int().positive().optional().describe('macOS display number. Defaults to 1.'),
|
|
30
|
+
windowId: zod_1.z.number().int().positive().optional().describe('macOS CoreGraphics window ID'),
|
|
31
|
+
application: zod_1.z.string().optional().describe('macOS application name used to resolve a window, for example QuickTime Player'),
|
|
32
|
+
windowTitle: zod_1.z.string().optional().describe('Optional title substring used to select an application window'),
|
|
33
|
+
rect: zod_1.z.object({
|
|
34
|
+
x: zod_1.z.number().int(),
|
|
35
|
+
y: zod_1.z.number().int(),
|
|
36
|
+
width: zod_1.z.number().int().positive(),
|
|
37
|
+
height: zod_1.z.number().int().positive(),
|
|
38
|
+
}).optional().describe('Optional macOS screen rectangle'),
|
|
39
|
+
showCursor: zod_1.z.boolean().optional().describe('Include the pointer in macOS screen/window capture'),
|
|
40
|
+
showClicks: zod_1.z.boolean().optional().describe('Show clicks in macOS screen/window capture'),
|
|
41
|
+
}, async (input) => {
|
|
42
|
+
try {
|
|
43
|
+
const session = await manager.start(Object.assign(Object.assign({}, input), { cwd }));
|
|
44
|
+
return captureToolResult({
|
|
45
|
+
status: 'recording',
|
|
46
|
+
capture: session.status(),
|
|
47
|
+
next: 'Drive the scenario, add markers at meaningful checkpoints, then call stop_video_capture.',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return captureToolError(error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
server.tool('get_video_capture_status', 'Get one video capture session, or list recent sessions when sessionId is omitted.', {
|
|
55
|
+
sessionId: zod_1.z.string().optional().describe('Capture session ID. Omit to list active and recent sessions.'),
|
|
56
|
+
}, async ({ sessionId }) => {
|
|
57
|
+
try {
|
|
58
|
+
if (!sessionId) {
|
|
59
|
+
return captureToolResult({ captures: manager.list() });
|
|
60
|
+
}
|
|
61
|
+
const session = manager.get(sessionId);
|
|
62
|
+
if (!session)
|
|
63
|
+
throw new Error(`Unknown video capture session ${sessionId}.`);
|
|
64
|
+
return captureToolResult({ capture: session.status() });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return captureToolError(error);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
server.tool('add_video_marker', 'Add a timestamped marker to the active capture manifest at a meaningful scenario checkpoint.', {
|
|
71
|
+
sessionId: zod_1.z.string().optional().describe('Capture session ID. Defaults to the active capture.'),
|
|
72
|
+
name: zod_1.z.string().min(1).describe('Short checkpoint name'),
|
|
73
|
+
details: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional().describe('Optional structured checkpoint context'),
|
|
74
|
+
}, async ({ sessionId, name, details }) => {
|
|
75
|
+
try {
|
|
76
|
+
const session = manager.get(sessionId);
|
|
77
|
+
if (!session)
|
|
78
|
+
throw new Error(sessionId ? `Unknown video capture session ${sessionId}.` : 'No video capture is active.');
|
|
79
|
+
const marker = session.addMarker(name, details);
|
|
80
|
+
return captureToolResult({ status: 'marked', sessionId: session.id, marker });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return captureToolError(error);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
server.tool('stop_video_capture', 'Stop and finalize a capture immediately. Returns only after the video and sidecar manifest are finalized.', {
|
|
87
|
+
sessionId: zod_1.z.string().optional().describe('Capture session ID. Defaults to the active capture.'),
|
|
88
|
+
}, async ({ sessionId }) => {
|
|
89
|
+
try {
|
|
90
|
+
const result = await manager.stop(sessionId, 'requested');
|
|
91
|
+
return result.state === 'failed'
|
|
92
|
+
? captureToolResult({ status: 'failed', capture: result }, true)
|
|
93
|
+
: captureToolResult({ status: 'completed', capture: result });
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return captureToolError(error);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function captureToolResult(value, isError = false) {
|
|
101
|
+
return Object.assign({ content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] }, (isError ? { isError: true } : {}));
|
|
102
|
+
}
|
|
103
|
+
function captureToolError(error) {
|
|
104
|
+
return captureToolResult({ error: error instanceof Error ? error.message : String(error) }, true);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=mcp-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../src/capture/mcp-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { listIosSimulatorTargets } from '../run/ios-simulator.js';
|
|
3
|
+
import { listAppleTvSimulatorTargets } from '../run/apple-tv.js';
|
|
4
|
+
export declare const DEFAULT_VIDEO_CAPTURE_TIMEOUT_SECONDS = 180;
|
|
5
|
+
export type VideoCapturePlatform = 'ios' | 'apple-tv' | 'roku' | 'macos';
|
|
6
|
+
export type VideoCaptureSource = 'apple-simulator' | 'avfoundation' | 'macos-screen' | 'macos-window';
|
|
7
|
+
export type VideoCaptureStopReason = 'requested' | 'timeout' | 'signal' | 'shutdown' | 'process-exit' | 'start-failed';
|
|
8
|
+
export type VideoCaptureState = 'recording' | 'stopping' | 'completed' | 'failed';
|
|
9
|
+
export interface VideoCaptureRect {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
}
|
|
15
|
+
export interface StartVideoCaptureOptions {
|
|
16
|
+
platform: VideoCapturePlatform;
|
|
17
|
+
source?: VideoCaptureSource;
|
|
18
|
+
cwd?: string;
|
|
19
|
+
outputPath?: string;
|
|
20
|
+
timeoutSeconds?: number;
|
|
21
|
+
/** Apple simulator name or UDID. Defaults to the only booted matching simulator. */
|
|
22
|
+
device?: string;
|
|
23
|
+
codec?: 'h264' | 'hevc';
|
|
24
|
+
/** AVFoundation video device name or index. Auto-selects the only non-screen input. */
|
|
25
|
+
videoDevice?: string;
|
|
26
|
+
/** Optional AVFoundation audio device name or index. */
|
|
27
|
+
audioDevice?: string;
|
|
28
|
+
frameRate?: number;
|
|
29
|
+
videoBitrate?: string;
|
|
30
|
+
/** macOS display number used by screencapture. Defaults to 1. */
|
|
31
|
+
display?: number;
|
|
32
|
+
/** macOS CoreGraphics window ID used by screencapture. */
|
|
33
|
+
windowId?: number;
|
|
34
|
+
/** Resolve a macOS window by application name when windowId is omitted. */
|
|
35
|
+
application?: string;
|
|
36
|
+
/** Optional substring used when resolving a window within application. */
|
|
37
|
+
windowTitle?: string;
|
|
38
|
+
rect?: VideoCaptureRect;
|
|
39
|
+
showCursor?: boolean;
|
|
40
|
+
showClicks?: boolean;
|
|
41
|
+
env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
|
|
42
|
+
}
|
|
43
|
+
export interface VideoCaptureMarker {
|
|
44
|
+
name: string;
|
|
45
|
+
atMs: number;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
details?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
export interface ResolvedVideoCapturePlan {
|
|
50
|
+
platform: VideoCapturePlatform;
|
|
51
|
+
source: VideoCaptureSource;
|
|
52
|
+
cwd: string;
|
|
53
|
+
outputPath: string;
|
|
54
|
+
manifestPath: string;
|
|
55
|
+
timeoutSeconds: number;
|
|
56
|
+
command: string;
|
|
57
|
+
args: string[];
|
|
58
|
+
readyPattern?: RegExp;
|
|
59
|
+
readyDelayMs?: number;
|
|
60
|
+
deviceId?: string;
|
|
61
|
+
deviceName?: string;
|
|
62
|
+
videoDevice?: string;
|
|
63
|
+
audioDevice?: string;
|
|
64
|
+
windowId?: number;
|
|
65
|
+
env: NodeJS.ProcessEnv;
|
|
66
|
+
}
|
|
67
|
+
export interface VideoCaptureStatus {
|
|
68
|
+
id: string;
|
|
69
|
+
state: VideoCaptureState;
|
|
70
|
+
platform: VideoCapturePlatform;
|
|
71
|
+
source: VideoCaptureSource;
|
|
72
|
+
outputPath: string;
|
|
73
|
+
manifestPath: string;
|
|
74
|
+
timeoutSeconds: number;
|
|
75
|
+
startedAt: string;
|
|
76
|
+
elapsedMs: number;
|
|
77
|
+
pid?: number;
|
|
78
|
+
deviceId?: string;
|
|
79
|
+
deviceName?: string;
|
|
80
|
+
videoDevice?: string;
|
|
81
|
+
audioDevice?: string;
|
|
82
|
+
windowId?: number;
|
|
83
|
+
markers: VideoCaptureMarker[];
|
|
84
|
+
stopReason?: VideoCaptureStopReason;
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface VideoCaptureResult extends VideoCaptureStatus {
|
|
88
|
+
state: 'completed' | 'failed';
|
|
89
|
+
finishedAt: string;
|
|
90
|
+
durationMs: number;
|
|
91
|
+
exitCode: number | null;
|
|
92
|
+
exitSignal: NodeJS.Signals | null;
|
|
93
|
+
bytesWritten: number;
|
|
94
|
+
}
|
|
95
|
+
export interface AvFoundationDeviceList {
|
|
96
|
+
video: Array<{
|
|
97
|
+
index: string;
|
|
98
|
+
name: string;
|
|
99
|
+
}>;
|
|
100
|
+
audio: Array<{
|
|
101
|
+
index: string;
|
|
102
|
+
name: string;
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
105
|
+
export interface VideoCaptureDependencies {
|
|
106
|
+
spawnProcess?: typeof spawn;
|
|
107
|
+
listIosTargets?: typeof listIosSimulatorTargets;
|
|
108
|
+
listAppleTvTargets?: typeof listAppleTvSimulatorTargets;
|
|
109
|
+
listAvFoundationDevices?: (cwd: string, env: NodeJS.ProcessEnv) => Promise<AvFoundationDeviceList>;
|
|
110
|
+
resolveMacWindowId?: (application: string, windowTitle: string | undefined, cwd: string, env: NodeJS.ProcessEnv) => Promise<number>;
|
|
111
|
+
now?: () => number;
|
|
112
|
+
}
|
|
113
|
+
export declare class VideoCaptureSession {
|
|
114
|
+
readonly plan: ResolvedVideoCapturePlan;
|
|
115
|
+
readonly id: `${string}-${string}-${string}-${string}-${string}`;
|
|
116
|
+
readonly completed: Promise<VideoCaptureResult>;
|
|
117
|
+
private readonly startedAtMs;
|
|
118
|
+
private readonly markers;
|
|
119
|
+
private readonly now;
|
|
120
|
+
private readonly child;
|
|
121
|
+
private resolveCompleted;
|
|
122
|
+
private state;
|
|
123
|
+
private stopReason?;
|
|
124
|
+
private error?;
|
|
125
|
+
private logTail;
|
|
126
|
+
private timeout?;
|
|
127
|
+
private forceStopTimeout?;
|
|
128
|
+
private result?;
|
|
129
|
+
private finalizing?;
|
|
130
|
+
private constructor();
|
|
131
|
+
static start(plan: ResolvedVideoCapturePlan, dependencies?: VideoCaptureDependencies): Promise<VideoCaptureSession>;
|
|
132
|
+
status(): VideoCaptureStatus;
|
|
133
|
+
addMarker(name: string, details?: Record<string, unknown>): VideoCaptureMarker;
|
|
134
|
+
stop(reason?: VideoCaptureStopReason): Promise<VideoCaptureResult>;
|
|
135
|
+
private observeProcess;
|
|
136
|
+
private waitUntilReady;
|
|
137
|
+
private finalize;
|
|
138
|
+
private performFinalize;
|
|
139
|
+
}
|
|
140
|
+
export declare class VideoCaptureManager {
|
|
141
|
+
private readonly dependencies;
|
|
142
|
+
private readonly sessions;
|
|
143
|
+
private activeSessionId?;
|
|
144
|
+
constructor(dependencies?: VideoCaptureDependencies);
|
|
145
|
+
start(options: StartVideoCaptureOptions): Promise<VideoCaptureSession>;
|
|
146
|
+
active(): VideoCaptureSession | undefined;
|
|
147
|
+
get(sessionId?: string): VideoCaptureSession | undefined;
|
|
148
|
+
list(): VideoCaptureStatus[];
|
|
149
|
+
stop(sessionId?: string, reason?: VideoCaptureStopReason): Promise<VideoCaptureResult>;
|
|
150
|
+
stopAll(reason?: VideoCaptureStopReason): Promise<VideoCaptureResult[]>;
|
|
151
|
+
private pruneCompletedSessions;
|
|
152
|
+
}
|
|
153
|
+
export declare const videoCaptureManager: VideoCaptureManager;
|
|
154
|
+
export declare function startVideoCapture(options: StartVideoCaptureOptions, dependencies?: VideoCaptureDependencies): Promise<VideoCaptureSession>;
|
|
155
|
+
export declare function resolveVideoCapturePlan(options: StartVideoCaptureOptions, dependencies?: VideoCaptureDependencies): Promise<ResolvedVideoCapturePlan>;
|
|
156
|
+
export declare function resolveVideoCaptureSource(options: StartVideoCaptureOptions): VideoCaptureSource;
|
|
157
|
+
export declare function parseAvFoundationDevices(output: string): AvFoundationDeviceList;
|
|
158
|
+
export declare function listAvFoundationDevices(cwd: string, env: NodeJS.ProcessEnv): Promise<AvFoundationDeviceList>;
|
|
159
|
+
export declare function resolveMacWindowId(application: string, windowTitle: string | undefined, cwd: string, env: NodeJS.ProcessEnv): Promise<number>;
|
|
160
|
+
export declare function defaultCaptureOutputPath(platform: VideoCapturePlatform, source: VideoCaptureSource, now?: Date): string;
|