feat(cli): extend --detach to workflow approve/reject/resume control verbs - #2204
feat(cli): extend --detach to workflow approve/reject/resume control verbs#2204buun-dev wants to merge 5 commits into
Conversation
📝 WalkthroughWalkthroughChangesDetached execution now supports Detached workflow controls
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant WorkflowCommand
participant DetachedChild
CLI->>WorkflowCommand: dispatch workflow control command with --detach
WorkflowCommand->>WorkflowCommand: perform read-only validation
WorkflowCommand->>DetachedChild: spawn same command without --detach or --json
WorkflowCommand-->>CLI: return human or JSON acknowledgement
DetachedChild->>DetachedChild: execute workflow mutation and continuation
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Good direction — unattended control verbs are squarely on the roadmap ( 1. Rebase onto current Your branch does not contain So as this PR stands, 2. Make the precheck a shared validator rather than a copy of one branch. The parent's read-only precheck replicates one of the four preconditions. The other three — Please extract something like 3.
That may well be the behavior you want — but it has to be stated, and callers need to be able to tell. Please:
4. Spawn with the command's
5. Please fill in One thing worth knowing rather than fixing: the detach ack is gated only on the child having a PID, so any child that starts and immediately dies reports as a created run. That's pre-existing (#2279) and it's why #2248 hid for a whole release — but this PR widens that surface from |
…verbs
--detach today only covers `workflow run`. But approve/reject/resume each
trigger a LONG inline execution when they act on a paused run — approve's
auto-resume, reject's on_reject rework, resume's re-run — hosted in the
calling shell. If that shell dies (a reaped automation task, a closed
terminal, a dropped SSH session), the run is left wedged mid-execution and
needs a manual recovery. That makes the control verbs unsafe to drive from
unattended automation.
Add --detach to all three verbs via a shared helper, runDetachedControlCommand:
it validates the run READ-ONLY (a precheck that refuses a non-paused run and
spawns nothing), then hands the whole command to a detached child — reusing
the existing spawnDetachedWorkflowRun, which rebuilds argv minus
--detach/--json — that owns ALL state mutation in its own process group. The
parent never mutates, so the decision is recorded exactly once, in the child
(mirroring `workflow run --detach`, where the parent likewise does nothing).
The child is spawned with the PARENT's cwd, never the run's working_path: the
child re-resolves everything by run-id, and an isolation-container run's
working_path can be a path the host cannot spawn into (ENOENT would make the
detach silently no-op).
Composes with --json (structured { ok, runId, action, detached, logPath } ack;
nothing executes in the parent). Signatures gain a `detach?` param after the
existing `cwd?`: (runId, [comment/reason], json?, cwd?, detach?).
Tests: approve/reject/resume each spawn a detached child with zero parent-side
mutation; --detach --json ack shape; precheck refuses a non-paused run and
spawns nothing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed control-verb gate
The CLI's read-only --detach precheck replicated only ONE of approveWorkflow's
four preconditions. The other three — missing approval context, child_workflow
gate, already-resolved — acked { ok: true } in the parent and then threw unseen
in the detached child's log: the exact failure --detach exists to prevent,
occurring on the surface nobody watches.
Extract the gate into two validators in workflow-operations and call them from
both the operations and the CLI precheck, so there is one gate rather than two
copies that drift silently in this direction again.
The two signatures differ deliberately: reject has no nodeId requirement (it
falls back to approval?.nodeId ?? 'unknown' for its audit event), so a run with
malformed approval metadata stays rejectable. resume needs no change — its
precheck already calls resumeWorkflow directly.
Error strings are copied verbatim; the pre-existing child_workflow refusal tests
pass unchanged, which is the proof the extraction is behavior-preserving.
…t in the ack buildDetachedRunCmd strips --json from the child argv, so the child takes the ordinary inline path and drives the run onward. Bare --json documents the opposite — it records the decision and withholds the auto-resume so the caller drives continuation. --detach --json therefore did the reverse of --json with nothing saying so. Keep the behavior (withholding continuation under --detach would leave a spawn that only records a decision, which is what bare --json already does) and make it legible: document the divergence in the CLI reference and CLAUDE.md, and add continues: true to the ack so an automation can tell whether it still owns continuation. Test asserts the child argv carries neither flag.
runDetachedControlCommand passed process.cwd() and discarded the --cwd that cli.ts had already threaded in. buildDetachedRunCmd appends --cwd last and the parser is last-wins, so a caller-supplied --cwd was overridden both in the spawn option and on the child argv — stranding the child in the parent's directory, possibly outside any git repo, after the parent had acked success. workflowRunCommand already passes its resolved cwd; only the control verbs regressed. Take cwd as a parameter and pass cwd ?? process.cwd(). The run's working_path remains a non-candidate: a container run's working_path is a distro path the host cannot spawn into, so the child still re-resolves everything by run id.
991707c to
6af8eb2
Compare
… too The Detached control verbs section lives under `workflow approve`, so a reader in the `workflow resume` section still saw the un-inverted contract: "--json validates and acks but does NOT re-execute inline". Under --detach it does re-execute. Cross-reference it where that claim is made.
|
Thanks — this was a good catch on item 2 in particular; it was the real defect and the rest 1. Rebase onto current The branch was 40 commits behind. Rebased clean, no conflicts. Two things came with it that
2. The read-only precheck replicating only one of You're right about the defect: the parent checked only Fixed by extracting the gate into Correction on the shape: the gates are not symmetric, so this is two validators, not one.
The extraction is behavior-preserving: error strings are copied verbatim, and the two 3. The You were right that it was unstated. I kept the behavior rather than "fixing" it: withholding continuation under All three locations you named are covered: the
4. Passing the caller's
This doesn't reopen the 5. PR template + compiled-binary verification — done. The PR body is rewritten from On the binary: agreed that
One thing I did not fix, flagged rather than folded in: the detach ack is gated only on the Also out of scope, deliberately: Commits on the branch (post-rebase):
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
packages/cli/src/commands/workflow.ts (1)
2304-2306: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winWarn when the child log file could not be opened.
workflowRunCommandprints an explicit warning whenlogPathis falsy (lines 939-943), because the child then runs with its output discarded. The control-verb path stays silent in that case. The user gets a success message with no trail if the child dies early. Add the same warning for parity.♻️ Proposed change
console.log(`Started '${action}' for run ${runId} in the background.`); console.log(`Track it with: archon workflow get ${runId}`); - if (logPath) console.log(`Child output: ${logPath}`); + if (logPath) { + console.log(`Child output: ${logPath}`); + } else { + console.warn('Warning: could not open a log file — child output will not be captured.'); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/commands/workflow.ts` around lines 2304 - 2306, Update the background control-verb output in workflowRunCommand to emit the same explicit warning used when logPath is falsy, indicating that child output is being discarded. Preserve the existing Child output message when logPath is available and keep the success and tracking messages unchanged.packages/cli/src/commands/workflow.test.ts (1)
3274-3279: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the approval gate mocks for detached approve/reject.
approveWorkflowusesworkflowDb.resolveApprovalGate, andrejectWorkflowusesworkflowDb.resolveApprovalGateorworkflowDb.resolveAndCancelApprovalGate. Keeping onlyupdateWorkflowRunasserts these two existing mocks under-enforces the “parent does not record the decision” invariant. Add the gate-call assertions to both the approve and reject detach tests.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/commands/workflow.test.ts` around lines 3274 - 3279, Update both detached approve and detached reject tests around the existing updateWorkflowRun and executeWorkflow assertions to also verify the relevant approval-gate mocks were not called: resolveApprovalGate for approve, and resolveApprovalGate or resolveAndCancelApprovalGate for reject. Preserve the existing zero-call assertions and ensure each test checks that the parent does not resolve or cancel the approval gate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/docs-web/src/content/docs/reference/cli.md`:
- Around line 340-350: Update the documented `runDetachedControlCommand`
response example and accompanying description to state that `logPath` may be
null when the detached workflow cannot open its log file; clarify that
automation must not assume it is always a string path.
- Around line 322-324: Update the `approve`, `reject`, and `resume`
documentation sentence to replace “the same four/three preconditions” with a
description that the parent performs the same read-only validation checks as the
operation, preserving the listed wrong-status, missing-context,
child_workflow-blocked, and already-resolved refusal cases.
---
Nitpick comments:
In `@packages/cli/src/commands/workflow.test.ts`:
- Around line 3274-3279: Update both detached approve and detached reject tests
around the existing updateWorkflowRun and executeWorkflow assertions to also
verify the relevant approval-gate mocks were not called: resolveApprovalGate for
approve, and resolveApprovalGate or resolveAndCancelApprovalGate for reject.
Preserve the existing zero-call assertions and ensure each test checks that the
parent does not resolve or cancel the approval gate.
In `@packages/cli/src/commands/workflow.ts`:
- Around line 2304-2306: Update the background control-verb output in
workflowRunCommand to emit the same explicit warning used when logPath is falsy,
indicating that child output is being discarded. Preserve the existing Child
output message when logPath is available and keep the success and tracking
messages unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e408ba16-7097-4ed5-b9e1-cb0ad6a58aee
📒 Files selected for processing (7)
CLAUDE.mdpackages/cli/src/cli.tspackages/cli/src/commands/workflow.test.tspackages/cli/src/commands/workflow.tspackages/core/src/operations/workflow-operations.test.tspackages/core/src/operations/workflow-operations.tspackages/docs-web/src/content/docs/reference/cli.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/cli/src/cli.ts
| `approve`, `reject`, and `resume` accept `--detach`. The parent validates the run | ||
| **read-only** — the same four/three preconditions the operation itself enforces, so a | ||
| wrong-status, missing-context, `child_workflow`-blocked, or already-resolved run is |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Replace "four/three preconditions" with a description of the checks.
The phrase "the same four/three preconditions" exposes an internal count that differs between approve and reject, and the count will drift when the validators change. The sentence already lists the refusal cases, so state the guarantee instead of the number.
📝 Proposed wording
-`approve`, `reject`, and `resume` accept `--detach`. The parent validates the run
-**read-only** — the same four/three preconditions the operation itself enforces, so a
-wrong-status, missing-context, `child_workflow`-blocked, or already-resolved run is
-refused synchronously and nothing is spawned — then hands the whole command to a
+`approve`, `reject`, and `resume` accept `--detach`. The parent validates the run
+**read-only** with the same preconditions the operation itself enforces, so a
+wrong-status, missing-context, `child_workflow`-blocked, or already-resolved run is
+refused synchronously and nothing is spawned. The parent then hands the whole command to a📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `approve`, `reject`, and `resume` accept `--detach`. The parent validates the run | |
| **read-only** — the same four/three preconditions the operation itself enforces, so a | |
| wrong-status, missing-context, `child_workflow`-blocked, or already-resolved run is | |
| `approve`, `reject`, and `resume` accept `--detach`. The parent validates the run | |
| **read-only** with the same preconditions the operation itself enforces, so a | |
| wrong-status, missing-context, `child_workflow`-blocked, or already-resolved run is | |
| refused synchronously and nothing is spawned. The parent then hands the whole command to a |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/docs-web/src/content/docs/reference/cli.md` around lines 322 - 324,
Update the `approve`, `reject`, and `resume` documentation sentence to replace
“the same four/three preconditions” with a description that the parent performs
the same read-only validation checks as the operation, preserving the listed
wrong-status, missing-context, child_workflow-blocked, and already-resolved
refusal cases.
| ```json | ||
| { | ||
| "ok": true, | ||
| "runId": "…", | ||
| "action": "approve", | ||
| "detached": true, | ||
| "continues": true, | ||
| "workflowName": "assist", | ||
| "logPath": "~/.archon/logs/detached-run-<id>.log" | ||
| } | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Document that logPath can be null.
runDetachedControlCommand puts the return value of spawnDetachedWorkflowRun into logPath. The workflow run --detach path treats a falsy value as "could not open a log file", so the field is not always a path. State that logPath is null when the log file could not be opened, so an automation does not assume a string.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/docs-web/src/content/docs/reference/cli.md` around lines 340 - 350,
Update the documented `runDetachedControlCommand` response example and
accompanying description to state that `logPath` may be null when the detached
workflow cannot open its log file; clarify that automation must not assume it is
always a string path.
…'s own dev carried its own --detach control-verb implementation (248af22), predating PR coleam00#2204. The PR branch carries the same feature after maintainer review: a shared assertApprovable/assertRejectable gate instead of a status-only precheck, `continues: true` on the --detach --json ack, and the caller's --cwd threaded to the spawned child. All 11 conflict hunks were supersessions rather than disagreements — same code, reviewed version — so each resolved to the PR side: runDetachedControlCommand signature 4 args -> 5 (cwd inserted) spawn cwd process.cwd() -> cwd ?? process.cwd() approve precheck status only (1 of 4) -> assertApprovable reject precheck status only (1 of 3) -> assertRejectable ack payload no continues -> continues: true test fixture metadata: {} -> a real approval context two test hunks empty on our side -> +163 lines Resolved hunk-by-hunk, NOT `checkout --theirs`: dev's --base threading and container-ctx-on-resume work had auto-merged into other regions of the same file, and taking it wholesale would have dropped them silently. Verified after: the --base references and the PR's fixes coexist. Verified: type-check 11/11, lint --max-warnings 0, format:check, workflow.test 201 pass (199 from the PR plus 2 of dev's own, so nothing was overwritten), workflow-operations 49 pass, and bun run test across all 8 test-bearing packages. The sole failure is @archon/providers' broken-symlink case at EPERM — Windows refusing symlink creation without elevation, identical on an unmerged tree.
Summary
--detachexisted only onworkflow run. The control verbs (approve,reject,resume) hosted the executor in the calling shell, so a reaped shell — a harness task, a closed terminal, a dropped SSH session — left the run wedged mid-resume: approval recorded, workflow never continued.--detachnow works on all three control verbs. The parent validates the run read-only and spawns a detached child that owns every state mutation in its own process group. The precondition gate is extracted intoassertApprovable/assertRejectablein@archon/coreso the parent's precheck and the operation itself are literally the same code.--detach --jsongainscontinues: true, and the child is now spawned with the caller's--cwd.resumeWorkflow's gate (its precheck already called the shared operation). No change to the chat/HTTP/manage_runsurfaces beyond the behavior-preserving extraction.workflow run --detachis untouched.UX Journey
Before
After
Architecture Diagram
Before
After
Connection inventory (list every module-to-module edge, mark changes):
cli/commands/workflow.ts(approve precheck)core/operations/workflow-operations.assertApprovablecli/commands/workflow.ts(reject precheck)core/operations/workflow-operations.assertRejectablecore.approveWorkflowcore.assertApprovablecore.rejectWorkflowcore.assertRejectablerunDetachedControlCommandspawnDetachedWorkflowRuncwd, notprocess.cwd()cli/cli.tsworkflow{Approve,Reject,Resume}Command--detach(5th arg, after upstream'scwd)cli/commands/workflow.ts(resume precheck)core.resumeWorkflowcore.{approve,reject}Workflowdb/workflows.resolveApprovalGatemanage_run/ HTTP APIcore.{approve,reject}WorkflowLabel Snapshot
risk: lowsize: Mcli,core,docscli:workflow,core:operationsChange Metadata
feature(with an embeddedbugfix forcwd, and arefactorfor the shared gate)cliLinked Issue
--detachagainst real paused runs. Stating that explicitly rather than leaving the field blank.workflow run), but this PR widens that surface fromrunto the control verbs, which is precisely why the shared validator matters: it moves the four/three refusal cases from "child dies unseen" to "parent refuses synchronously".devso it now contains fix(cli): drop Bun SFE virtual argv[1] from detached re-invoke (#2248) #2273's Bun SFE argv fix and test(cli): build the web-dist tarball fixture in-process instead of spawning tar #2310'sdownloadWebDistCI fix.)Validation Evidence (required)
Evidence provided:
packages/cli/src/commands/workflow.test.ts: 199 pass / 0 fail (193 pre-change baseline + 6 new).packages/core/src/operations/workflow-operations.test.ts: 49 pass / 0 fail (41 baseline + 8 new).child_workflowrefusal tests pass unchanged. That is the proof the gate extraction is behavior-preserving — the error strings were copied verbatim, so no caller-visible message changed.manage-run-tool.test.ts(the only file thatmock.modulesworkflow-operations) passes unchanged at 30/30. Becausemock.module()merges rather than replaces, the two new exports keep their real implementations there;manage-run-tool.tscalls only the mocked operations, never the validators.If any command is intentionally skipped, explain why:
bun run validatecannot complete on a Windows host: the chain reachesbun run test:install, andscripts/test-install.shexits immediately withWindows is not supported. Please use WSL2. The eight checks before it all pass; the&&chain then short-circuits, sobun run testwas run separately.bun run test(full per-package sweep, all 8 test-bearing packages) produced exactly one failure:@archon/providers→pathKind > returns "missing" for a broken symlink without throwing, failing withEPERM: operation not permitted, symlink. That is Windows refusing symlink creation without elevation/Developer Mode — an environment limit in a package this branch does not touch. Every other package passed.Security Impact (required)
--detachre-invokes the same CLI with the same argv minus--detach/--json; the child has exactly the parent's authority.runDetachedControlCommandpreviously spawned intoprocess.cwd()regardless of the caller's--cwd. It now spawns into thecwdthe caller actually asked for. This reduces the set of directories a detached child can land in and removes a case where the child could be started outside any git repo after the parent had already acked success. The run'sworking_pathremains a non-candidate by design: a container run'sworking_pathis a distro path the host cannot spawn into, so the child re-resolves everything by run id.Compatibility / Migration
--detachis purely additive on all three verbs; without it every verb behaves exactly as before.continuesis an additive field on an ack that only exists under--detach --json, a combination that shipped nowhere before this PR. The extracted validators throw the same error strings the inline checks did.Human Verification (required)
Verified against a compiled Windows binary, not
bun run cli— dev mode is precisely where the Bun single-file-executable argv bug never appears, so dev-mode evidence cannot cover it.Binary:
bun build --compile --minify --target=bun-windows-x64withBUNDLED_IS_BINARY = true; self-reportsArchon CLI v0.6.0 / Platform: win32-x64 / Build: binary / Git commit: 6af8eb2a. Driven against an isolatedARCHON_HOME(throwaway SQLite DB) and a throwaway two-bash-nodes-around-one-approval-gate workflow, so the runs are real and cost no AI tokens.Verified scenarios:
approve <id> --detach --json→ ack{ok:true, detached:true, continues:true}. Child log contains noUnknown command: /$bunfs/root/…and noUnknown command: B:/~BUN/root/…. Child log shows[after] Completed (118ms)→past the gate→Workflow completed successfully.;workflow getreports"status": "completed". The run genuinely advanced — the ack alone would not have proven this, since a pre-fix binary acks success too.reject <id> --detach --json→ ackcontinues: true; noUnknown command; child logRejected and cancelled: smoke-detach-gate;workflow getreports"status": "cancelled".resume <id> --detach --json→ ackcontinues: true; noUnknown command; child re-invoked, logged[before] Skipped (prior_success)and re-paused at the gate as expected.--json(run stays paused, gate resolved), then ranapprove <id> --detach --jsonagain:{"ok": false, "error": "Workflow run … was already approved and is awaiting resume."}, and that run's child-log file stayed byte-identical (1965 → 1965), proving nothing was spawned. Before this PR the parent acked{ok:true}here and the child died unseen.approve <completed-run-id> --detach --json→{"ok": false, "error": "Cannot approve run with status 'completed'. Only paused runs can be approved."}; log-file count unchanged (3 → 3) and that run's log byte-identical (1718 → 1718). Nothing spawned.Edge cases checked:
rejectdeliberately tolerates a malformed/absent approval context whereapproverefuses (covered by unit test — it must still spawn); thechild_workflowredirect is refused synchronously for both verbs (unit tests);cwd: undefinedstill falls back toprocess.cwd()so the pre-existing detach test'sexpect(spawnOptions?.cwd).toBe(process.cwd())assertion passes untouched.What was not verified: the
child_workflow-blocked-parent redirect was not reproduced against the compiled binary (it needs aworkflow:sub-run tree and is covered by unit tests at both layers, including two pre-existing tests that pass unchanged). Linux/macOS binaries were not built — the argv fix being relied on (fix(cli): drop Bun SFE virtual argv[1] from detached re-invoke (#2248) #2273) is platform-independent, but onlywin32-x64was exercised end-to-end here.bun run validatewas not run to completion on this host (see Validation Evidence).Side Effects / Blast Radius (required)
assertApprovable/assertRejectablenow sit on theapproveWorkflow/rejectWorkflowpath used by every surface — CLI, chat command handler, HTTP API, and themanage_runnative tool. That is the honest blast radius. It is mitigated by the extraction being behavior-preserving: error strings are verbatim copies, and the pre-existingchild_workflowrefusal tests for both operations pass unchanged.--detachprecheck is now strictly stricter than before. A caller who previously got{ok:true}for a run with a missing approval context, achild_workflowgate, or an already-resolved gate will now get{ok:false}synchronously. That is the intended fix, but it is a visible behavior change for anyone who was (unknowingly) relying on the false success.continuesfield gives automation a machine-readable signal instead of inferred behavior.Rollback Plan (required)
--detachdisappears fromapprove/reject/resume;workflow run --detachis untouched; the operations revert to their inline gates with identical messages. No data migration, no config, nothing persisted by this change.--detachis itself the opt-in. Every verb without the flag behaves exactly as before.{ok:true, detached:true}whileworkflow getshows the run unchanged minutes later; or adetached-run-<id>.logcontainingUnknown command:— both indicate the child failed to re-invoke.Risks and Mitigations
child_workflowrefusal tests and the full 49-test core operations suite pass unchanged; eight new unit tests pin each gate's message individually.workflow-operationssilently un-mocks them in any test thatmock.modules that path, because Bun'smock.module()merges rather than replaces — the documented cause of test(core): 'should abandon a running run' intermittently times out on windows-latest (3 hits in one day, fully mocked test) #2240.manage-run-tool.test.ts), it mocks only the four operations, andmanage-run-tool.tsnever calls the validators directly. Suite verified passing at 30/30.--detach --jsoncontinues the run while bare--jsondoes not — a genuine asymmetry that could surprise a caller.--detachwould spawn a child that only records a decision, which is what bare--jsonalready does), documented in both the CLI reference andCLAUDE.md, and made machine-readable viacontinues: true. A unit test asserts the child argv carries neither--detachnor--json.Summary by CodeRabbit
New Features
--detachsupport for workflowresume,approve, andrejectcommands.Documentation