AGENTS.md@packages/client/src/components/access-grant · git:20261021.aa266aa · 2026-10-21 · sha256 4f2d5e4a1b2de079

AGENTS.md@packages/client/src/components/access-grant git:20261021.aa266aaA

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

# DOX — packages/client/src/components/access-grant

Files in this directory. One row per source file.

| File | Purpose |
|------|---------|
| `GrantPromptDialog.tsx` | S1 held / S2 deferred access-grant dialog on client-utils `Dialog` (`size="md"`, non-flush, `testId="grant-dialog"`). Exports `GrantPromptDialog({prompt, now, queued, onAnswer})`. Subject = monospace headline (`grant-dialog-subject`, React text only); plane-specific title/reason; store named in `grant-dialog-consequence` before buttons. Footer order Deny (`Dialog.Cancel`), Allow once, Allow always — ALL `neutral` intent, none emphasised/focus-defaulted (initial focus = built-in close). Held: `grant-dialog-waiting` countdown from `expiresAt`. Deferred: `grant-dialog-deferred` pill, no countdown, allow-once OMITTED. Ladder (`grant-dialog-ladder`) only when `copy.ladder` non-empty: radios = denied subject + carried rungs, denied preselected, no free text, `grant-dialog-selected` beside answers. Allow once/always send selected rung; Deny + every dismissal send the denied subject. See change: add-access-grant-dialog (tasks 7.1, 7.2, 7.4, 7.5). Filesystem/cwd planes (`YOLO_PLANES`) render `GrantDialogYoloOffer` in the body, before the footer: dashed secondary affordance, NOT a verdict; activation never answers the pending denial (10.74). See change: add-access-grant-dialog (tasks 8b.7a) Path-plane prompts show the pi-trust checkbox; `onAnswer(verdict, subject, piTrust?)`. See change: mirror-dashboard-trust-to-pi. Title/plane/reason copy for `preview-egress`. See change: improve-canvas-html-and-url-ux. |
| `GrantPromptHost.tsx` | App-wide mount of the grant dialog (rendered in both App returns). Exports `GrantPromptHost({onMessage, send, ws, store?, loadPending?})`. `grant_channel` → `setGrantChannel`; `ws === null` → `clearGrantChannel`; `grant_request`/`grant_dismiss` → `GrantPromptStore.apply`. One dialog at a time (`queue[0]`, rest counted). Answer → `store.claim` gate → `grant_response` over WS (late answer after dismissal never sent). 1 s tick drives countdown + `store.expire`. Every (re)connect reconciles vs `GET /api/access/prompts` prompted entries. See change: add-access-grant-dialog (tasks 7.1-7.3) Sends `piTrust` with `grant_response`. See change: mirror-dashboard-trust-to-pi. |
| `PiTrustCheckbox.tsx` | "Also trust this folder in pi" checkbox + `usePiTrustChoice(source)` (seeded from source default). See change: mirror-dashboard-trust-to-pi. |
| `YoloAccessCard.tsx` | Access page YOLO card (S6). Exports `YoloAccessCard({yolo, base, store?, onChanged?})`. Active (`yolo-access-active`, `data-scope`): planes (filesystem, working directory), EVERY root + add time or "every folder" when unscoped, remaining (`yolo-access-remaining`; env = "until the server stops"), End now (`yolo-end` → `endYolo`). No dismiss control. Below: `YoloActivationForm` with `allowUnscoped`, `base` = selected session cwd. See change: add-access-grant-dialog (tasks 8b.7, 8b.7a, 8b.7b) Body copy + planes line name the agent path gate. See change: yolo-covers-agent-path-gate. |
| `YoloActivation.tsx` | Shared YOLO activation for three entry points, one server session. Exports `YoloActivationForm({yolo, base, allowUnscoped?, afterActivate?, store?, onChanged?})`, `GrantDialogYoloOffer({subject})` (base = denial subject, no unscoped, says the request still needs an answer), `DirectoryYoloAction({cwd})` (own folder pre-selected). Roots only from `fetchYoloRoots(base)`, `roots[0]` pre-selected, no free text; durations only from `durationsMinutes`, shortest pre-selected; unscoped (`yolo-unscoped-option`, warning tokens + `border-2` + bold) never pre-selected. Live session → add mode (`data-mode="add"`, no durations, `yolo-add-note` "timer is unchanged", `yolo-add-root`); unscoped live → `yolo-covers-all`. `available=false` → every control rendered disabled + `yolo-unavailable-reason`, never hidden (10.54). After POST → `yoloStatus.refresh()`. See change: add-access-grant-dialog (tasks 8b.7a, 8b.7b) A new `base` resets the root choice (no stale root from the previous folder; review 9.5). |
| `YoloIndicators.tsx` | Active-YOLO signals, undismissable, no live region, links to `/settings/access`. Exports `useYoloAppBar()` (sidebar `header-app-bar` props while live: orange `--severity-warning-bg` tint + inset `--accent-orange-text` underline, static `title`, `data-yolo`; no click handler, no 1 Hz tick, one `setTimeout` at expiry), `YoloBarLink` (first bar child, `absolute opacity-0`, revealed on focus; keyboard/AT path), `YoloComposerStrip({cwd})` (single-line `yolo-composer-strip` above the composer, scoped by `isCwdInYoloScope`; sentence link + time sibling `shrink-0 tabular-nums`, `∞` + sr-only `yolo.noExpiry` when never expiring), module-private `yoloCoverageSentence` (scope x expiry -> 4 static `yolo.coverage*` keys), helpers `useLiveYoloSession` (expired = inactive), `yoloRemainingLabel`, `yoloTone`. `useOpenAccess` leaves modified / non-primary clicks to the browser. `YoloPill` / `YoloSessionIndicator` removed (wrapped + grew rows, issue #898). Copy names agent + dashboard file access. See change: add-access-grant-dialog (8b.7), yolo-covers-agent-path-gate, fix-yolo-indicator-overflow. |
| `__tests__/GrantPromptDialog.test.tsx` | allow-always carries the pi-trust choice. See change: mirror-dashboard-trust-to-pi. |
| `__tests__/PiTrustCheckbox.test.tsx` | #F1: checkbox defaults + consequence text in worktree-init, pin, Add Folder, grant prompt. See change: mirror-dashboard-trust-to-pi. |