git:20260923.f827e38 to git:20261006.e23e533
2 added, 2 removed. Audit A to A.
# 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) |
| `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) |
- | `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) |
+ | `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 indicators, undismissable (no close control, no hide state), link to `/settings/access`. Exports `YoloPill` (sidebar header row 1 beside `TunnelButton`; absent when inactive/expired; `m:ss` or `∞`), `YoloSessionIndicator({cwd})` (session surface when `isCwdInYoloScope`; peer of the pill, shows without the sidebar), helpers `useLiveYoloSession` (expired = inactive), `yoloRemainingLabel`, `yoloTone` (scoped = warning tokens, unscoped = warning tokens + `border-2` + bold + "everywhere" (never error, ui-plan S6)). `data-scope` scoped/unscoped. See change: add-access-grant-dialog (tasks 8b.7) |
+ | `YoloIndicators.tsx` | Active-YOLO indicators, undismissable (no close control, no hide state), link to `/settings/access`. Exports `YoloPill` (sidebar header row 1 beside `TunnelButton`; absent when inactive/expired; `m:ss` or `∞`), `YoloSessionIndicator({cwd})` (session surface when `isCwdInYoloScope`; peer of the pill, shows without the sidebar), helpers `useLiveYoloSession` (expired = inactive), `yoloRemainingLabel`, `yoloTone` (scoped = warning tokens, unscoped = warning tokens + `border-2` + bold + "everywhere" (never error, ui-plan S6)). `data-scope` scoped/unscoped. See change: add-access-grant-dialog (tasks 8b.7) Copy names agent + dashboard file access. See change: yolo-covers-agent-path-gate. |