fix(cron): add stop button for automated tasks in web UI#35
Conversation
Add a Stop button to the shared session composer for active cron sessions, wired to a new `abort()` action that clears todos and calls the session abort endpoint. On the server, `SessionRoutes.abort` now cancels the linked `cronRunID` via `CronScheduler.cancelRun` before aborting the prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: codeplane-agent[bot] <287208015+codeplane-agent[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a user-facing “Stop” control for active cron-driven sessions in the session composer UI, and wires it through to the server abort endpoint so that stopping a session also cancels the associated cron run.
Changes:
- App: Introduces an
abortingflag +abort()action in the session composer state, and exposesworking/abortingaccessors for UI use. - App UI: Renders a Stop button in the read-only bar for cron sessions while the session is working.
- Server: Enhances
session.abortto cancel the linked cron run (CronScheduler.cancelRun) before aborting the session prompt.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/app/src/pages/session/composer/session-composer-state.ts | Adds abort state/action and exposes aborting() + working for the Stop UI wiring. |
| packages/app/src/pages/session/composer/session-composer-region.tsx | Displays Stop button for working cron sessions in the read-only bar. |
| packages/codeplane/src/server/routes/instance/session.ts | Cancels associated cron run before proceeding with prompt/session abort. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const abort = () => { | ||
| const id = params.id | ||
| if (!id || store.aborting) return | ||
|
|
||
| batch(() => { | ||
| globalSync.todo.set(id, []) | ||
| sync.set("todo", id, []) | ||
| sync.set("session_status", id, idle) | ||
| setStore("aborting", true) | ||
| }) | ||
|
|
||
| sdk.client.session | ||
| .abort({ sessionID: id }) | ||
| .catch((err: unknown) => { | ||
| const description = err instanceof Error ? err.message : String(err) | ||
| showToast({ title: language.t("common.requestFailed"), description }) | ||
| }) | ||
| .finally(() => setStore("aborting", false)) | ||
| } |
| const info = yield* session.get(sessionID).pipe( | ||
| Effect.catch(() => Effect.succeed(undefined as Session.Info | undefined)), | ||
| ) |
| const abort = () => { | ||
| const id = params.id | ||
| if (!id || store.aborting) return | ||
|
|
||
| batch(() => { | ||
| globalSync.todo.set(id, []) | ||
| sync.set("todo", id, []) | ||
| sync.set("session_status", id, idle) | ||
| setStore("aborting", true) | ||
| }) | ||
|
|
||
| sdk.client.session | ||
| .abort({ sessionID: id }) | ||
| .catch((err: unknown) => { | ||
| const description = err instanceof Error ? err.message : String(err) | ||
| showToast({ title: language.t("common.requestFailed"), description }) | ||
| }) | ||
| .finally(() => setStore("aborting", false)) | ||
| } |
| const info = yield* session.get(sessionID).pipe( | ||
| Effect.catch(() => Effect.succeed(undefined as Session.Info | undefined)), | ||
| ) |
Triage — Keep OpenConfirmed real defects in this PR. Copilot review flagged them; no past agent commentary here. Defects found
Why not closeThe abort rollback gap is a real UX bug — users see a falsely-idle session after a failed abort. The type assertion is a real correctness concern. Keep open. |
Review: stop button for automated tasks in web UIStatus: Merge candidate All CI checks are green. The server-side abort handler correctly cancels the linked cron run via CronScheduler.cancelRun before proceeding with prompt abort. This pairs cleanly with PR #34's UI changes. |
Summary
abort()action that clears todos and calls the session abort endpointCronScheduler.cancelRunbefore aborting the prompt on the serverChanges
packages/app/src/pages/session/composer/session-composer-state.ts: addedabortingflag,abort()action (clears todos, sets idle, callssdk.client.session.abort), and exportedaborting()accessor +workingaliaspackages/app/src/pages/session/composer/session-composer-region.tsx: renders a Stop button (variant="secondary") for active cron sessions within the read-only barpackages/codeplane/src/server/routes/instance/session.ts:SessionRoutes.abortnow checkssession.cronRunIDand cancels it viaCronScheduler.cancelRunbefore proceeding with the prompt abortVerification
bun --cwd packages/app typecheck— 0 errorsbun --cwd packages/codeplane typecheck— 1 pre-existing error insrc/mcp/index.ts(Zod schema mismatch, unrelated)