AGENTS.md@packages/apple-tools · git:20261019.0a763e4 · 2026-10-19 · sha256 d8042a2a172b13ab

AGENTS.md@packages/apple-tools git:20261019.0a763e4A

Immutable. This exact content never changes and is served at /api/v1/blob/d8042a2a172b13ab.

# DOX — packages/apple-tools

Files in this directory. One row per source file. See change: add-apple-tools-imcp-plugin.

| File | Purpose |
|------|---------|
| `README.md` | Package overview. iMCP (Apple PIM) provisioning for pi via pi's built-in MCP (pi ≥ 1.0.0). macOS-only, no Mail. Install/provision/manual-grant, nine provisioning states. See change: migrate-mcp-to-pi-builtin. |
| `package.json` | pi-dashboard-plugin manifest. id `apple-tools`, priority 100. `dependsOn: ["mcp-client"]`. `requires: { paths: ["${imcpServerPath}"] }` (NO `piExtensions`). `configSchema` `./config.schema.json`. Claims `settings-section`→`AppleToolsSettings` (no `tab` — renders under the plugin's own row). `bin` `pi-apple-tools-install`. `pi.skills` `.pi/skills/apple-tools`. NO `pi-mcp-adapter` dep. No postinstall. See change: migrate-mcp-to-pi-builtin. |
| `config.schema.json` | JSON Schema 7. `imcpServerPath` only (default canonical `/Applications` location — the key the `paths` requirement interpolates). `exposure`/`toolExposure`/`enabled` deliberately absent: they live on the `mcpServers.iMCP` entry in mcp.json and are operator-owned (preserved on refresh). See change: migrate-mcp-to-pi-builtin. |
| `vitest.config.ts` | jsdom + react, shared setup-home globalSetup. |
| `tsconfig.json` | Extends tsconfig.base; jsx react-jsx; noEmit. |
| `.pi/skills/apple-tools/SKILL.md` | Agent skill. Seven reachable services; Mail exclusion + redirect to `apple-mail-fast-export`; Messages=iMessage/SMS; load-time `--check`; TCC revocation → menu-bar remediation. iMCP reached through pi's built-in MCP (pi ≥ 1.0.0), tools as `mcp__iMCP__*`. See change: migrate-mcp-to-pi-builtin. |
| `src/detect.ts` | Pure injectable probes: `parseVersion`/`compareVersions`/`meetsMinimum` (numeric, MIN_MACOS 15.3), `candidatePaths`/`discoverServer` (override-as-preference, ordered candidate list). Constants: IMCP_RELATIVE, IMCP_DOWNLOAD_URL, IMCP_BREW_CASK. |
| `src/install.ts` | `runInstaller(env, {check})` — the nine-state provisioning machine (write + write-suppressed check twin). `TerminalState` / `TERMINAL_STATES`, `InstallerEnv`, `InstallResult`. Post-brew re-discovery gate. Pure over injected env. Owns NO writer: `env.mcps` is the `mcp-client.config` service — `ensureServerEntry("iMCP", {command}, {kind:"global"})` (command refreshed; operator `enabled`/`exposure`/`toolExposure` + unknown keys preserved), `checkConfigFiles` (checks `mcpJson` only). `ensureAdapterPackage` + every `settings.json` write REMOVED. `relayConfigFailure` maps `ConfigRefusal` onto terminal states: `write-failed` → `CONFIG_WRITE_FAILED`, else `CONFIG_UNPARSEABLE`. See change: extract-mcp-client-plugin, migrate-mcp-to-pi-builtin. |
| `src/reconcile.ts` | `shouldReconcilePath` — server-side write-back guard (unset/default only, never over an operator override). `DEFAULT_IMCP_PATH`. |
| `src/doctor.ts` | `doctorProbe(env, packagePresent)` — read-only verdict from the shared checker; non-macOS never a remediation item. |
| `src/env.ts` | Real-environment `InstallerEnv` factory. The ONLY module that touches the real OS: `sw_vers`, brew via argv-array execFileSync (shared platform/exec wrapper). `createInstallerEnv`, BREW_TIMEOUT_MS. Builds `mcps` via `createMcpClientConfigService({configIO, knownCwds: () => [], paths?})` from `@blackbelt-technology/pi-dashboard-mcp-client-plugin/core` — hostless, global scope. Option `paths` (test seam) replaces the old `adapter`. Hardened atomic write moved to mcp-client `config-io.ts`; paths from `defaultLayerPaths`, so `PI_CODING_AGENT_DIR` is honoured. See change: extract-mcp-client-plugin, migrate-mcp-to-pi-builtin. |
| `src/bin/install.ts` | `pi-apple-tools-install [--check] [--path <p>]` CLI. Writes exactly ONE file (`~/.pi/agent/mcp.json`) in write mode; never the server plugin store. See change: migrate-mcp-to-pi-builtin. |
| `src/server/index.ts` | Plugin server entry. `ctx.consume<McpClientConfigService>("mcp-client.config")` at registration; absent → THROWS (fail closed — `dependsOn: ["mcp-client"]` guarantees ordering). `GET /api/apple-tools/status` (read-only, 10s TTL cache; iMCP readout via `readServerEntry("iMCP", {kind:"global"})`). `plugin_action` handler `run-installer` only (refuses the brew branch — delegates the long network install to the CLI). `set-disabled` / `set-direct-tools` DELETED — hard break, they live in mcp-client. Status readout fields `exposure` (display, default `codemode`) + `enabled` replace `directTools` + `disabled`. Path reconciliation via `updatePluginConfig` on the action path only. See change: extract-mcp-client-plugin, migrate-mcp-to-pi-builtin. |
| `src/client/index.tsx` | Intentionally empty client entry (`export {}`): the only claim loads lazily from `AppleToolsSettings.tsx` via manifest `module`. See change: lazy-plugin-claim-modules. |
| `src/client/AppleToolsSettings.tsx` | `AppleToolsSettings` settings-section panel (lazy `module`). Kit-only body, no identity header. `pillFor(status)` → `SettingsStatusPill` word (Checking / Not installed / Installed / macOS too old / …; raw state only as `data-status`), fix-naming `SettingsNotice` per state (Copy command / Check again / Copy details). Path = kit `TextField` draft on `useSettingsDraftSource` id `plugin:apple-tools`; commit sends ONLY `{ imcpServerPath }`, empty path = field error. Run installer: busy + `apple-tools-install-result` notice. Status 404 → `apple-tools-error` sentence + Try again + Copy details (code only copied). `useMissingDeps` banner hides installer. Non-macOS inert. Links `MANAGE_MCP_PATH`. See change: extract-mcp-client-plugin, retro-ux-plugin-settings-wave-2. |
| `src/client/__tests__/AppleToolsSettings.test.tsx` | Draft-source harness (`SettingsDraftProvider` + `PluginContextProvider`). Covers state→pill table (#E14), no identity text (#E7), owned-key commit (#F2), status-unavailable (#X3), installer busy/result. See change: retro-ux-plugin-settings-wave-2. |