Files
claude-code-haha/scripts
程序员阿江(Relakkes) 8e033e2890 fix(computer-use): restore the sidecar signing exclusion, and show app icons
Two things, in one commit because both touch `src/server/api/computer-use.ts`
and the halves cannot be split without rewriting the file twice.

## The regression

`desktop/package.json` had lost `"claude-sidecar-[^/]+$"` from `mac.signIgnore`.
That entry is not a hardening nicety — it is load-bearing for attestation:

  1. `build-sidecars.ts` signs the sidecar with an explicit
     `--identifier com.claude-code-haha.desktop.sidecar`
  2. `ClientAttestation.swift` compares that identifier EXACTLY in
     `validDesktopChain`
  3. without the exclusion, electron-builder re-signs the sidecar and drops the
     flag, so codesign derives the identifier from the file name
     (`claude-sidecar-aarch64-apple-darwin`), which never matches

Measured on the shipped 0.5.3 build: host and helper identifiers were correct,
the sidecar's was not. `validDesktopChain` backs BOTH `authorizeOneShot` and
`authorizeDaemon`, so this was not merely a broken permission probe — every
Computer Use call in that build failed closed with `unauthorized_client`.

The existing guard was a literal `toEqual` on the whole signIgnore array, which
does not survive an edit that changes the array and the expectation together —
exactly how the entry was lost. The replacement asserts the behaviour instead:
real sidecar file names must match some exclusion pattern, and the identifier
constants in `sign-identity.ts` and `ClientAttestation.swift` must agree.

`checkCuHelperPermissions` swallowed the failure into nulls, which the settings
page renders as a permanent "checking…" — indistinguishable from a probe still
in flight, and the only symptom this bug ever produced. It now records an
error-level diagnostic: the helper binary is present, so the user did nothing
wrong and the check still did not complete.

## App icons

Rows in the picker and the authorized list showed a letter tile. They now show
the application's own icon, resolved the way Finder does it: `CFBundleIconFile`
from Info.plist, the `.icns` under `Contents/Resources`, rasterised with `sips`.

`openTargetService` already does this, but its resolver is keyed on a
`TargetDefinition` and cannot answer for an arbitrary installed app, so the
path-only half lives in `macAppIcon.ts` and that service is left alone.

The endpoint takes a bundle id and resolves the path itself. There is
deliberately no parameter that names a file — it rasterises and returns bytes,
so its input surface is a security property, and a test drives paths at it.

Enumeration is shared across concurrent lookups: opening the picker fires one
icon request per visible row while the cache is still cold, and a plain
check-then-fill cache would walk every application root once per row.

macOS only, matching where this engine exists. The Windows list renders no icon
slot at all, and Linux is not a supported Computer Use platform.

## Verification

- 208 installed applications on the dev machine: 204 icons resolved; the 4
  misses are background bundles (Adobe sync extension, a URL handler, an
  updater, a token host) that ship no icon and correctly fall back
- check:server 3345 pass, desktop 4101 pass, check:policy 243 pass, lint clean
  (the 2 failures in each suite are `*.golden.test.ts`, pre-existing on main)
- mutation-checked that the new guards actually fail: removing the signIgnore
  entry, dropping the icon `onError` fallback, and breaking the in-flight share
  each turn a test red
2026-08-05 22:59:26 +08:00
..