Files
orca/config/scripts/trim-windows-icon-source.mjs
T
OrcaWinandOrcaWin 7d6603aa17 [comment audit] Complete repository-wide comment cleanup (#33249)
* [comment audit] Align legacy failure-read counts with cached display

* [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci]

* [comment audit] Condense shared generation, path and preview comments [skip ci]

* [comment audit] Condense host, file and Git contract rationale [skip ci]

* [comment audit] Tighten Git lifecycle and provider contract comments [skip ci]

* [comment audit] Clarify shared host authority and launch isolation [skip ci]

* [comment audit] simplify local access mobile and native chat contracts [skip ci]

* [comment audit] simplify native chat presentation and state contracts [skip ci]

* [comment audit] simplify native runtime and provider contracts [skip ci]

* [comment audit] simplify migration and orchestration contracts [skip ci]

* [comment audit] simplify plugin trust and process capture rationale [skip ci]

* [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci]

* [comment audit] clarify remote recovery and launch wire rationale [skip ci]

* [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci]

* [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci]

* [comment audit] clarify sidebar, skill and SSH invariants [skip ci]

* [comment audit] condense structured chat delivery and timing rationale [skip ci]

* [comment audit] condense terminal replay and telemetry invariants [skip ci]

* [comment audit] clarify launch permission and terminal delivery rationale [skip ci]

* [comment audit] clarify workspace ownership and layout contracts [skip ci]

* [comment audit] wait for fitted and painted SSH terminal links

* [comment audit] clarify layout persistence and session ownership [skip ci]

* [comment audit] clarify host routing and workspace lifecycle contracts [skip ci]

* [comment audit] clarify startup persistence and app lifetime comments [skip ci]

* [comment audit] clarify recovery and activity boundaries [skip ci]

* [comment audit] condense activity and artifact invariants [skip ci]

* [comment audit] condense automation authority contracts [skip ci]

* [comment audit] simplify automation scheduling and history contracts [skip ci]

* [comment audit] clarify browser chrome and annotation lifecycles [skip ci]

* [comment audit] clarify browser routing and retained guest ownership [skip ci]

* [comment audit] clarify browser recovery and document ownership comments [skip ci]

* [comment audit] restore hosted runners required by native IME fixtures

* [comment audit] shorten preview, palette and dashboard invariants [skip ci]

* [comment audit] clarify terminal preview, dashboard and retention comments [skip ci]

* [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci]

* [comment audit] shorten rich-text and combined-diff ownership comments [skip ci]

* [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci]

* [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci]

* [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci]

* [comment audit] clarify rich Markdown source and selection safeguards [skip ci]

* [comment audit] clarify editor loading and emulator stream lifetimes [skip ci]

* [comment audit] trim emulator and feature tour narration [skip ci]

* [comment audit] clarify floating workspace and GitHub cache ownership [skip ci]

* [comment audit] trim provider controls and Linear filter explanations [skip ci]

* [comment audit] clarify pairing and chat resume lifetimes [skip ci]

* [comment audit] clarify chat delivery and transcript lifetimes [skip ci]

* [comment audit] clarify session options and host-owned status [skip ci]

* [comment audit] clarify draft durability and live-status precedence [skip ci]

* [comment audit] Trim chat send and model ownership explanations [skip ci]

* [comment audit] Shorten transcript ownership and send recovery comments [skip ci]

* [comment audit] Simplify native chat composer and transcript hook comments [skip ci]

* [comment audit] Shorten native chat scroll and structured session explanations [skip ci]

* [comment audit] Trim workspace picker and onboarding commentary [skip ci]

* [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci]

* [comment audit] Trim sidebar and session history explanations [skip ci]

* [comment audit] Condense session resume and review checks comments [skip ci]

* [comment audit] Shorten checks state and file explorer refresh comments [skip ci]

* [comment audit] Trim plugin bridge and source-control action rationale [skip ci]

* [comment audit] Trim source-control listing and review rationale [skip ci]

* [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci]

* [comment audit] Condense Settings account and appearance rationale [skip ci]

* [comment audit] Trim pairing and repository Settings explanations [skip ci]

* [comment audit] Condense Settings search SSH and terminal safeguards [skip ci]

* [comment audit] Shorten Settings voice and provider ownership comments [skip ci]

* [comment audit] Condense Settings draft persistence and host-state rationale [skip ci]

* [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci]

* [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci]

* [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci]

* [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci]

* [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci]

* [comment audit] Prune focus-read baseline after comment cleanup

* [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci]

* [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci]

* [comment audit] Clarify viewport geometry and skill update safeguards [skip ci]

* [comment audit] Tighten skill inventory, usage and host status comments [skip ci]

* [comment audit] Clarify usage ownership and resource kill safeguards [skip ci]

* [comment audit] Tighten tab selection, rename and search contracts [skip ci]

* [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci]

* [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci]

* [comment audit] Tighten provider loading and terminal recovery comments [skip ci]

* [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci]

* [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci]

* [comment audit] Tighten PTY startup and replay explanations [skip ci]

* [comment audit] Clarify PTY identity and delivery ownership [skip ci]

* [comment audit] Shorten remote reconnect and input replay rationale [skip ci]

* [comment audit] Condense terminal parking clipboard and file link comments [skip ci]

* [comment audit] Clarify IME ownership and trim trace history [skip ci]

* [comment audit] Shorten pane recovery and parked watcher explanations [skip ci]

* [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci]

* [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci]

* [comment audit] Trim renderer lifecycle and menu rationale [skip ci]

* [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci]

* [comment audit] Clarify renderer hook evidence and source ownership [skip ci]

* [comment audit] Tighten IPC ownership and reconnect explanations [skip ci]

* [comment audit] Trim renderer focus, paste and attention comments [skip ci]

* [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci]

* [comment audit] Trim agent launch, resume and ownership commentary [skip ci]

* [comment audit] Shorten account, browser and editor comments [skip ci]

* [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci]

* [comment audit] Condense launch recovery and editor tokenization comments [skip ci]

* [comment audit] Condense workspace selection and terminal pane rationale [skip ci]

* [comment audit] Condense terminal fitting and rendering recovery comments [skip ci]

* [comment audit] Condense terminal input and host routing explanations [skip ci]

* [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci]

* [comment audit] Condense structured launch and terminal link explanations [skip ci]

* [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci]

* [comment audit] Condense session persistence and workspace activation rationale [skip ci]

* [comment audit] Condense workspace routing and browser ownership rationale [skip ci]

* [comment audit] Condense mirror recovery and layout authority rationale [skip ci]

* [comment audit] Condense runtime transport and file safety rationale [skip ci]

* [comment audit] Condense runtime graph and structured session rationale [skip ci]

* [comment audit] Condense browser creation and remote tab recovery rationale [skip ci]

* [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci]

* [comment audit] Condense frame, startup and provider cache rationale [skip ci]

* [comment audit] Condense host twin and agent lifecycle rationale [skip ci]

* [comment audit] Condense browser authority and editor cleanup rationale [skip ci]

* [comment audit] Condense editor buffer identity and review cache rationale [skip ci]

* [comment audit] Condense provider lifetime and repository ownership rationale [skip ci]

* [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci]

* [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci]

* [comment audit] Condense cleanup ownership and listing admission rationale [skip ci]

* [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci]

* [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci]

* [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci]

* [comment audit] Condense cloud rollout and assignment safety rationale [skip ci]

* [comment audit] Condense relay session and database recovery rationale [skip ci]

* [comment audit] Condense relay placement and protocol compatibility rationale [skip ci]

* [comment audit] Condense build and packaging constraints [skip ci]

* [comment audit] Condense CI gates and validation isolation rationale [skip ci]

* [comment audit] Condense catalog identity and browser validation rationale [skip ci]

* [comment audit] Condense mobile browser and frame-budget rationale [skip ci]

* [comment audit] Shorten mobile route and browser test explanations [skip ci]

* [comment audit] Condense editor and session seam test rationale [skip ci]

* [comment audit] Trim session and terminal closure history [skip ci]

* [comment audit] Shorten terminal browser and census explanations [skip ci]

* [comment audit] Preserve root-only E2E diagnostic baseline

* [comment audit] Condense mobile seam and HTML preview test rationale [skip ci]

* [comment audit] Condense preview instrumentation and render harness rationale [skip ci]

* [comment audit] Condense bundle contracts and native-build constraints [skip ci]

* [comment audit] Shorten native packaging and CI routing rationale [skip ci]

* [comment audit] Condense release tooling and benchmark constraints [skip ci]

* [comment audit] Condense packaging and platform gate rationale [skip ci]

* [comment audit] Shorten mobile route and history rationale [skip ci]

* [comment audit] Condense mobile browser and component rationale [skip ci]

* [comment audit] Shorten drawer and workspace-form rationale [skip ci]

* [comment audit] Trim mobile review and editor-document explanations [skip ci]

* [comment audit] Condense editor lifecycle and Markdown explanations [skip ci]

* [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci]

* [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci]

* [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci]

* [comment audit] Condense bridge stream, native request and audio rationale [skip ci]

* [comment audit] Reduce bridge schema and page-client commentary [skip ci]

* [comment audit] Tighten mobile page bridge contracts [skip ci]

* [comment audit] Clarify mobile cache and session constraints [skip ci]

* [comment audit] Condense mobile route and lifecycle rationale [skip ci]

* [comment audit] Tighten mobile shell hook timing rationale [skip ci]

* [comment audit] Clarify route handoff and notification compatibility [skip ci]

* [comment audit] Clarify push registration and dictation cleanup constraints [skip ci]

* [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci]

* [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci]

* [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci]

* [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci]

* [comment audit] Tighten stream replay and queued session ownership rationale [skip ci]

* [comment audit] Condense mobile composer and reply-schema constraints [skip ci]

* [comment audit] Clarify mobile transcript recovery and session ownership [skip ci]

* [comment audit] Clarify mobile queue and source-control compatibility [skip ci]

* [comment audit] Condense storage and task launch constraints [skip ci]

* [comment audit] Clarify task schemas and terminal document ownership [skip ci]

* [comment audit] Tighten terminal input and viewport rationale [skip ci]

* [comment audit] Shorten terminal and RPC recorder contracts [skip ci]

* [comment audit] Condense recorder engine and connection contracts [skip ci]

* [comment audit] Shorten host credential and relay recovery comments [skip ci]

* [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci]

* [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci]

* [comment audit] Condense catalog and relay entry contracts [skip ci]

* [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci]

* [comment audit] Condense WSL relay and E2E regression rationale [skip ci]

* [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci]

* [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci]

* [comment audit] Shorten layout oracle and regression explanations [skip ci]

* [comment audit] Condense paired recovery and ownership regression contracts [skip ci]

* [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci]

* [comment audit] Condense terminal rendering and IME regression rationale [skip ci]

* [comment audit] Shorten terminal recovery and benchmark contracts [skip ci]

* [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci]

* [comment audit] Condense workflow routing and release rationale [skip ci]

* [comment audit] Condense mobile security and installer contracts [skip ci]

* [comment audit] Shorten native rationale and stylesheet workarounds [skip ci]

* [comment audit] Shorten Windows visibility probe rationale [skip ci]

* [comment audit] Condense embedded release and signing rationale [skip ci]

* [comment audit] Retain current main test behavior in final reconciliation [skip ci]

* [comment audit] Complete final comment review across current source inventory

* [comment audit] Handle consolidated audit reports before final CI

* [comment audit] Preserve credential storage census detail [skip ci]

* [comment audit] Scale broad changed E2E selections with verified timing shards

* [comment audit] Align E2E assertions with browser close and settled session metadata

* [comment audit] Match existing E2Es to current resource and windowing contracts

* [comment audit] Observe the shared server outage notice in reconnect coverage

* [comment audit] Make existing renderer probes measure settled tab and PTY work

* [comment audit] Align palette E2E selector with task search

* [comment audit] Refresh remaining palette search selectors

* [comment audit] Keep selector correction within selected audit specs

* [comment audit] Await emoji fixture settings inside renderer evaluation

* [comment audit] Cancel fixture fit retries between terminal tests

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-25 04:05:46 -07:00

209 lines
7.3 KiB
JavaScript

#!/usr/bin/env node
// Trim macOS Icon Composer inset when generating Windows ICO; untrimmed glyph fills only ~83% and looks undersized (#5357).
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { PNG } from 'pngjs'
// Target ~96% largest-frame fill because Windows downscales it; retain margin for antialiasing/shadow.
export const ICON_CANVAS_MARGIN_RATIO = 0.02
// Ignore low-alpha safe-area shadow when finding glyph bounds.
const ALPHA_BACKGROUND_THRESHOLD = 16
// Standard Windows ICO sizes, largest first (matches the prior ImageMagick set).
export const ICO_FRAME_SIZES = [256, 128, 64, 48, 32, 16]
export function decodePng(buffer) {
const png = PNG.sync.read(buffer)
return { width: png.width, height: png.height, data: png.data }
}
export function encodePng({ width, height, data }) {
const png = new PNG({ width, height })
data.copy(png.data)
return PNG.sync.write(png)
}
// Return tight alpha-threshold bounds or null for fully transparent image.
export function findOpaqueBounds({ width, height, data }, threshold = ALPHA_BACKGROUND_THRESHOLD) {
let minX = width
let minY = height
let maxX = -1
let maxY = -1
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const alpha = data[(y * width + x) * 4 + 3]
if (alpha > threshold) {
if (x < minX) {
minX = x
}
if (x > maxX) {
maxX = x
}
if (y < minY) {
minY = y
}
if (y > maxY) {
maxY = y
}
}
}
}
if (maxX < 0) {
return null
}
return { minX, minY, maxX, maxY, width: maxX - minX + 1, height: maxY - minY + 1 }
}
export function cropImage({ width, data }, bounds) {
const cropWidth = bounds.width
const cropHeight = bounds.height
const out = Buffer.alloc(cropWidth * cropHeight * 4)
for (let y = 0; y < cropHeight; y++) {
const srcRow = (bounds.minY + y) * width + bounds.minX
const srcStart = srcRow * 4
out.set(data.subarray(srcStart, srcStart + cropWidth * 4), y * cropWidth * 4)
}
return { width: cropWidth, height: cropHeight, data: out }
}
// Pad trimmed glyph uniformly into square without clipping shadow or distorting aspect ratio.
export function squareWithMargin(image, marginRatio = ICON_CANVAS_MARGIN_RATIO) {
const longSide = Math.max(image.width, image.height)
const side = Math.round(longSide / (1 - 2 * marginRatio))
const data = Buffer.alloc(side * side * 4)
const offsetX = Math.floor((side - image.width) / 2)
const offsetY = Math.floor((side - image.height) / 2)
for (let y = 0; y < image.height; y++) {
const srcStart = y * image.width * 4
const dstStart = ((offsetY + y) * side + offsetX) * 4
data.set(image.data.subarray(srcStart, srcStart + image.width * 4), dstStart)
}
return { width: side, height: side, data }
}
// Premultiply alpha during box-filter downscale to avoid dark fringes at transparent edges.
export function resizeImage(image, targetWidth, targetHeight) {
const { width: srcW, height: srcH, data: src } = image
const out = Buffer.alloc(targetWidth * targetHeight * 4)
const scaleX = srcW / targetWidth
const scaleY = srcH / targetHeight
for (let ty = 0; ty < targetHeight; ty++) {
const sy0 = ty * scaleY
const sy1 = (ty + 1) * scaleY
const y0 = Math.floor(sy0)
const y1 = Math.min(srcH, Math.ceil(sy1))
for (let tx = 0; tx < targetWidth; tx++) {
const sx0 = tx * scaleX
const sx1 = (tx + 1) * scaleX
const x0 = Math.floor(sx0)
const x1 = Math.min(srcW, Math.ceil(sx1))
let rSum = 0
let gSum = 0
let bSum = 0
let aSum = 0
let weightSum = 0
for (let sy = y0; sy < y1; sy++) {
const wy = Math.min(sy1, sy + 1) - Math.max(sy0, sy)
for (let sx = x0; sx < x1; sx++) {
const wx = Math.min(sx1, sx + 1) - Math.max(sx0, sx)
const weight = wx * wy
if (weight <= 0) {
continue
}
const idx = (sy * srcW + sx) * 4
const alpha = src[idx + 3]
const premul = (alpha / 255) * weight
rSum += src[idx] * premul
gSum += src[idx + 1] * premul
bSum += src[idx + 2] * premul
aSum += alpha * weight
weightSum += weight
}
}
const dst = (ty * targetWidth + tx) * 4
if (weightSum === 0 || aSum === 0) {
out[dst] = 0
out[dst + 1] = 0
out[dst + 2] = 0
out[dst + 3] = 0
continue
}
const alphaAvg = aSum / weightSum
const colorDivisor = alphaAvg / 255
out[dst] = Math.round(rSum / weightSum / colorDivisor)
out[dst + 1] = Math.round(gSum / weightSum / colorDivisor)
out[dst + 2] = Math.round(bSum / weightSum / colorDivisor)
out[dst + 3] = Math.round(alphaAvg)
}
}
return { width: targetWidth, height: targetHeight, data: out }
}
// Use PNG-compressed ICO frames, supported since Vista and matching previous ImageMagick output.
export function encodeIco(frames) {
const header = Buffer.alloc(6)
header.writeUInt16LE(0, 0) // reserved
header.writeUInt16LE(1, 2) // type 1 = icon
header.writeUInt16LE(frames.length, 4)
const directory = Buffer.alloc(frames.length * 16)
let dataOffset = 6 + frames.length * 16
const payloads = []
frames.forEach((frame, index) => {
const png = encodePng(frame)
payloads.push(png)
const entry = index * 16
// Width/height of 256 are stored as 0 per the ICO spec.
directory.writeUInt8(frame.width >= 256 ? 0 : frame.width, entry)
directory.writeUInt8(frame.height >= 256 ? 0 : frame.height, entry + 1)
directory.writeUInt8(0, entry + 2) // color count (0 = truecolor)
directory.writeUInt8(0, entry + 3) // reserved
directory.writeUInt16LE(1, entry + 4) // color planes
directory.writeUInt16LE(32, entry + 6) // bits per pixel
directory.writeUInt32LE(png.length, entry + 8)
directory.writeUInt32LE(dataOffset, entry + 12)
dataOffset += png.length
})
return Buffer.concat([header, directory, ...payloads])
}
// Trim safe-area inset from source and return filled multi-size ICO; export permits pixel-level regression test.
export function buildWindowsIcoFromPng(sourcePngBuffer, sizes = ICO_FRAME_SIZES) {
const source = decodePng(sourcePngBuffer)
const bounds = findOpaqueBounds(source)
if (!bounds) {
throw new Error('Source icon is fully transparent; cannot trim safe-area inset.')
}
const trimmed = cropImage(source, bounds)
const filled = squareWithMargin(trimmed)
const frames = sizes.map((size) => resizeImage(filled, size, size))
return encodeIco(frames)
}
function resolveDefaultPaths() {
const scriptDir = import.meta.dirname
const projectDir = dirname(dirname(scriptDir))
return {
sourcePng: join(projectDir, 'resources', 'build', 'icon.png'),
outputIco: join(projectDir, 'resources', 'build', 'icon.ico')
}
}
function main() {
const { sourcePng, outputIco } = resolveDefaultPaths()
if (!existsSync(sourcePng)) {
console.error(`Error: source PNG not found at ${sourcePng}`)
process.exit(1)
}
const ico = buildWindowsIcoFromPng(readFileSync(sourcePng))
writeFileSync(outputIco, ico)
console.log(` -> ${outputIco} (filled multi-size ICO, safe-area inset trimmed)`)
}
if (
import.meta.url === `file://${process.argv[1]}` ||
process.argv[1]?.endsWith('trim-windows-icon-source.mjs')
) {
main()
}