Merge origin/master (plan line #590) into web-permission-sandbox-merge-master

Shared-surface conflicts resolve as unions: the fixture serves all five
projection keys (title/todos/permissions/plan/goal) with the /permission
and /plan command mirrors side by side, the connection specs assert the
five-key baseline and the shifted approval/question replay indices, and
the cli roster/deps, tsconfig aggregate, and README allowlist carry both
lines' rows. Plan-side content lands verbatim from master.

One end-state consolidation both branches half-did: with questions
(ui-question) and approvals (ApprovalPanel) each owning a composer
takeover, PendingCard retires outright — ChatView renders no pending
placeholder, the card component and its specs go, and both README halves
state the takeover-only contract.
This commit is contained in:
imccyu
2026-07-29 03:52:55 +08:00
70 changed files with 1453 additions and 289 deletions

View File

@@ -218,12 +218,14 @@ export class Session implements SessionFace {
this.notifier.markDirty()
return result
}
// Blank flips on ACCEPTANCE, not attempt: an accepted prompt has logged
// its user/message on the host (events.length > 0 is fact, not
// optimism), while a rejected first prompt must keep the session blank
// — the client-side blank mirror only ever lowers, so flipping early on
// a failure would surface the session forever and strip its
// connectWorkspace reuse eligibility against the host's authority.
// Blank flips on ACCEPTANCE, not attempt: an accepted prompt starts the
// conversation's first turn on the host (the host criterion — a logged
// turn/start — is fact, not optimism; standalone command and projection
// events never flip it), while a rejected first prompt must keep the
// session blank — the client-side blank mirror only ever lowers, so
// flipping early on a failure would surface the session forever and
// strip its connectWorkspace reuse eligibility against the host's
// authority.
if (this.blankBit) {
this.blankBit = false
this.options.onEngaged?.(this)