feat(TASK-050): bracket --macro runs like --execute and close the isolated-macro leak
The --macro dispatch arm now opens the top-level agent bracket before macro_execute and closes it signal-aware afterwards, draining pending hooks like the --execute arm; both bracket calls no-op without a loaded agent, so agent-less macro runs are unaffected. The isolated arm of macro_execute closes the bracket an in-macro .agent step opens on its fresh context, on the step-failure path too. Binary-level tests pin agent.started plus exactly one terminal event for the --agent flag and for in-macro .agent steps in both isolation modes, on success and failure.
This commit is contained in:
3 files changed
+249
-12
No files matched your search
+15
-5
@@ -83,12 +83,22 @@ pub async fn macro_execute(
|
||||
.bootstrap_tools(app.as_ref(), true, abort_signal.clone())
|
||||
.await?;
|
||||
|
||||
for step in ¯o_value.steps {
|
||||
let command = Macro::interpolate_command(step, &variables);
|
||||
println!(">> {}", multiline_text(&command));
|
||||
run_repl_command(&mut macro_ctx, abort_signal.clone(), &command).await?;
|
||||
// An in-macro `.agent` step opens the top-level agent bracket on this
|
||||
// fresh context, so it must also close here — on the step-failure path
|
||||
// too, or the run would leak `agent.started` with no terminal event.
|
||||
// Signal-aware like the headless dispatch arms: a ctrl-c'd macro
|
||||
// classifies as interrupted, not failed.
|
||||
let result = async {
|
||||
for step in ¯o_value.steps {
|
||||
let command = Macro::interpolate_command(step, &variables);
|
||||
println!(">> {}", multiline_text(&command));
|
||||
run_repl_command(&mut macro_ctx, abort_signal.clone(), &command).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
.await;
|
||||
macro_ctx.top_level_agent_finished(result.as_ref().err(), Some(&abort_signal));
|
||||
result
|
||||
}
|
||||
|
||||
struct MacroModeGuard<'a> {
|
||||
|
||||
Reference in new issue
Block a user