Plan P3 / spec §10.3.1 / §21.5.
Mirrors the connector-gate's auto oauth-prompt pattern: when the
EFFECTIVE pipeline (consumer-declared OR scenario-fallback) contains
a stage whose atoms[] list `diff-review`, applyPlugin() now
synthesises an implicit `choice` GenUI surface so the user can
accept / reject / partial without the plugin author having to
declare the surface by hand.
apps/daemon/src/plugins/atoms/auto-surfaces.ts:
deriveAutoAtomSurfaces({ pipeline }) → GenUISurfaceSpec[]
For each stage that lists 'diff-review', emits one surface:
id: '__auto_diff_review_<stageId>'
kind: 'choice'
persist: 'run' (per-run; user sees one prompt
per cycle through the stage)
trigger: { stageId, atom: 'diff-review' }
schema: { decision: ['accept' | 'reject' | 'partial'],
accepted_files: string[],
rejected_files: string[],
reason: string }
required: ['decision']
timeout: 24 h (a diff review may sit overnight)
onTimeout: 'abort'
apply.ts integration:
- Auto-surface derivation moved AFTER the bundled-scenario
fallback resolution (P3 / O1) so a consumer that inherits
the bundled scenario's diff-review stage still gets the
auto-surface.
- Plugin-author-declared surface with the same id wins, via
the existing mergeAutoOAuthPrompts dedupe (re-used so we
don't duplicate dedupe logic).
Daemon tests: 1608 → 1614 (+6 cases on plugins-auto-surfaces:
multi-stage diff-review surface fan-out, no-pipeline returns
empty, no-diff-review returns empty, plugin-declared pipeline
integration, scenario-fallback pipeline integration, plugin-
author-declared surface with same id wins).
Co-authored-by: Tom Huang <1043269994@qq.com>