From 6960c654eea5decfcd7cff468be92a8bc104b0bb Mon Sep 17 00:00:00 2001 From: jepegit Date: Sun, 19 Apr 2026 23:28:11 +0200 Subject: [PATCH] Include issue comments during /issue-init (#45) - Fetch comments alongside the issue body via `gh issue view --json title,body,url,number,comments` and triage them into a new optional "Comments (curated summary)" section in issue_original.md (three buckets: Additional tasks, Clarifications / constraints, Superseded / retracted). The issue body itself stays byte-for-byte. - New `issueflow-issue-comments` skill describes the triage rules (chronological precedence, noise filtering, maintainer-authority tie-breaker, output contract, edge cases) and is delegated to from both the /issue-init command and the issueflow-issue-init skill. - Register the new skill in TEMPLATE_MANIFEST; bump the manifest-count test and add focused tests that check the command fetches comments, the init skill delegates, and the new skill documents the triage rules. - Append an [Unreleased] entry to HISTORY.md. Made-with: Cursor --- .../03-solved-issues/issue45_original.md | 12 +++ .issueflows/03-solved-issues/issue45_plan.md | 89 +++++++++++++++++ .../03-solved-issues/issue45_status.md | 30 ++++++ HISTORY.md | 2 + .../templates/commands/issue-init.md.j2 | 37 +++++-- .../issueflow_issue_comments/SKILL.md.j2 | 96 +++++++++++++++++++ .../skills/issueflow_issue_init/SKILL.md.j2 | 30 ++++-- src/issue_flow/templating.py | 4 + tests/test_templating.py | 57 ++++++++++- 9 files changed, 341 insertions(+), 16 deletions(-) create mode 100644 .issueflows/03-solved-issues/issue45_original.md create mode 100644 .issueflows/03-solved-issues/issue45_plan.md create mode 100644 .issueflows/03-solved-issues/issue45_status.md create mode 100644 src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2 diff --git a/.issueflows/03-solved-issues/issue45_original.md b/.issueflows/03-solved-issues/issue45_original.md new file mode 100644 index 0000000..6c81ebc --- /dev/null +++ b/.issueflows/03-solved-issues/issue45_original.md @@ -0,0 +1,12 @@ +# Issue #45: include issue comments + +Source: https://github.com/jepegit/issue-flow/issues/45 + +## Original issue text + +It seems like issue-flow (during init) does not take into account additional comments to the issue. This is often not the wanted behaviour. + +Task + +1. improve "/issue-init" so that it also goes through the comments and include tasks from them (depending on the context, some comments might be downvoted or negated later on in the comment section). The comment section (added inside the _original.md file) does not have to be a 1-to-1 representation of the actual comments. +2. add another skill - describing how to review the comments and extract relevant tasks from them. diff --git a/.issueflows/03-solved-issues/issue45_plan.md b/.issueflows/03-solved-issues/issue45_plan.md new file mode 100644 index 0000000..4cbc9db --- /dev/null +++ b/.issueflows/03-solved-issues/issue45_plan.md @@ -0,0 +1,89 @@ +# Plan for issue #45: include issue comments + +## Goal + +Make `/issue-init` comment-aware: fetch GitHub issue comments along with the body, and append a curated summary section to `issue_original.md` that distills follow-up tasks, clarifications, and superseded points. Ship a companion skill (`issueflow-issue-comments`) that the init command and future work can lean on when interpreting comment threads. + +## Constraints + +- Preserve the existing `## Original issue text` contract: the body is kept byte-for-byte as GitHub returns it. Comments go in a new, separate section so diffs of the original body stay clean. +- Both deliverables must render cleanly through `issue_flow.templating.render_template` (defaults: `{{ issueflows_dir }}`, `{{ agent_dir }}`, etc.). +- `TEMPLATE_MANIFEST` in [src/issue_flow/templating.py](src/issue_flow/templating.py) must list the new skill, and `tests/test_templating.py` expectations must stay green. +- Keep changes cohesive with the existing tone/structure of [commands/issue-init.md.j2](src/issue_flow/templates/commands/issue-init.md.j2) and [skills/issueflow_issue_init/SKILL.md.j2](src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2). +- No design/guide doc needed under `.issueflows/04-designs-and-guides/` for this change (behavior is fully captured in the command + skill templates). + +## Approach + +1. **Fetch shape.** Switch the `gh` call in the `/issue-init` spec from `--json title,body,url,number` to `--json title,body,url,number,comments`. That returns each comment with `author.login`, `body`, and `createdAt`, which is enough for curation. + +2. **File layout inside `issue_original.md`.** Add one new optional section after the original body. The body section is unchanged (still byte-for-byte). If the issue has no comments, omit the new section entirely. Template: + + ```markdown + # Issue #: + + Source: <url> + + ## Original issue text + + <body exactly as in GitHub issue> + + ## Comments (curated summary) + + - **Additional tasks**: <bullets distilled from comments that add real work> + - **Clarifications / constraints**: <bullets the agent should honour> + - **Superseded / retracted**: <earlier points later contradicted or walked back> + + _Note: this section is an interpretive summary, not a verbatim comment dump. Source comments: <count>, last comment by @<login> on <date>._ + ``` + + - The curated summary is produced by the agent at init time using the new skill. + - No verbatim paste of comments (per the issue: "does not have to be a 1-to-1 representation"). + +3. **Command edits** — [src/issue_flow/templates/commands/issue-init.md.j2](src/issue_flow/templates/commands/issue-init.md.j2): + - Step 2: fetch `title, body, url, number, comments`. + - New step 2a "Triage comments": call out the new skill `issueflow-issue-comments` as the playbook; list what counts as an additional task, a clarification, or a superseded point; explicitly allow collapsing/dropping noise. + - Step 5: extend the file-content format with the optional `## Comments (curated summary)` section, and state the "omit if no comments" rule. + - Constraints section: clarify that the body remains byte-for-byte; only the new section is interpretive. + - Output section: include "N comments triaged" in the summary to the user. + +4. **Init skill edits** — [src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2](src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2): + - Mirror the fetch change and add a short "Triage comments" step right before the write step. + - Point to the new `issueflow-issue-comments` skill for the triage rules. + - Update the "Write" section to show the optional curated-comments block. + +5. **New skill** — create `src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2` with the standard frontmatter (`disable-model-invocation: true`, name `issueflow-issue-comments`) and sections: + - **When to use** — invoked by `/issue-init` (and reusable by any workflow that needs to re-triage comments later). + - **Inputs** — the JSON array of comments from `gh issue view --json comments` (author, body, createdAt). + - **Triage rules** — chronological precedence (later wins conflicts); explicit negations move earlier items into Superseded; collapse duplicates; ignore chit-chat, LGTMs, bot messages; three buckets (additional tasks / clarifications / superseded); paraphrase, quote sparingly. + - **Output contract** — the exact markdown block shown in step 2. + - **Edge cases** — zero comments (skip section), only bot comments (skip section), heated/multi-author threads (note the disagreement rather than guessing a winner). + +6. **Manifest + tests** — [src/issue_flow/templating.py](src/issue_flow/templating.py): + - Add `("skills/issueflow_issue_comments/SKILL.md.j2", "{agent_dir}/skills/issueflow-issue-comments/SKILL.md")` to `TEMPLATE_MANIFEST`. + - [tests/test_templating.py](tests/test_templating.py): + - Bump `test_manifest_entry_count` from 20 to 21 and fix the inline comment. + - Add `issueflow_issue_comments` to the list in `test_manifest_has_expected_commands_and_skills`. + - Add `test_issue_init_fetches_and_triages_comments` asserting the rendered `issue-init` command mentions comments fetching, the curated-summary section header, and the new skill name. + - Add `test_issue_comments_skill_documents_triage_rules` asserting the new skill renders, mentions chronological precedence and the three buckets. + +## Files to touch + +- [src/issue_flow/templates/commands/issue-init.md.j2](src/issue_flow/templates/commands/issue-init.md.j2) — fetch comments, add triage step, extend file-content format, update constraints + output. +- [src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2](src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2) — mirror the command changes; point at the new skill. +- `src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2` (new) — full triage skill. +- [src/issue_flow/templating.py](src/issue_flow/templating.py) — register the new skill in `TEMPLATE_MANIFEST`. +- [tests/test_templating.py](tests/test_templating.py) — bump count, extend lists, add two focused tests. + +## Test strategy + +- `uv run pytest` (full suite). +- New assertions above. +- Manual smoke: render both templates via `render_template` and eyeball the output. + +## Open questions + +Resolved pre-implementation: + +1. Skill name: `issueflow-issue-comments` (accepted). +2. No raw-comment appendix — keep it lean with only the curated summary. +3. No explicit edits to `/issue-yolo` or `/iflow`; they inherit the new behavior via `/issue-init`. diff --git a/.issueflows/03-solved-issues/issue45_status.md b/.issueflows/03-solved-issues/issue45_status.md new file mode 100644 index 0000000..287e599 --- /dev/null +++ b/.issueflows/03-solved-issues/issue45_status.md @@ -0,0 +1,30 @@ +# Status for issue #45: include issue comments + +- [x] Done + +## What was done + +- `/issue-init` now fetches GitHub issue comments alongside body (`gh issue view --json title,body,url,number,comments`) and triages them into a curated section written to `issue<N>_original.md`. +- Added a new skill `issueflow-issue-comments` describing how to triage the comment thread into three buckets (Additional tasks, Clarifications / constraints, Superseded / retracted) with chronological precedence, noise filtering, and edge-case handling. +- Updated `issueflow-issue-init` skill to mirror the new fetch + triage step and to delegate to the new skill. +- Registered the new skill in `TEMPLATE_MANIFEST` so `issue-flow update` emits it into `{agent_dir}/skills/issueflow-issue-comments/SKILL.md`. + +## Files changed + +- [src/issue_flow/templates/commands/issue-init.md.j2](../../src/issue_flow/templates/commands/issue-init.md.j2) — fetch comments, add triage step (2a), extend file format with optional `## Comments (curated summary)` section, update output + constraints. +- [src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2](../../src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2) — mirror the command changes; delegate to the new skill. +- [src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2](../../src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2) — new skill with triage rules, three buckets, output contract, and edge cases. +- [src/issue_flow/templating.py](../../src/issue_flow/templating.py) — added the new skill entry to `TEMPLATE_MANIFEST`. +- [tests/test_templating.py](../../tests/test_templating.py) — bumped manifest count to 21, added `issueflow_issue_comments` to the expected-skills list, and added three focused tests (`test_issue_init_fetches_and_triages_comments`, `test_issue_init_skill_delegates_to_comments_skill`, `test_issue_comments_skill_documents_triage_rules`). + +## Tests + +- `uv run pytest -q` → 71 passed. +- No linter errors on changed files. + +## Remaining work + +None. Both tasks in the original issue are covered: + +1. `/issue-init` goes through the comments and includes tasks from them (non 1-to-1 curated summary, honors chronological precedence so later comments can supersede earlier ones). +2. A new skill (`issueflow-issue-comments`) describes how to review the comments and extract relevant tasks. diff --git a/HISTORY.md b/HISTORY.md index 9be6b14..152472c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,6 +9,8 @@ than the GitHub release notes they link to. ## [Unreleased] +- `/issue-init` now fetches GitHub issue comments and writes a curated "Comments (curated summary)" section into `issue<N>_original.md` (later comments win over earlier ones). New `issueflow-issue-comments` skill documents the triage rules (three buckets, noise filtering, edge cases). (#45) + ## [0.2.3] - 2026-04-19 - **Dependency awareness at install time (#18).** A new `Prerequisites` section in the README documents the external CLI tools the scaffolded workflow shells out to (`git`, `gh` — with install hints per OS and a `gh auth login` reminder), and `issue-flow init` / `issue-flow update` now run a `shutil.which`-based dependency check up front. If anything is missing, the CLI prints the install hints and asks for confirmation before continuing. The prompt is auto-skipped on non-TTY stdin (CI) and can be bypassed explicitly with `--skip-dep-check`. diff --git a/src/issue_flow/templates/commands/issue-init.md.j2 b/src/issue_flow/templates/commands/issue-init.md.j2 index d002a83..b64a7e5 100644 --- a/src/issue_flow/templates/commands/issue-init.md.j2 +++ b/src/issue_flow/templates/commands/issue-init.md.j2 @@ -30,12 +30,22 @@ The text after this slash command is the **issue reference**. It may also be **e - support both SSH and HTTPS remote URL formats - if parsing fails, ask the user for either full issue URL or `owner/repo` -2. Fetch issue data using GitHub CLI (explicit repo if needed): - - title - - body - - url - - number - - and confirm resolved `owner/repo` +2. Fetch issue data using GitHub CLI (explicit repo if needed). Include comments so they can be triaged into the original file: + - `gh issue view <N> --repo owner/repo --json title,body,url,number,comments` + - `comments` returns an array where each entry has at least `author.login`, `body`, and `createdAt`. + - Confirm resolved `owner/repo` to the user. + +2a. **Triage comments** (only if the `comments` array is non-empty). + - Follow the `issueflow-issue-comments` skill (`{{ agent_dir }}/skills/issueflow-issue-comments/SKILL.md`) for the rules; summary: + - Process comments in chronological order. **Later comments win conflicts** with earlier ones. + - Sort each useful point into one of three buckets: + - **Additional tasks** — new work that isn't already in the issue body. + - **Clarifications / constraints** — guidance on *how* to do the existing work (scope, non-goals, style preferences, must-keep behaviors). + - **Superseded / retracted** — earlier tasks or preferences that later comments walked back or contradicted. + - Collapse duplicates; drop chit-chat, "LGTM" / emoji-only / bot messages. + - Paraphrase; quote sparingly. The section is an **interpretive summary**, not a verbatim dump. + - If all comments are noise (bot-only, pure chit-chat), skip the section entirely rather than writing an empty one. + - If multiple authors openly disagree and no one "wins", record the disagreement under *Clarifications* rather than guessing a winner. 2.5. **Branch status preflight** (report only; do not block and do not delete anything). - Run `git fetch --prune` so tracking info is fresh. @@ -55,7 +65,7 @@ The text after this slash command is the **issue reference**. It may also be **e 4. Create this file: - `{{ issueflows_dir }}/{{ current_issues_folder }}/issue<number>_original.md` -5. File content format: +5. File content format. The `## Comments (curated summary)` section is **optional** — include it only when the triage step (2a) produced at least one bullet; omit it entirely otherwise: ```markdown # Issue #<number>: <title> @@ -64,7 +74,17 @@ The text after this slash command is the **issue reference**. It may also be **e ## Original issue text <body exactly as in GitHub issue> + + ## Comments (curated summary) + + - **Additional tasks**: <bullets distilled from comments that add real work> + - **Clarifications / constraints**: <bullets the agent should honour> + - **Superseded / retracted**: <earlier points later contradicted or walked back> + + _Note: this section is an interpretive summary of the comment thread, not a verbatim dump. Source comments: <count>, last comment by @<login> on <date>._ ``` + - Drop any of the three bullet groups that have no content (do not keep empty `- **...**:` lines). + - Keep the `_Note: ..._` footer whenever the section is present so readers can tell where the summary came from. 6. If `gh` is not authenticated or issue fetch fails: - stop and report the exact error - suggest `gh auth login` @@ -78,11 +98,12 @@ Report: - repository used (`owner/repo`) - if the issue number was inferred from the current branch after the user confirmed in step **1 A**, state the branch name and that `#NN` was inferred from it - file path created +- how many comments were fetched and how many survived triage (e.g. "12 comments fetched, 4 surfaced as tasks/clarifications, 2 marked superseded"); say so explicitly when the curated section was omitted (no comments or all noise) - archive moves performed (source -> destination, grouped by issue number) - whether the operation succeeded ## Constraints -- Preserve the issue body exactly as returned by GitHub. +- Preserve the issue **body** exactly as returned by GitHub (the `## Original issue text` section is byte-for-byte). Only the `## Comments (curated summary)` section is interpretive. - Use UTF-8 markdown. - Allowed file modifications for this command: - create/update the target `issue<number>_original.md` diff --git a/src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2 b/src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2 new file mode 100644 index 0000000..19f6fe8 --- /dev/null +++ b/src/issue_flow/templates/skills/issueflow_issue_comments/SKILL.md.j2 @@ -0,0 +1,96 @@ +--- +name: issueflow-issue-comments +description: >- + Triage a GitHub issue's comment thread into a curated, bucketed summary + (additional tasks, clarifications, superseded) for inclusion in + issue<N>_original.md. Invoked by /issue-init; also reusable when re-triaging + comments later in an issue's lifecycle. +disable-model-invocation: true +--- + +# issue-flow — issue comments triage + +Follow this skill when you need to turn a GitHub issue's comment thread into a short, decision-useful summary that lives next to the original issue body under `{{ issueflows_dir }}/{{ current_issues_folder }}/issue<N>_original.md`. + +It is the playbook that `/issue-init` (and the `issueflow-issue-init` skill) delegate to for anything beyond fetching raw comments. + +## When to use + +- `/issue-init` just fetched an issue with a non-empty `comments` array and needs to write the `## Comments (curated summary)` section. +- You are re-running triage on an already-captured issue because new comments have arrived (the issue body must stay byte-for-byte; only the curated section is rewritten). +- Any workflow that needs to understand "what does the comment thread actually ask us to do?" without pasting the raw thread into a file. + +## Inputs + +A JSON array of comments as returned by: + +``` +gh issue view <N> --repo owner/repo --json comments -q .comments +``` + +Each element has at least: + +- `author.login` — commenter handle +- `body` — markdown text +- `createdAt` — ISO timestamp + +If you only have raw comment text, ask for the structured form (author + date matter for tie-breaking and for the footer). + +## Triage rules + +1. **Chronological precedence.** Walk the comments oldest → newest. If a later comment contradicts or walks back an earlier point, the earlier point moves to **Superseded / retracted** and the later one takes its place in the appropriate bucket. + +2. **Three buckets, pick exactly one per surviving point.** + - **Additional tasks** — new, concrete work that is not already in the issue body. Phrase as imperatives ("also update X", "add Y to Z"). If the point is vague ("maybe do something about caching"), either sharpen it into a task or drop it. + - **Clarifications / constraints** — guidance on *how* to do the existing work: scope boundaries, non-goals, must-keep behaviors, stylistic or architectural preferences, acceptance criteria. Useful phrase: "when doing X, make sure Y". + - **Superseded / retracted** — earlier tasks, preferences, or decisions that a later comment explicitly or implicitly walked back. Keep these visible (don't silently delete them) so the agent doesn't redo retracted work. + +3. **Drop the noise.** Do not include: + - Bot comments (CI, coverage bots, auto-assign bots, etc.). + - Pure chit-chat, "LGTM", "+1", emoji-only reactions. + - Status pings ("any update?") without new content. + - Comments that only quote earlier ones without adding anything. + +4. **Collapse duplicates.** If two commenters make the same point, record it once. + +5. **Paraphrase; quote sparingly.** Short direct quotes are fine when exact wording matters (e.g. a feature name, an error message). Otherwise rewrite in your own words so the summary is scannable. + +6. **Handle open disagreement honestly.** If two authors openly disagree and no later comment resolves it, record the disagreement under *Clarifications* (for example: "author A prefers option X, author B prefers option Y — no resolution in thread"). Do not guess a winner. + +7. **Respect maintainer authority when obvious.** If the repo owner or a maintainer explicitly overrides an earlier suggestion, treat that as the winning position and move the overridden suggestion to *Superseded*. + +## Output contract + +Write exactly this block into `issue<N>_original.md`, immediately after the `## Original issue text` section: + +```markdown +## Comments (curated summary) + +- **Additional tasks**: <bullets distilled from comments that add real work> +- **Clarifications / constraints**: <bullets the agent should honour> +- **Superseded / retracted**: <earlier points later contradicted or walked back> + +_Note: this section is an interpretive summary of the comment thread, not a verbatim dump. Source comments: <count>, last comment by @<login> on <date>._ +``` + +Formatting rules: + +- Each bucket's bullet is itself a list if there is more than one item — nest concrete bullets under the bold label. +- **Drop any bucket that is empty** — do not leave `- **Additional tasks**: ` with no content. +- **Always keep the `_Note: ..._` footer** when the section exists. Use the total `comments` length for `<count>` and the `author.login` + date of the most recent non-dropped comment for `@<login>` / `<date>`. +- Use UTF-8 markdown. No leading/trailing blank lines inside the section beyond what's shown. + +## Edge cases + +- **Zero comments** — skip the whole section. Do not write an empty `## Comments (curated summary)` header. +- **All comments are noise** (bot-only, pure chit-chat, emoji) — skip the whole section. Note this in the command's final report ("N comments fetched, all filtered as noise — section omitted"). +- **Every surviving point lands in a single bucket** — that's fine; just emit that one bucket. +- **Multi-author thread with heated disagreement** — log the disagreement under *Clarifications*, do not invent a resolution. +- **Comments reference external PRs, gists, or linked issues** — keep the reference (shortened URL or `owner/repo#N`) in the bullet, but do not fetch the linked content; it's out of scope for this skill. +- **Comments include code blocks the agent will need later** — summarize the intent in the bullet and mention that the full snippet is in the linked comment; do not paste large blocks into the summary. + +## Constraints + +- This skill only writes into the `## Comments (curated summary)` section of `issue<N>_original.md`. It never touches the issue body, the status file, or the plan file. +- It never calls `gh` itself — it expects the caller (`/issue-init` or similar) to provide the comments JSON. +- It never talks to the network beyond what the caller has already fetched. diff --git a/src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2 b/src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2 index b792f6c..aa420e3 100644 --- a/src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2 +++ b/src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2 @@ -1,9 +1,11 @@ --- name: issueflow-issue-init description: >- - Run the /issue-init workflow: resolve GitHub issue reference, fetch with gh, - write issue<number>_original.md under {{ issueflows_dir }}/{{ current_issues_folder }}/, - and archive other current issues by done status. + Run the /issue-init workflow: resolve GitHub issue reference, fetch body + and comments with gh, triage the comments via the issueflow-issue-comments + skill, write issue<number>_original.md under + {{ issueflows_dir }}/{{ current_issues_folder }}/, and archive other + current issues by done status. disable-model-invocation: true --- @@ -26,7 +28,15 @@ Follow this skill when the user wants to **capture a GitHub issue locally** usin - **Empty / whitespace** — Run `git branch --show-current`. If empty or `main`/`master` (case-insensitive), **stop** and ask for a number, URL, or `owner/repo/#n`. If the branch matches `^\d+-.+`, ask once whether to use that leading issue number; do not proceed without a clear yes/no. - **Archived-issue guard** — Before writing, check `{{ issueflows_dir }}/{{ partly_solved_folder }}/` and `{{ issueflows_dir }}/{{ solved_folder }}/` for existing `issue<n>_*` files. If the issue is already archived, warn and require a second explicit confirmation before re-opening it in `{{ issueflows_dir }}/{{ current_issues_folder }}/`. -3. **Fetch** — `gh issue view <n> --repo owner/repo --json title,body,url,number`. On failure, report the error and suggest `gh auth login`. +3. **Fetch** — `gh issue view <n> --repo owner/repo --json title,body,url,number,comments`. The `comments` field returns an array of `{author.login, body, createdAt, ...}` that step 3a consumes. On failure, report the error and suggest `gh auth login`. + +3a. **Triage comments** (skip if `comments` is empty). Follow the [`issueflow-issue-comments`](../issueflow-issue-comments/SKILL.md) skill. Summary of rules: + - Process comments chronologically; **later comments win conflicts** with earlier ones. + - Sort points into three buckets: **Additional tasks**, **Clarifications / constraints**, **Superseded / retracted**. + - Collapse duplicates; drop chit-chat, emoji-only, "LGTM" and bot messages. + - Paraphrase — this section is an interpretive summary, not a verbatim dump. + - If all comments are noise, skip the curated section entirely. + - On open disagreement with no clear winner, log it under *Clarifications* rather than picking a side. 3.5 **Branch status preflight** (report only) — Run `git fetch --prune`. Report current branch, clean/dirty working tree, and ahead/behind counts vs `origin/<default>` (detect default via `gh repo view --json defaultBranchRef -q .defaultBranchRef.name`, else `git symbolic-ref --quiet --short refs/remotes/origin/HEAD`, else `main`). If the current branch matches `^(\d+)-.+` and files for that issue already live in `{{ issueflows_dir }}/{{ partly_solved_folder }}/` or `{{ issueflows_dir }}/{{ solved_folder }}/`, note that the branch looks stale. Never delete or move anything at this step. @@ -42,13 +52,21 @@ Follow this skill when the user wants to **capture a GitHub issue locally** usin ## Original issue text <body exactly as returned by GitHub> + + ## Comments (curated summary) + + - **Additional tasks**: <bullets distilled from comments that add real work> + - **Clarifications / constraints**: <bullets the agent should honour> + - **Superseded / retracted**: <earlier points later contradicted or walked back> + + _Note: this section is an interpretive summary of the comment thread, not a verbatim dump. Source comments: <count>, last comment by @<login> on <date>._ ``` - Preserve the body **byte-for-byte** (including trailing newlines). + Preserve the body **byte-for-byte** (including trailing newlines). The `## Comments (curated summary)` section is **optional** — include it only when step 3a produced at least one bullet, and drop any of the three bullet groups that have no content. 6. **Conflicts** — If `issue<number>_original.md` already exists, do not overwrite silently; ask the user. -7. **Report** — Summarize number, `owner/repo`, branch inference (if used), path written, archive moves (source → destination), and success or failure. +7. **Report** — Summarize number, `owner/repo`, branch inference (if used), path written, comment triage counts (fetched vs surfaced vs superseded, or "section omitted" when skipped), archive moves (source → destination), and success or failure. ## Constraints diff --git a/src/issue_flow/templating.py b/src/issue_flow/templating.py index d9b4407..1b5ef70 100644 --- a/src/issue_flow/templating.py +++ b/src/issue_flow/templating.py @@ -88,6 +88,10 @@ def render_template(template_name: str, context: dict[str, str]) -> str: "skills/issueflow_issue_init/SKILL.md.j2", "{agent_dir}/skills/issueflow-issue-init/SKILL.md", ), + ( + "skills/issueflow_issue_comments/SKILL.md.j2", + "{agent_dir}/skills/issueflow-issue-comments/SKILL.md", + ), ( "skills/issueflow_issue_plan/SKILL.md.j2", "{agent_dir}/skills/issueflow-issue-plan/SKILL.md", diff --git a/tests/test_templating.py b/tests/test_templating.py index b1f2316..4738a76 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -55,8 +55,8 @@ def test_resolve_output_path() -> None: def test_manifest_entry_count() -> None: - # 8 commands + 1 rule + 1 doc + 10 skills = 20 - assert len(TEMPLATE_MANIFEST) == 20 + # 8 commands + 1 rule + 1 doc + 11 skills = 21 + assert len(TEMPLATE_MANIFEST) == 21 def test_manifest_has_expected_commands_and_skills() -> None: @@ -76,6 +76,7 @@ def test_manifest_has_expected_commands_and_skills() -> None: for skill in ( "issueflow_iflow", "issueflow_issue_init", + "issueflow_issue_comments", "issueflow_issue_plan", "issueflow_issue_start", "issueflow_issue_pause", @@ -258,3 +259,55 @@ def test_issue_yolo_forwards_history_tokens() -> None: rendered = render_template("commands/issue-yolo.md.j2", _default_context()) assert "nohistory" in rendered assert "log " in rendered # `log "..."` bullet-summary override + + +def test_issue_init_fetches_and_triages_comments() -> None: + """/issue-init must fetch comments and call the comments-triage skill.""" + rendered = render_template("commands/issue-init.md.j2", _default_context()) + # gh fetch now asks for the comments field too. + assert "title,body,url,number,comments" in rendered + # The curated section header appears in the file-content template. + assert "## Comments (curated summary)" in rendered + # The triage step exists and delegates to the new skill. + assert "Triage comments" in rendered + assert "issueflow-issue-comments" in rendered + # The three triage buckets are named. + assert "Additional tasks" in rendered + assert "Clarifications" in rendered + assert "Superseded" in rendered + # The body contract is still byte-for-byte. + assert "byte-for-byte" in rendered + + +def test_issue_init_skill_delegates_to_comments_skill() -> None: + """The issue-init skill must fetch comments and point at the comments skill.""" + rendered = render_template( + "skills/issueflow_issue_init/SKILL.md.j2", _default_context() + ) + assert "title,body,url,number,comments" in rendered + assert "issueflow-issue-comments" in rendered + assert "## Comments (curated summary)" in rendered + + +def test_issue_comments_skill_documents_triage_rules() -> None: + """The new issueflow-issue-comments skill must describe triage rules and buckets.""" + rendered = render_template( + "skills/issueflow_issue_comments/SKILL.md.j2", _default_context() + ) + # Frontmatter identity. + assert "name: issueflow-issue-comments" in rendered + assert "disable-model-invocation: true" in rendered + # Chronological precedence (later wins) is called out. + lowered = rendered.lower() + assert "chronological" in lowered + assert "later" in lowered + # All three buckets are named. + assert "Additional tasks" in rendered + assert "Clarifications" in rendered + assert "Superseded" in rendered + # The output contract header matches exactly what /issue-init expects. + assert "## Comments (curated summary)" in rendered + # Noise-filtering guidance exists. + assert "bot" in lowered + # Zero-comment edge case is handled. + assert "zero comments" in lowered or "skip the whole section" in lowered