feat(host): add workflows.list and teams.* sidebar routes

- workflows.list folds tool-workflow/* session events (the same four types
  the official workflow-run panel folds) across the whole session tree,
  merging the stored log with a live session/event mirror deduped by seq;
  absence of events yields an empty list, never an error.
- teams.view / teams.taskCreate / teams.taskUpdate ride the experimental
  agentTeams service's Remote vocabulary with structural degradation:
  layer absent -> {available:false}; root leads no team -> {team:null};
  CAS conflicts pass through the service's own result union.
- wire gains the team-error code; context-types gains structural mirrors
  of the team view/request vocabulary (no experimental package import).
- 29 unit tests across fold, route merging/degradation, and CAS shaping.
This commit is contained in:
Menghuan1918
2026-09-27 22:18:14 +08:00
parent ad6b0b1486
commit c445495f8b
9 changed files with 1016 additions and 0 deletions
+71
View File
@@ -275,6 +275,77 @@ export interface SidebarAgentPresetsService {
mount(agentCtx: unknown, presetId: string): Promise<void>
}
/**
* The experimental Agent Teams service face (`ctx.agentTeams`, mounted only
* when the deployment loads `dsh-experimental-agent-team-profile`; absent →
* `ctx.get` returns undefined and the Teams block hides). Only the
* browser-facing Remote vocabulary the Tasks page needs is mirrored —
* structurally, so the plugin never imports the experimental package.
*/
export interface SidebarAgentTeamsService {
/** The agent's team membership, or undefined for a non-team/stale agent. */
tryMembership(agent: unknown): unknown
/** The point-in-time team snapshot the official panel renders. */
remoteView(agent: unknown): Promise<{ members: SidebarTeamMemberView[]; tasks: SidebarTeamTaskView[] }>
/** Create one shared task (CAS-free; ids are server-issued). */
remoteCreateTask(agent: unknown, req: SidebarCreateTeamTaskRequest): Promise<SidebarTeamTaskMutationResult>
/** Compare-and-set mutation of one shared task (stale revision → conflict). */
remoteUpdateTask(agent: unknown, req: SidebarUpdateTeamTaskRequest): Promise<SidebarTeamTaskMutationResult>
}
/** One team member as the runtime-enriched view reports it. */
export interface SidebarTeamMemberView {
/** The member's session id (the teammate's child session under the lead). */
id: string
name: string
role: 'lead' | 'teammate'
status: 'running' | 'idle' | 'inactive' | 'provisioning' | 'failed'
description?: string
provider?: string
context?: 'fresh' | 'fork'
model?: string
diagnostics: string[]
}
/** One shared task-board row (durable fields plus derived readiness). */
export interface SidebarTeamTaskView {
id: string
revision: number
subject: string
description: string
status: 'pending' | 'in_progress' | 'completed' | 'deleted'
ownerName?: string
blockedBy: string[]
writeScopes: string[]
ready: boolean
writeScopeWarnings: string[]
}
/** Input for creating one shared task. */
export interface SidebarCreateTeamTaskRequest {
subject: string
description: string
blockedBy?: readonly string[]
writeScopes?: readonly string[]
}
/** Input for one CAS task mutation. */
export interface SidebarUpdateTeamTaskRequest {
taskId: string
expectedRevision: number
action: 'claim' | 'release' | 'edit' | 'set_dependencies' | 'complete' | 'reopen' | 'reassign' | 'delete'
subject?: string
description?: string
blockedBy?: readonly string[]
writeScopes?: readonly string[]
owner?: string
}
/** Browser task-mutation result (stale revisions kept distinct, passthrough). */
export type SidebarTeamTaskMutationResult =
| { ok: true; value: SidebarTeamTaskView }
| { ok: false; error: { code: 'team-task-conflict' | 'team-rejected'; message: string } }
/** The host session-title service face (mirror of the sessionTitle service). */
export interface SidebarSessionTitleService {
/** Rename one live session's title (pins it against auto-regeneration). */