Merge origin/master (single-exe pipeline #253, duplication lint #281, side-sessions RFC)

Beyond line merges: python/sdk-runtime's deploy manifest gains
@deepseek-ai/dsh-mode — the single-exe closure gate
(verify-runtime-closure) requires every workspace peer of dsh-acp, and
the bridge's type-only peer edge on dsh-mode counts; the AGENTS.md
efficiency section is condensed to fit the 1820-word ceiling after
master's single-exe additions. Catalogs and graphs regenerated.
This commit is contained in:
kingwl
2026-07-14 10:46:09 +08:00
145 changed files with 11508 additions and 585 deletions

View File

@@ -110,6 +110,8 @@ export const name = 'acp'
// because `initialize` advertises `loadSession: true`. `tools` lets a tool own
// how its calls render (`presentCall`/`presentResult`); the bridge looks up the
// definition by name and falls back to a generic presentation when absent.
// TODO(acp-session-inject): drop `sessions`; this bridge never reads
// ctx.sessions, and agent/session ownership is already behind ctx.agents.
export const inject = ['agents', 'sessions', 'sessionPersistence', 'tools', 'userInteraction']
/**
@@ -362,10 +364,13 @@ export function apply(ctx: Context, config: AcpConfig): void {
// this warn sink so a throwing tool presenter is logged, not propagated.
const makePresenter = (agent?: Agent): ToolPresenter => new ToolPresenter(tools, (message) => { logger.warn(message) }, agent)
// TODO(derive-acp-session-id): derive an event's id from agent.session and
// verify sessions.get(id)?.agent === agent; then remove this reverse map and
// SessionRecord.sessionId, whose sole read duplicates the same identity.
// Live sessions keyed by id (RFC 011 multi-session), plus an agent→sessionId
// reverse map so `agent/*` events (which carry only the Agent) demux in O(1).
// The two stay in lockstep: a record is added to `sessions` and the agent to
// `bySession` together, and removed together.
// The forward record and weak reverse entry are installed together; removing
// the record releases its strong Agent reference, so the WeakMap entry expires.
const sessions = new Map<SessionId, SessionRecord>()
const bySession = new WeakMap<Agent, SessionId>()
// Session ids whose `session/load` is mid-`resume()` (the slot is reserved