Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions cmd/serve/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,19 +359,27 @@ func registerStaticTools(server *mcp.Server, f *cmdutil.Factory) {
// workflow_delete -- DELETE /api/workflows/{id}
server.AddTool(&mcp.Tool{
Name: "workflow_delete",
Description: "Delete a workflow by ID",
Description: "Delete a workflow by ID. Use force=true to delete workflows that have execution history.",
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"workflow_id": map[string]any{
"type": "string",
"description": "The workflow ID to delete",
},
"force": map[string]any{
"type": "boolean",
"description": "Force delete even if the workflow has execution history. This will permanently delete all runs and logs.",
},
},
"required": []string{"workflow_id"},
},
}, makeStaticHandler(f, http.MethodDelete, func(args map[string]any, baseURL string) string {
return baseURL + "/api/workflows/" + getStringArg(args, "workflow_id")
u := baseURL + "/api/workflows/" + getStringArg(args, "workflow_id")
if force, ok := args["force"]; ok && force == true {
u += "?force=true"
}
return u
}, nil))

// workflow_execute -- POST /api/workflow/{id}/execute
Expand Down
28 changes: 19 additions & 9 deletions cmd/workflow/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@ func NewDeleteCmd(f *cmdutil.Factory) *cobra.Command {
kh wf delete abc123

# Delete without prompting
kh wf delete abc123 --yes`,
kh wf delete abc123 --yes

# Force delete a workflow that has execution history
kh wf delete abc123 --force`,
RunE: func(cmd *cobra.Command, args []string) error {
workflowID := args[0]

yes, err := cmd.Flags().GetBool("yes")
if err != nil {
yes = false
}
force, _ := cmd.Flags().GetBool("force")
yes, _ := cmd.Flags().GetBool("yes")

if !yes && f.IOStreams.IsTerminal() {
fmt.Fprintf(f.IOStreams.Out, "Delete workflow %s? This cannot be undone. (y/N) ", workflowID)
prompt := fmt.Sprintf("Delete workflow %s? This cannot be undone. (y/N) ", workflowID)
if force {
prompt = fmt.Sprintf("Force delete workflow %s and all its execution history? This cannot be undone. (y/N) ", workflowID)
}
fmt.Fprint(f.IOStreams.Out, prompt)
scanner := bufio.NewScanner(f.IOStreams.In)
if scanner.Scan() {
answer := strings.TrimSpace(strings.ToLower(scanner.Text()))
Expand All @@ -55,22 +60,26 @@ func NewDeleteCmd(f *cmdutil.Factory) *cobra.Command {
host := cmdutil.ResolveHost(cmd, cfg)

url := khhttp.BuildBaseURL(host) + "/api/workflows/" + workflowID
if force {
url += "?force=true"
}
req, err := client.NewRequest(http.MethodDelete, url, nil)
if err != nil {
return err
}

resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("cannot delete workflow %s: it may have existing runs that prevent deletion", workflowID)
return fmt.Errorf("cannot delete workflow %s: %w", workflowID, err)
}
defer resp.Body.Close()

if resp.StatusCode == http.StatusNotFound {
return cmdutil.NotFoundError{Err: fmt.Errorf("workflow %q not found", workflowID)}
}
if resp.StatusCode == http.StatusInternalServerError {
return fmt.Errorf("cannot delete workflow %s: workflow has existing runs that prevent deletion", workflowID)
if resp.StatusCode == http.StatusConflict && !force {
fmt.Fprintf(f.IOStreams.ErrOut, "Workflow has execution history. Use --force to delete the workflow and all its runs.\n")
return fmt.Errorf("workflow %s has existing runs that prevent deletion", workflowID)
}
if resp.StatusCode != http.StatusOK {
return khhttp.NewAPIError(resp)
Expand All @@ -90,6 +99,7 @@ func NewDeleteCmd(f *cmdutil.Factory) *cobra.Command {
}

cmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
cmd.Flags().Bool("force", false, "Force delete even if workflow has execution history")

return cmd
}
1 change: 1 addition & 0 deletions docs/kh_workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Manage workflows
### SEE ALSO

* [kh](kh.md) - KeeperHub CLI
* [kh workflow delete](kh_workflow_delete.md) - Delete a workflow
* [kh workflow get](kh_workflow_get.md) - Get a workflow
* [kh workflow go-live](kh_workflow_go-live.md) - Publish a workflow
* [kh workflow list](kh_workflow_list.md) - List workflows
Expand Down
41 changes: 41 additions & 0 deletions docs/kh_workflow_delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## kh workflow delete

Delete a workflow

```
kh workflow delete <workflow-id> [flags]
```

### Examples

```
# Delete a workflow (will prompt for confirmation)
kh wf delete abc123

# Delete without prompting
kh wf delete abc123 --yes

# Force delete a workflow that has execution history
kh wf delete abc123 --force
```

### Options

```
--force Force delete even if workflow has execution history
-h, --help help for delete
-y, --yes Skip confirmation prompt
```

### Options inherited from parent commands

```
-H, --host string KeeperHub host (default: app.keeperhub.com)
--jq string Filter JSON output with a jq expression
--json Output as JSON
--no-color Disable color output
```

### SEE ALSO

* [kh workflow](kh_workflow.md) - Manage workflows
Loading