feat(background-task): rendu live des tâches de fond — subscriber UI + canal IPC (#58)
Câble un canal attachable au flux de sortie d'une tâche de fond (runner infrastructure + commande app-tauri + port/adaptateurs frontend) et le panneau ProjectWorkStatePanel s'y abonne pour un rendu live au lieu d'un état figé au dernier snapshot. Validations obtenues avant commit : - cargo test -p infrastructure --test background_task_runner : vert - cargo check -p backend -p app-tauri : vert - npx vitest run src/features/workstate/workstate.test.tsx : vert - npm run typecheck : vert - verdict QA #58 : vert Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@ -30,6 +30,7 @@ use application::{
|
||||
UpdateProjectMcpToolPermissionsInput, UpdateProjectPermissionsInput,
|
||||
UpdateProjectSystemPermissionsInput, UpdateSkillInput,
|
||||
};
|
||||
use backend::stream::OutputSink;
|
||||
use domain::ports::ModelServerRuntime;
|
||||
use domain::ports::PtyHandle;
|
||||
|
||||
@ -38,9 +39,9 @@ use crate::dto::{
|
||||
parse_layout_id, parse_memory_slug, parse_model_server_id, parse_node_id, parse_profile_id,
|
||||
parse_project_id, parse_session_id, parse_skill_id, parse_task_id, parse_template_id,
|
||||
parse_ticket_id, save_model_server_input, AgentDriftListDto, AgentDto, AgentListDto,
|
||||
AppExitWorkGuardStateDto, AssignSkillRequestDto, AttachLiveAgentRequestDto,
|
||||
AttachLiveAgentResponseDto, BackgroundTaskDto, ChangeAgentProfileDto,
|
||||
ChangeAgentProfileRequestDto, CloneOpenCodeProfileFromSeedRequestDto,
|
||||
AppExitWorkGuardStateDto, AssignSkillRequestDto, AttachBackgroundTaskResultDto,
|
||||
AttachLiveAgentRequestDto, AttachLiveAgentResponseDto, BackgroundTaskDto,
|
||||
ChangeAgentProfileDto, ChangeAgentProfileRequestDto, CloneOpenCodeProfileFromSeedRequestDto,
|
||||
CloneProfileFromSeedRequestDto, ConfigureProfilesRequestDto, ConversationDetailsDto,
|
||||
CreateAgentFromTemplateRequestDto, CreateAgentRequestDto, CreateLayoutRequestDto,
|
||||
CreateLayoutResultDto, CreateMemoryRequestDto, CreateProjectRequestDto, CreateSkillRequestDto,
|
||||
@ -77,6 +78,7 @@ use crate::embedded_server::{
|
||||
};
|
||||
use crate::pty::{PtyBridge, PtyChunk};
|
||||
use crate::state::{AppState, FocusedProjectDto};
|
||||
use crate::stream::TauriChannelSink;
|
||||
use domain::{DeviceId, SkillRef, SkillScope};
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -3745,6 +3747,54 @@ pub async fn retry_background_task(
|
||||
.map_err(ErrorDto::from)
|
||||
}
|
||||
|
||||
/// `attach_background_task` — attach a UI output subscriber to a command-backed
|
||||
/// background task.
|
||||
///
|
||||
/// If the task is still live, the response contains PTY scrollback and a fresh
|
||||
/// live subscription is pumped to `on_output`. If it is already terminal, the
|
||||
/// response contains only the persisted output tail and no PTY subscription is
|
||||
/// attempted.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an [`ErrorDto`] (`INVALID` for malformed id, `NOT_FOUND` if the task
|
||||
/// has no live handle and no terminal result, `PROCESS`/`STORE` on backend
|
||||
/// failure).
|
||||
#[tauri::command]
|
||||
pub async fn attach_background_task(
|
||||
task_id: String,
|
||||
on_output: Channel<PtyChunk>,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<AttachBackgroundTaskResultDto, ErrorDto> {
|
||||
let id = parse_task_id(&task_id)?;
|
||||
let plan = state
|
||||
.background_task_attach_plan(id)
|
||||
.await
|
||||
.map_err(ErrorDto::from)?;
|
||||
let live = plan.live_handle.is_some();
|
||||
|
||||
if let Some(handle) = plan.live_handle {
|
||||
match state.pty_port.subscribe_output(&handle) {
|
||||
Ok(stream) => {
|
||||
std::thread::spawn(move || {
|
||||
let sink = TauriChannelSink::new(on_output);
|
||||
for chunk in stream {
|
||||
if sink.send(chunk).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => return Err(ErrorDto::from(AppError::from(e))),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(AttachBackgroundTaskResultDto {
|
||||
task_id: plan.task_id.to_string(),
|
||||
scrollback: plan.scrollback,
|
||||
live,
|
||||
})
|
||||
}
|
||||
|
||||
/// `list_background_tasks` — read the background-task read-model for a project,
|
||||
/// optionally narrowed to one owning agent.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user