@laitszkin/apollo-toolkit 2.11.2 → 2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -81,6 +81,11 @@ class OpenGitHubIssueTests(unittest.TestCase):
81
81
  proposal="Allow exporting incident timelines",
82
82
  reason="Support postmortem handoff",
83
83
  suggested_architecture="Add shared exporters and UI action",
84
+ impact=None,
85
+ evidence=None,
86
+ suggested_action=None,
87
+ severity=None,
88
+ affected_scope=None,
84
89
  )
85
90
 
86
91
  self.assertIn("### 功能提案", zh_body)
@@ -88,6 +93,28 @@ class OpenGitHubIssueTests(unittest.TestCase):
88
93
  self.assertIn("### Feature Proposal", en_body)
89
94
  self.assertIn("### Suggested Architecture", en_body)
90
95
 
96
+ def test_build_issue_body_supports_security_issue_sections(self) -> None:
97
+ en_body = MODULE.build_issue_body(
98
+ issue_type=MODULE.ISSUE_TYPE_SECURITY,
99
+ language="en",
100
+ title="[Security] Missing auth",
101
+ problem_description="Endpoint misses admin check",
102
+ suspected_cause=None,
103
+ reproduction=None,
104
+ proposal=None,
105
+ reason=None,
106
+ suggested_architecture=None,
107
+ impact="Sensitive export may leak",
108
+ evidence="Reproduced request and code path review",
109
+ suggested_action="Add authz and tests",
110
+ severity="high",
111
+ affected_scope="/admin/export",
112
+ )
113
+
114
+ self.assertIn("### Security Risk", en_body)
115
+ self.assertIn("### Severity", en_body)
116
+ self.assertIn("### Suggested Mitigation", en_body)
117
+
91
118
  def test_validate_issue_content_args_requires_feature_fields(self) -> None:
92
119
  with self.assertRaises(SystemExit):
93
120
  MODULE.validate_issue_content_args(
@@ -118,6 +145,43 @@ class OpenGitHubIssueTests(unittest.TestCase):
118
145
  suggested_architecture="shared module",
119
146
  problem_description=None,
120
147
  suspected_cause=None,
148
+ impact=None,
149
+ evidence=None,
150
+ suggested_action=None,
151
+ severity=None,
152
+ affected_scope=None,
153
+ )
154
+ )
155
+
156
+ def test_validate_issue_content_args_requires_security_fields(self) -> None:
157
+ with self.assertRaises(SystemExit):
158
+ MODULE.validate_issue_content_args(
159
+ Namespace(
160
+ issue_type=MODULE.ISSUE_TYPE_SECURITY,
161
+ problem_description="auth missing",
162
+ affected_scope="",
163
+ impact="sensitive export may leak",
164
+ evidence="reproduced",
165
+ suggested_action="add authz",
166
+ severity="high",
167
+ reason=None,
168
+ suggested_architecture=None,
169
+ suspected_cause=None,
170
+ )
171
+ )
172
+
173
+ MODULE.validate_issue_content_args(
174
+ Namespace(
175
+ issue_type=MODULE.ISSUE_TYPE_SECURITY,
176
+ problem_description="auth missing",
177
+ affected_scope="/admin/export",
178
+ impact="sensitive export may leak",
179
+ evidence="reproduced",
180
+ suggested_action="add authz",
181
+ severity="high",
182
+ reason=None,
183
+ suggested_architecture=None,
184
+ suspected_cause=None,
121
185
  )
122
186
  )
123
187
 
@@ -130,6 +194,11 @@ class OpenGitHubIssueTests(unittest.TestCase):
130
194
  suggested_architecture=None,
131
195
  problem_description="Repeated timeout warnings escalated into request failures.",
132
196
  suspected_cause="handler.py:12",
197
+ impact=None,
198
+ evidence=None,
199
+ suggested_action=None,
200
+ severity=None,
201
+ affected_scope=None,
133
202
  )
134
203
  )
135
204
 
@@ -153,6 +222,11 @@ class OpenGitHubIssueTests(unittest.TestCase):
153
222
  "- Difference/Impact: users still receive errors.\n"
154
223
  ),
