feat(authorization): obtain a credential by asking the human

Some credentials cannot be configured, only obtained: getting one means
a conversation — open this page, paste that code, pick an account. The
new seam owns that conversation and the one-attempt-per-key lifecycle,
and never the protocol, so a second authorization protocol arrives as
another flow rather than as another seam.

A flow is registered under the CredentialKey it writes, which is also
how the seam knows which plugin answers for the format inside that
record. The flow owns the write: run() resolving means the record is
already committed through ctx.credentials, and the seam confirms it.
That keeps a library persisting through its own store adapter the
single writer instead of being copied back out and written twice.

The interaction travels with the request rather than a registry,
because whoever starts an authorization is the one who can talk to the
human about it. A request already withdrawn never claims the key and
never starts the flow — relying on each flow to check its signal before
the first await would let one that does not hang holding the key.
This commit is contained in:
Yichen Jiang
2026-08-20 17:58:38 +08:00
parent 86a9f8c862
commit 732a7361f5
36 changed files with 1468 additions and 23 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ packages/ @deepseek-ai/dsh-<pkg> workspaces at packages/<group>/<pkg>/
session/ durable session data: persistence, projection, titles, telemetry
identity/ anonymous identity
settings/ user-settings capability + file provider
credentials/ credential-reference capability + env/.env provider
credentials/ credential/authorization capabilities + env/.env provider
acp/ automation-only Agent Client Protocol server
interaction/ approval/interaction capabilities, permission, commands, ask-user
boot/ shared app-bin glue