### Fixed
- **Client auto-update silently stuck on old version** — `installClientPackage()` now deletes both `package-lock.json` and `node_modules/` before reinstalling, preventing Arborist from short-circuiting on the already-installed version. Previously, the lockfile pinned the version forever after the first install, so even though `fetchLatestVersion()` correctly detected a newer version (e.g., `1.0.6`), the reinstall step would faithfully reinstall the locked version (e.g., `1.0.5`) every time. The client now resolves `latest` from the registry on every update, producing a log like `Installed @jean2/client@1.0.6 (verified)`.

### Added
- **Supply-chain protection via minimum version age** — `fetchLatestVersion()` now fetches the full package metadata (including per-version publish timestamps) instead of just the `/latest` endpoint. Newly published `@jean2/client` versions must be at least `JEAN2_PACKAGE_MIN_AGE_HOURS` (default 24h) old before they are eligible for auto-install. This creates a time buffer where a compromised npm publish token can be caught and the malicious version un-published before it auto-deploys to running servers. If the latest version is too fresh, the update is skipped with a log line like `@jean2/client@1.0.7 was published 2h ago (minimum: 24h) — skipping auto-update`. Set `JEAN2_PACKAGE_MIN_AGE_HOURS=0`, `false`, or `off` to disable.
- **Integrity pinning for `@jean2/client`** — `installClientPackage()` now extracts and stores `dist.integrity` (SRI hash) from npm metadata in `.client-manifest.json`. The install log shows `(verified)` when integrity was captured, and Arborist independently verifies integrity during install.
- **Min-age protection for tool SDK dependencies** — `installDependencies()` for tools now checks publish age of resolved `@jean2/sdk` versions before installing. If too fresh, a warning is logged (tools use semver ranges, not `latest`, so blocking isn't appropriate — but the warning prompts manual review).
- **Integrity tracking for tool SDK installs** — tool install manifests (`.install-manifest.json`) now record `sdkVersion` and `sdkIntegrity` for `@jean2/sdk` when present, providing an audit trail for supply-chain investigation.
- **Shared npm utilities** — common Arborist-based install logic extracted into `services/npm-utils.ts` with `createArborist()`, `resetInstallState()`, `fetchPackageMetadata()`, `checkVersionAge()`, `resolveMaxSatisfying()`, and `extractIntegrity()`. Both the client launcher and tool installer now share this module.

### Changed
- **Arborist installs use `preferOnline: true`** — both client and tool npm installs now bypass the stale npm metadata cache, ensuring version resolution is always fresh from the registry. The old lockfile and `node_modules/` are cleared on every install via `resetInstallState()`.