155
224
  suspected_cause="handler.py:12",
225
+ impact=None,
226
+ evidence=None,
227
+ suggested_action=None,
228
+ severity=None,
229
+ affected_scope=None,
156
230
  )
157
231
  )
158
232
 
@@ -181,6 +255,11 @@ class OpenGitHubIssueTests(unittest.TestCase):
181
255
  suggested_architecture=None,
182
256
  repo="owner/repo",
183
257
  dry_run=True,
258
+ impact=None,
259
+ evidence=None,
260
+ suggested_action=None,
261
+ severity=None,
262
+ affected_scope=None,
184
263
  )
185
264
 
186
265
  with patch.object(MODULE, "parse_args", return_value=args), patch.object(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laitszkin/apollo-toolkit",
3
- "version": "2.11.2",
3
+ "version": "2.11.3",
4
4
  "description": "Apollo Toolkit npm installer for managed skill copying across Codex, OpenClaw, and Trae.",
5
5
  "license": "MIT",
6
6
  "author": "LaiTszKin",
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: read-github-issue
3
+ description: Read and search remote GitHub issues via GitHub CLI (`gh`). Use when users ask to list issues, filter issue candidates, inspect a specific issue with comments, or gather issue context before planning follow-up work.
4
+ ---
5
+
6
+ # Read GitHub Issue
7
+
8
+ ## Dependencies
9
+
10
+ - Required: none.
11
+ - Conditional: none.
12
+ - Optional: none.
13
+ - Fallback: If `gh` is unavailable or unauthenticated, stop and report the exact blocked command instead of guessing repository state.
14
+
15
+ ## Standards
16
+
17
+ - Evidence: Verify repository context first, then read remote issue data directly from `gh issue list` / `gh issue view` instead of paraphrasing from memory.
18
+ - Execution: Confirm the target repo, find candidate issues with the bundled script, then inspect the chosen issue with comments and structured fields.
19
+ - Quality: Keep the skill focused on issue discovery and retrieval only; do not embed any hardcoded fixing, branching, PR, or push workflow.
20
+ - Output: Return candidate issues, selected issue details, comments summary, and any missing information needed before follow-up work.
21
+
22
+ ## Overview
23
+
24
+ Use this skill to gather trustworthy GitHub issue context with `gh`: discover open or closed issues, narrow them with labels or search text, then inspect a chosen issue in detail before any separate planning or implementation workflow begins.
25
+
26
+ ## Prerequisites
27
+
28
+ - `gh` is installed and authenticated (`gh auth status`).
29
+ - The current directory is a git repository with the correct `origin`, or the user provides `--repo owner/name`.
30
+
31
+ ## Workflow
32
+
33
+ ### 1) Verify repository and remote context
34
+
35
+ - Run `gh repo view --json nameWithOwner,isPrivate,defaultBranchRef` to confirm target repo.
36
+ - If the user specifies another repository, always use `--repo <owner>/<repo>` in issue commands.
37
+
38
+ ### 2) Find candidate issues with the bundled script
39
+
40
+ - Preferred command:
41
+
42
+ ```bash
43
+ python3 scripts/find_issues.py --limit 50 --state open
44
+ ```
45
+
46
+ - Optional filters:
47
+ - `--repo owner/name`
48
+ - `--label bug`
49
+ - `--search "panic in parser"`
50
+ - If the issue target is still unclear, present top candidates and ask which issue number or URL should be inspected next.
51
+
52
+ ### 3) Read a specific issue in detail
53
+
54
+ - Preferred command:
55
+
56
+ ```bash
57
+ python3 scripts/read_issue.py 123 --comments
58
+ ```
59
+
60
+ - Optional flags:
61
+ - `--repo owner/name`
62
+ - `--json`
63
+ - `--comments`
64
+ - Use the returned title, body, labels, assignees, state, timestamps, and comments to summarize the issue precisely.
65
+
66
+ ### 4) Summarize gaps before any follow-up action
67
+
68
+ - Identify missing acceptance criteria, repro details, affected components, or environment context.
69
+ - If issue text and comments are insufficient, state exactly what is missing instead of inventing a fix plan.
70
+
71
+ ## Included Script
72
+
73
+ ### `scripts/find_issues.py`
74
+
75
+ - Purpose: consistent remote issue listing via `gh issue list`.
76
+ - Outputs a readable table by default, or JSON with `--output json`.
77
+ - Uses only GitHub CLI so it reflects remote GitHub state.
78
+
79
+ ### `scripts/read_issue.py`
80
+
81
+ - Purpose: deterministic issue detail retrieval via `gh issue view`.
82
+ - Outputs either a human-readable summary or full JSON for downstream automation.
83
+ - Can include issue comments so the agent can read the latest discussion before taking any other step.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Read GitHub Issue"
3
+ short_description: "Read and search remote GitHub issues"
4
+ default_prompt: "Use $read-github-issue to verify the target GitHub repository with gh, find candidate issues with the bundled issue-search script, inspect the selected issue with comments and structured fields, summarize the trustworthy issue context, and call out any missing details before any separate planning or implementation work."
@@ -17,7 +17,7 @@ def positive_int(raw: str) -> int:
17
17
 
18
18
  def parse_args() -> argparse.Namespace:
19
19
  parser = argparse.ArgumentParser(
20
- description="List remote GitHub issues with gh CLI and display table or JSON output."
20
+ description="Find remote GitHub issues with gh CLI and display table or JSON output."
21
21
  )
22
22
  parser.add_argument("--repo", help="Target repository in owner/name format.")
23
23
  parser.add_argument("--state", default="open", choices=["open", "closed", "all"])
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import subprocess
7
+ import sys
8
+
9
+
10
+ ISSUE_FIELDS = "number,title,body,state,author,labels,assignees,comments,createdAt,updatedAt,closedAt,url"
11
+
12
+
13
+ def parse_args() -> argparse.Namespace:
14
+ parser = argparse.ArgumentParser(
15
+ description="Read a remote GitHub issue with gh CLI and display summary or JSON output."
16
+ )
17
+ parser.add_argument("issue", help="Issue number or URL.")
18
+ parser.add_argument("--repo", help="Target repository in owner/name format.")
19
+ parser.add_argument(
20
+ "--comments",
21
+ action="store_true",
22
+ help="Keep issue comments in formatted output.",
23
+ )
24
+ parser.add_argument(
25
+ "--json",
26
+ action="store_true",
27
+ help="Print raw JSON output.",
28
+ )
29
+ return parser.parse_args()
30
+
31
+
32
+ def build_command(args: argparse.Namespace) -> list[str]:
33
+ cmd = [
34
+ "gh",
35
+ "issue",
36
+ "view",
37
+ args.issue,
38
+ "--json",
39
+ ISSUE_FIELDS,
40
+ ]
41
+ if args.repo:
42
+ cmd.extend(["--repo", args.repo])
43
+ return cmd
44
+
45
+
46
+ def join_names(items: list[dict], key: str) -> str:
47
+ values = [item.get(key, "") for item in items if item.get(key)]
48
+ return ", ".join(values) if values else "-"
49
+
50
+
51
+ def print_summary(issue: dict, include_comments: bool) -> None:
52
+ print(f"Number: #{issue.get('number', '')}")
53
+ print(f"Title: {issue.get('title', '')}")
54
+ print(f"State: {issue.get('state', '')}")
55
+ print(f"URL: {issue.get('url', '')}")
56
+ print(f"Author: {(issue.get('author') or {}).get('login', '-')}")
57
+ print(f"Labels: {join_names(issue.get('labels', []), 'name')}")
58
+ print(f"Assignees: {join_names(issue.get('assignees', []), 'login')}")
59
+ print(f"Created: {issue.get('createdAt', '')}")
60
+ print(f"Updated: {issue.get('updatedAt', '')}")
61
+ print(f"Closed: {issue.get('closedAt', '') or '-'}")
62
+ print("")
63
+ print("Body:")
64
+ print(issue.get("body", "") or "-")
65
+
66
+ if include_comments:
67
+ comments = issue.get("comments", [])
68
+ print("")
69
+ print(f"Comments ({len(comments)}):")
70
+ if not comments:
71
+ print("-")
72
+ return
73
+ for comment in comments:
74
+ author = (comment.get("author") or {}).get("login", "-")
75
+ created = comment.get("createdAt", "")
76
+ body = comment.get("body", "") or "-"
77
+ print(f"- [{created}] {author}: {body}")
78
+
79
+
80
+ def main() -> int:
81
+ args = parse_args()
82
+ cmd = build_command(args)
83
+
84
+ try:
85
+ result = subprocess.run(cmd, check=True, capture_output=True, text=True)
86
+ except FileNotFoundError:
87
+ print("Error: gh CLI is not installed or not in PATH.", file=sys.stderr)
88
+ return 1
89
+ except subprocess.CalledProcessError as exc:
90
+ print(exc.stderr.strip() or "gh issue view failed.", file=sys.stderr)
91
+ return exc.returncode
92
+
93
+ try:
94
+ issue = json.loads(result.stdout)
95
+ except json.JSONDecodeError:
96
+ print("Error: unable to parse gh output as JSON.", file=sys.stderr)
97
+ return 1
98
+
99
+ if args.json:
100
+ print(json.dumps(issue, indent=2))
101
+ return 0
102
+
103
+ print_summary(issue, include_comments=args.comments)
104
+ return 0
105
+
106
+
107
+ if __name__ == "__main__":
108
+ sys.exit(main())
@@ -12,13 +12,13 @@ from pathlib import Path
12
12
  from unittest.mock import patch
13
13
 
14
14
 
15
- SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "list_issues.py"
16
- SPEC = importlib.util.spec_from_file_location("list_issues", SCRIPT_PATH)
15
+ SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "find_issues.py"
16
+ SPEC = importlib.util.spec_from_file_location("find_issues", SCRIPT_PATH)
17
17
  MODULE = importlib.util.module_from_spec(SPEC)
18
18
  SPEC.loader.exec_module(MODULE)
19
19
 
20
20
 
21
- class ListIssuesTests(unittest.TestCase):
21
+ class FindIssuesTests(unittest.TestCase):
22
22
  def test_build_command_with_filters(self) -> None:
23
23
  args = Namespace(
24
24
  repo="owner/repo",
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+ import io
7
+ import json
8
+ import unittest
9
+ from argparse import Namespace
10
+ from pathlib import Path
11
+ from unittest.mock import patch
12
+
13
+
14
+ SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "read_issue.py"
15
+ SPEC = importlib.util.spec_from_file_location("read_issue", SCRIPT_PATH)
16
+ MODULE = importlib.util.module_from_spec(SPEC)
17
+ SPEC.loader.exec_module(MODULE)
18
+
19
+
20
+ class ReadIssueTests(unittest.TestCase):
21
+ def test_build_command_with_repo(self) -> None:
22
+ args = Namespace(issue="123", repo="owner/repo", comments=False, json=False)
23
+
24
+ self.assertEqual(
25
+ MODULE.build_command(args),
26
+ [
27
+ "gh",
28
+ "issue",
29
+ "view",
30
+ "123",
31
+ "--json",
32
+ MODULE.ISSUE_FIELDS,
33
+ "--repo",
34
+ "owner/repo",
35
+ ],
36
+ )
37
+
38
+ def test_main_returns_error_when_gh_missing(self) -> None:
39
+ args = Namespace(issue="123", repo=None, comments=False, json=False)
40
+
41
+ with patch.object(MODULE, "parse_args", return_value=args), patch(
42
+ "subprocess.run", side_effect=FileNotFoundError
43
+ ), patch("sys.stderr", new_callable=io.StringIO) as stderr:
44
+ code = MODULE.main()
45
+
46
+ self.assertEqual(code, 1)
47
+ self.assertIn("not in PATH", stderr.getvalue())
48
+
49
+ def test_main_json_output(self) -> None:
50
+ args = Namespace(issue="123", repo=None, comments=False, json=True)
51
+ payload = {
52
+ "number": 123,
53
+ "title": "Need better retries",
54
+ "body": "detail",
55
+ "state": "OPEN",
56
+ "author": {"login": "octocat"},
57
+ "labels": [],
58
+ "assignees": [],
59
+ "comments": [],
60
+ "createdAt": "2026-03-24T00:00:00Z",
61
+ "updatedAt": "2026-03-24T01:00:00Z",
62
+ "closedAt": None,
63
+ "url": "https://github.com/owner/repo/issues/123",
64
+ }
65
+
66
+ class Result:
67
+ stdout = json.dumps(payload)
68
+
69
+ with patch.object(MODULE, "parse_args", return_value=args), patch(
70
+ "subprocess.run", return_value=Result()
71
+ ), patch("sys.stdout", new_callable=io.StringIO) as stdout:
72
+ code = MODULE.main()
73
+
74
+ self.assertEqual(code, 0)
75
+ self.assertEqual(json.loads(stdout.getvalue()), payload)
76
+
77
+ def test_print_summary_includes_comments(self) -> None:
78
+ issue = {
79
+ "number": 123,
80
+ "title": "Need better retries",
81
+ "body": "detail",
82
+ "state": "OPEN",
83
+ "author": {"login": "octocat"},
84
+ "labels": [{"name": "bug"}],
85
+ "assignees": [{"login": "alice"}],
86
+ "comments": [
87
+ {
88
+ "author": {"login": "bob"},
89
+ "createdAt": "2026-03-24T02:00:00Z",
90
+ "body": "extra context",
91
+ }
92
+ ],
93
+ "createdAt": "2026-03-24T00:00:00Z",
94
+ "updatedAt": "2026-03-24T01:00:00Z",
95
+ "closedAt": None,
96
+ "url": "https://github.com/owner/repo/issues/123",
97
+ }
98
+
99
+ with patch("sys.stdout", new_callable=io.StringIO) as stdout:
100
+ MODULE.print_summary(issue, include_comments=True)
101
+
102
+ output = stdout.getvalue()
103
+ self.assertIn("#123", output)
104
+ self.assertIn("bug", output)
105
+ self.assertIn("extra context", output)
106
+
107
+
108
+ if __name__ == "__main__":
109
+ unittest.main()
@@ -1,105 +0,0 @@
1
- ---
2
- name: fix-github-issues
3
- description: Resolve issues from remote GitHub repositories via GitHub CLI (`gh`), implement and validate fixes locally, then either open a pull request through `open-source-pr-workflow` (or `open-pr-workflow` in environments that use that alias) or hand off to `commit-and-push` when the user explicitly wants a direct push. Use when users ask to list remote issues, pick one or more issues to fix, and deliver the result through a linked PR or an explicit direct-push workflow.
4
- ---
5
-
6
- # Fix GitHub Issues
7
-
8
- ## Dependencies
9
-
10
- - Required: `systematic-debug` for diagnosis and validated fixes.
11
- - Conditional: `open-source-pr-workflow` (or `open-pr-workflow`) when the user wants a PR; `commit-and-push` when the user explicitly wants a direct commit/push flow.
12
- - Optional: none.
13
- - Fallback: If the required handoff for the user's requested delivery mode is unavailable, stop and report the blocked dependency instead of improvising another release path.
14
-
15
- ## Standards
16
-
17
- - Evidence: Verify repository context, fetch remote issue details, and derive expected behavior from issue text before coding.
18
- - Execution: Select the issue, open an isolated worktree by default, fix it through `systematic-debug`, validate locally, then hand off to the delivery workflow that matches the user's request.
19
- - Quality: Keep scope limited to the selected issue, capture exact validation commands, preserve issue linkage in the final PR or commit message, and treat temporary worktree cleanup as part of completion rather than an optional follow-up.
20
- - Output: Finish with either a linked PR or a direct pushed commit, then clean up the temporary worktree plus any matching local branch before reporting completion.
21
-
22
- ## Overview
23
-
24
- Use this skill to run an end-to-end issue-fixing loop with `gh`: discover open issues, select a target, implement and test the fix, then hand off either to `open-source-pr-workflow` for PR submission or to `commit-and-push` when the user explicitly wants a direct push.
25
-
26
- ## Prerequisites
27
-
28
- - `gh` is installed and authenticated (`gh auth status`).
29
- - The current directory is a git repository with the correct `origin`.
30
- - The repository has test or validation commands that can prove the fix.
31
-
32
- ## Workflow
33
-
34
- ### 1) Verify repository and remote context
35
-
36
- - Run `gh repo view --json nameWithOwner,isPrivate,defaultBranchRef` to confirm target repo.
37
- - If the user specifies another repository, always use `--repo <owner>/<repo>` in issue commands.
38
- - Run `git fetch --all --prune` before implementation.
39
-
40
- ### 2) List remote issues with GitHub CLI
41
-
42
- - Preferred command:
43
-
44
- ```bash
45
- python3 scripts/list_issues.py --limit 50 --state open
46
- ```
47
-
48
- - Optional filters:
49
- - `--repo owner/name`
50
- - `--label bug`
51
- - `--search "panic in parser"`
52
- - If the issue target is still unclear, present top candidates and ask the user which issue number to fix.
53
-
54
- ### 3) Read issue details before coding
55
-
56
- - Run `gh issue view <issue-number> --comments` (plus `--repo` when needed).
57
- - Identify expected behavior, edge cases, and acceptance signals from issue text/comments.
58
- - Do not guess missing requirements; ask the user when critical details are ambiguous.
59
-
60
- ### 4) Open worktree by default after issue selection
61
-
62
- - Immediately create and enter an isolated worktree once the issue number is selected and confirmed.
63
- - Use a compliant branch name (`codex/{change_type}/{changes}`) and keep all edits in that worktree.
64
- - If the user explicitly asks to stay in the current tree, follow that request; otherwise worktree is the default path.
65
-
66
- ### 5) Implement the fix with `systematic-debug`
67
-
68
- - Execute the `systematic-debug` workflow: inspect, reproduce with tests, diagnose, then apply minimal fix.
69
- - Keep scope limited to the selected issue.
70
- - Reuse existing code patterns and avoid unrelated refactors.
71
-
72
- ### 6) Validate the fix
73
-
74
- - Run focused tests/lint/build relevant to the touched area.
75
- - Capture exact commands and outcomes; these will be reused in the PR body.
76
- - Ensure the change can be linked back to the issue number.
77
-
78
- ### 7) Open PR via dependency skill
79
-
80
- - If the user explicitly asks to commit and push directly, invoke `commit-and-push` instead of opening a PR.
81
- - In direct-push mode:
82
- - keep the issue number in the commit message or final summary when appropriate
83
- - state the exact target branch the user requested
84
- - push only after validation is complete
85
- - Otherwise invoke `open-source-pr-workflow` (or `open-pr-workflow` if that alias exists in the environment).
86
- - In PR mode, provide:
87
- - issue number or link
88
- - motivation and engineering decisions
89
- - executed test commands and results
90
- - Include issue-closing reference (for example, `Closes #<issue-number>`) whenever a PR is opened.
91
-
92
- ### 8) Clean up the temporary worktree after PR creation or direct push
93
-
94
- - Once the PR is opened or the direct push is complete and no more work is needed in that isolated tree, remove the worktree you created for the fix.
95
- - Also clean up the matching local branch reference if it is no longer needed locally.
96
- - Verify the cleanup with `git worktree list` and confirm the temporary path no longer appears before finishing.
97
- - If the worktree cannot be removed because of uncommitted changes or a still-checked-out branch, resolve that state immediately instead of leaving cleanup for a later user request.
98
-
99
- ## Included Script
100
-
101
- ### `scripts/list_issues.py`
102
-
103
- - Purpose: consistent remote issue listing via `gh issue list`.
104
- - Outputs a readable table by default, or JSON with `--output json`.
105
- - Uses only GitHub CLI so it reflects remote GitHub state.
@@ -1,4 +0,0 @@
1
- interface:
2
- display_name: "Fix GitHub Issues"
3
- short_description: "Resolve remote GitHub issues, then open a PR or push directly"
4
- default_prompt: "Use $fix-github-issues to verify the target GitHub repository with gh, list and inspect remote issues, create an isolated worktree and compliant branch after issue selection, use $systematic-debug to reproduce and fix the issue with tests, validate the result, then either hand off to $open-source-pr-workflow for a linked PR or to $commit-and-push when the user explicitly wants a direct push, and finally delete the temporary worktree."