Merge pull request #1576 from BradGroux/fix/hosted-native-capture-display

fix: configure hosted display before native capture
This commit is contained in:
Brad Groux 2026-09-07 22:02:18 -05:00 • committed by GitHub
commit cb5d192e47
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 65 additions and 2 deletions

View file

@ -40,6 +40,11 @@ jobs:
with:
fetch-depth: 0
- name: Configure native capture display
run: |
swift scripts/native-ui/hosted-display.swift --configure-hosted
swift scripts/native-ui/hosted-display.swift --check
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0

View file

@ -41,3 +41,5 @@ Permitted post-build changes are regular, non-executable README/documentation Ma
The optional `focusedBoardAssets` capture list permits only `board-5000.png`, at 1360×900 native content pixels. It has the same build, app digest, timestamp, byte-hash and committed-file requirements as the maintained captures. A published focused image requires its original capture entry.
Run `node --import tsx ../scripts/native-ui/board-performance.mjs <candidate.app> <new-evidence-directory>` from `server/`. After that feature run passes, supply its `report.json` as the final argument to `pnpm docs:capture-media <candidate.app> <new-capture-directory> capture <board-report.json>`. The capture command verifies the same candidate identity and original screenshot hash before incorporating the focused image. This supplements the fourteen maintained assets and ten task-mode views; it does not replace them.
The signed workflow configures its disposable macOS runner to an available, unscaled 1920×1080 display mode before building. The setting lasts only for that runner login session. `swift scripts/native-ui/hosted-display.swift --check` is read-only and verifies the display prerequisite locally; `--configure-hosted` is restricted to GitHub Actions. Native acceptance records the actual display work area and fails before the matrix if it cannot contain the retained capture sizes.

View file

@ -36,8 +36,8 @@ export const settingsSections = [
'Maintenance',
];
export const contentSizes = {
// Hosted macOS runners expose only 760px of usable content height. Keep the
// expanded width while using a height the native window manager can honor.
// Retain the original matched capture sizes. The hosted workflow configures
// a 1920x1080 display before packaging; default runner displays can be smaller.
normal: { width: 1700, height: 760 },
minimum: { width: 1180, height: 760 },
};

View file

@ -0,0 +1,47 @@
import CoreGraphics
import Foundation
func fail(_ message: String) -> Never {
FileHandle.standardError.write(Data((message + "\n").utf8))
exit(1)
}
let argument = CommandLine.arguments.dropFirst().first ?? "--check"
guard ["--check", "--configure-hosted"].contains(argument) else {
fail("Usage: swift scripts/native-ui/hosted-display.swift [--check|--configure-hosted]")
}
let display = CGMainDisplayID()
if argument == "--configure-hosted" {
guard ProcessInfo.processInfo.environment["GITHUB_ACTIONS"] == "true" else {
fail("Display configuration is restricted to the disposable GitHub Actions runner")
}
let modes = CGDisplayCopyAllDisplayModes(display, nil) as? [CGDisplayMode] ?? []
guard let mode = modes.first(where: {
$0.width == 1920 && $0.height == 1080 && $0.pixelWidth == 1920 && $0.pixelHeight == 1080
}) else {
fail("Runner has no unscaled 1920x1080 mode. Available: " + modes.map {
"\($0.width)x\($0.height) (\($0.pixelWidth)x\($0.pixelHeight) pixels)"
}.joined(separator: ", "))
}
var configuration: CGDisplayConfigRef?
guard CGBeginDisplayConfiguration(&configuration) == .success, let configuration else {
fail("Cannot begin runner display configuration")
}
guard CGConfigureDisplayWithDisplayMode(configuration, display, mode, nil) == .success else {
CGCancelDisplayConfiguration(configuration)
fail("Cannot select runner display mode")
}
guard CGCompleteDisplayConfiguration(configuration, .forSession) == .success else {
fail("Cannot apply runner display mode for this login session")
}
}
guard let actual = CGDisplayCopyDisplayMode(display) else { fail("No active display mode") }
let evidence: [String: Any] = [
"width": actual.width, "height": actual.height,
"pixelWidth": actual.pixelWidth, "pixelHeight": actual.pixelHeight,
"configured": argument == "--configure-hosted"
]
print(String(data: try JSONSerialization.data(withJSONObject: evidence, options: [.sortedKeys]), encoding: .utf8)!)
guard actual.width >= 1920 && actual.height >= 1080 else {
fail("Native capture requires at least 1920x1080 logical display points")
}

View file

@ -685,6 +685,15 @@ async function checkSeededRendererFailures() {
}
try {
await launch();
report.display = await app.evaluate(({ screen }) => {
const { bounds, workArea, scaleFactor } = screen.getPrimaryDisplay();
return { bounds, workArea, scaleFactor };
});
await persist();
assert(
report.display.workArea.width >= 1780 && report.display.workArea.height >= 960,
'Native capture needs a work area of at least 1780x960; configure the runner display first'
);
report.titlebarAction = await verifyConfiguredTitlebarAction(app, page);
report.menuCommands = await verifyNativeMenuCommands(app, page);
report.settingsWindow = await verifyNativeSettingsWindow(app, page);