diff --git a/CHANGELOG.md b/CHANGELOG.md index c0652953..1e3e58f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,20 @@ All notable changes to this project will be documented in this file. --- +## [0.26.17] - 2026-02-03 + +### Fixed (0.26.17) + +- **Daily standup exports: comment annotations** (fixes [#179](https://github.com/nold-ai/specfact-cli/issues/179)) + - **`--comments` / `--annotations`**: Include item descriptions and comment annotations in `--copilot-export` and + `--summarize`/`--summarize-to` outputs when the adapter supports `get_comments` (GitHub). + - **Docs**: Updated daily standup tutorial and guides to document the new flags and outputs. + +### Changed (0.26.17) + +- **Version**: Bumped to 0.26.17 for issue [#179](https://github.com/nold-ai/specfact-cli/issues/179) + +--- ## [0.26.16] - 2026-02-02 ### Added (0.26.16) diff --git a/docs/getting-started/tutorial-daily-standup-sprint-review.md b/docs/getting-started/tutorial-daily-standup-sprint-review.md index edd6e502..d5da5853 100644 --- a/docs/getting-started/tutorial-daily-standup-sprint-review.md +++ b/docs/getting-started/tutorial-daily-standup-sprint-review.md @@ -20,8 +20,12 @@ This tutorial walks you through a complete **daily standup and sprint review** w - Use **`.specfact/backlog.yaml`** or environment variables when you're not in the repo (e.g. CI) or to override - **Post a standup comment** to the first (or selected) item with `--yesterday`, `--today`, `--blockers` and `--post` - Use **`--interactive`** for step-by-step story review (arrow-key selection, full detail, **existing comments on each issue** when the adapter supports them) -- Use **`--copilot-export `** to write a Markdown summary for Copilot slash-command during standup -- Use **`--summarize`** or **`--summarize-to `** to output a **prompt** (instruction + filter context + standup data) for a slash command (e.g. `specfact.daily`) or copy-paste to Copilot to **generate a standup summary** +- Use **`--copilot-export `** to write a Markdown summary for Copilot slash-command during standup; + add **`--comments`** (alias **`--annotations`**) to include descriptions and comment annotations when + the adapter supports fetching comments +- Use **`--summarize`** or **`--summarize-to `** to output a **prompt** (instruction + filter context + + standup data) for a slash command (e.g. `specfact.daily`) or copy-paste to Copilot to **generate a + standup summary**; add **`--comments`**/**`--annotations`** to include comment annotations in the prompt - Use the **`specfact.backlog-daily`** (or `specfact.daily`) slash prompt for interactive walkthrough with the DevOps team story-by-story (focus, issues, open questions, discussion notes as comments) - Filter by **`--assignee`**, **`--sprint`** / **`--iteration`**, **`--blockers-first`**, and optional **`--suggest-next`** @@ -121,10 +125,13 @@ Use **`--suggest-next`** to show a suggested next item by value score (business To feed a **summary file** into your AI IDE (e.g. for a Copilot slash-command during standup): ```bash -specfact backlog daily github --copilot-export ./standup-summary.md +specfact backlog daily github --copilot-export ./standup-summary.md --comments ``` -The file contains one section per item (ID, title, status, assignees, last updated, progress, blockers). You can open it in your IDE and use it with Copilot. Same scope as the standup table (state, assignee, limit, etc.). +The file contains one section per item (ID, title, status, assignees, last updated, progress, blockers). +With `--comments`/`--annotations`, it also includes the item description and comment annotations when the +adapter supports fetching comments. You can open it in your IDE and use it with Copilot. Same scope as +the standup table (state, assignee, limit, etc.). --- @@ -134,13 +141,17 @@ To get a **prompt** you can paste into Copilot or feed to a slash command (e.g. ```bash # Print prompt to stdout (copy-paste to Copilot) -specfact backlog daily github --summarize +specfact backlog daily github --summarize --comments # Write prompt to a file (e.g. for slash command) -specfact backlog daily github --summarize-to ./standup-prompt.md +specfact backlog daily github --summarize-to ./standup-prompt.md --comments ``` -The output includes an instruction to generate a standup summary, the applied filter context (adapter, state, sprint, assignee, limit), and the same per-item data as `--copilot-export`. Use it with the **`specfact.backlog-daily`** slash prompt for interactive team walkthrough (story-by-story, current focus, issues/open questions, discussion notes as comments). +The output includes an instruction to generate a standup summary, the applied filter context (adapter, +state, sprint, assignee, limit), and the same per-item data as `--copilot-export`. With +`--comments`/`--annotations`, the prompt includes comment annotations when supported. Use it with the +**`specfact.backlog-daily`** slash prompt for interactive team walkthrough (story-by-story, current focus, +issues/open questions, discussion notes as comments). --- @@ -187,8 +198,8 @@ The output includes an instruction to generate a standup summary, the applied fi | Override or use outside repo | Use `.specfact/backlog.yaml`, env vars (`SPECFACT_GITHUB_REPO_OWNER`, etc.), or CLI `--repo-owner`/`--repo-name` or `--ado-org`/`--ado-project`. | | Post standup to first item | Use `--yesterday "..."` `--today "..."` `--blockers "..."` and `--post` (values required). | | Step through stories with full detail (including issue comments) | Use `--interactive`; optionally `--suggest-next`. | -| Feed standup into Copilot | Use `--copilot-export `. | -| Generate standup summary via AI (slash command or Copilot) | Use `--summarize` (stdout) or `--summarize-to `; use with `specfact.backlog-daily` slash prompt. | +| Feed standup into Copilot | Use `--copilot-export `; add `--comments`/`--annotations` for comment annotations. | +| Generate standup summary via AI (slash command or Copilot) | Use `--summarize` (stdout) or `--summarize-to `; add `--comments`/`--annotations` for comment annotations; use with `specfact.backlog-daily` slash prompt. | --- diff --git a/docs/guides/agile-scrum-workflows.md b/docs/guides/agile-scrum-workflows.md index 0a6f2139..e70940d4 100644 --- a/docs/guides/agile-scrum-workflows.md +++ b/docs/guides/agile-scrum-workflows.md @@ -14,7 +14,29 @@ SpecFact CLI supports real-world agile/scrum practices through: - **Definition of Ready (DoR)**: Automatic validation of story readiness for sprint planning - **Backlog Refinement** 🆕: AI-assisted template-driven refinement for standardizing work items from DevOps backlogs -- **Daily Standup**: Use `specfact backlog daily ` to list my/filtered items with status and last activity. Default scope (state=open, limit=20, optional assignee=me) is applied when not overridden; configure via `SPECFACT_STANDUP_STATE`, `SPECFACT_STANDUP_LIMIT`, `SPECFACT_STANDUP_ASSIGNEE` or `.specfact/standup.yaml`. Use `--iteration` / `--sprint` (e.g. `--sprint current`) to focus on current iteration when the adapter supports it; sprint/iteration end date is shown when provided by adapter or config (`standup.sprint_end_date`). A second table **Pending / open for commitment** lists unassigned items (same scope); use `--show-unassigned`/`--no-show-unassigned` or `--unassigned-only`. Use `--blockers-first` to sort items with blockers first; enable `show_priority` or `show_value` in standup config for optional priority/value column (value-driven/SAFe). Optional standup summary (yesterday/today/blockers) from item body; optionally post standup comment to linked issue via `--post` when the adapter supports comments (e.g. GitHub). **Interactive step-by-step review**: Use `--interactive` to select stories with arrow keys (questionary) and view full detail (refine-like: description, acceptance criteria, standup fields, comments when adapter supports); navigate with Next/Previous/Back to list/Exit. Use `--suggest-next` to show suggested next item by value score (business_value / (story_points × priority)). **Copilot export**: Use `--copilot-export ` to write a summarized Markdown file of each story for use with Copilot slash-command during standup (complementary aid, not replacement for backlog). **Kanban**: omit iteration/sprint and use state + limit; unassigned = pullable work. **Scrum/SAFe**: use `--sprint current` and optional priority/value. **Out of scope**: Sprint goal is in your board/sprint settings (not displayed by CLI). Stale/at-risk flags (e.g. "no update in N days") are not in scope—use last updated + blockers. Structured "blocked by" (link to another issue) is not in scope; only free-text blockers are supported. +- **Daily Standup**: Use `specfact backlog daily ` to list my/filtered items with status and last activity. + Default scope (state=open, limit=20, optional assignee=me) is applied when not overridden; configure via + `SPECFACT_STANDUP_STATE`, `SPECFACT_STANDUP_LIMIT`, `SPECFACT_STANDUP_ASSIGNEE` or + `.specfact/standup.yaml`. Use `--iteration` / `--sprint` (e.g. `--sprint current`) to focus on current + iteration when the adapter supports it; sprint/iteration end date is shown when provided by adapter or + config (`standup.sprint_end_date`). A second table **Pending / open for commitment** lists unassigned + items (same scope); use `--show-unassigned`/`--no-show-unassigned` or `--unassigned-only`. Use + `--blockers-first` to sort items with blockers first; enable `show_priority` or `show_value` in standup + config for optional priority/value column (value-driven/SAFe). Optional standup summary + (yesterday/today/blockers) from item body; optionally post standup comment to linked issue via `--post` + when the adapter supports comments (e.g. GitHub). + **Interactive step-by-step review**: Use `--interactive` to select stories with arrow keys (questionary) + and view full detail (refine-like: description, acceptance criteria, standup fields, comments when adapter + supports); navigate with Next/Previous/Back to list/Exit. Use `--suggest-next` to show suggested next + item by value score (business_value / (story_points × priority)). + **Copilot export**: Use `--copilot-export ` to write a summarized Markdown file of each story for + Copilot. Add `--comments` (alias `--annotations`) to include descriptions and comment annotations in + `--copilot-export` and `--summarize` outputs when the adapter supports `get_comments` (GitHub). + **Kanban**: omit iteration/sprint and use state + limit; unassigned = pullable work. **Scrum/SAFe**: use + `--sprint current` and optional priority/value. **Out of scope**: Sprint goal is in your board/sprint + settings (not displayed by CLI). Stale/at-risk flags (e.g. "no update in N days") are not in scope—use + last updated + blockers. Structured "blocked by" (link to another issue) is not in scope; only free-text + blockers are supported. - **Dependency Management**: Track story-to-story and feature-to-feature dependencies - **Prioritization**: Priority levels, ranking, and business value scoring - **Sprint Planning**: Target sprint/release assignment and story point tracking @@ -56,13 +78,19 @@ specfact backlog daily github \ # 4. Optional: interactive step-through, Copilot export, or standup summary prompt specfact backlog daily github --interactive # step-through; detail view shows existing comments on each issue # or -specfact backlog daily github --copilot-export ./standup.md +specfact backlog daily github --copilot-export ./standup.md --comments # or -specfact backlog daily github --summarize # prompt to stdout for AI to generate standup summary +specfact backlog daily github --summarize --comments # prompt to stdout for AI to generate standup summary specfact backlog daily github --summarize-to ./standup-prompt.md ``` -Use the **`specfact.backlog-daily`** (or `specfact.daily`) slash prompt for interactive walkthrough with the DevOps team story-by-story (current focus, issues/open questions, discussion notes as comments). Default scope: **state=open**, **limit=20**; configure via `SPECFACT_STANDUP_*` or `.specfact/standup.yaml`. Use `--assignee me`, `--sprint current`, `--blockers-first`, `--interactive`, `--suggest-next`, `--copilot-export `, `--summarize`, and `--summarize-to ` as needed. See [Tutorial: Daily Standup and Sprint Review](../getting-started/tutorial-daily-standup-sprint-review.md) for the full walkthrough. +Use the **`specfact.backlog-daily`** (or `specfact.daily`) slash prompt for interactive walkthrough with the +DevOps team story-by-story (current focus, issues/open questions, discussion notes as comments). Default +scope: **state=open**, **limit=20**; configure via `SPECFACT_STANDUP_*` or `.specfact/standup.yaml`. Use +`--assignee me`, `--sprint current`, `--blockers-first`, `--interactive`, `--suggest-next`, +`--copilot-export `, `--summarize`, `--summarize-to `, and `--comments`/`--annotations` as +needed. See [Tutorial: Daily Standup and Sprint Review](../getting-started/tutorial-daily-standup-sprint-review.md) +for the full walkthrough. ## Persona-Based Workflows diff --git a/docs/guides/devops-adapter-integration.md b/docs/guides/devops-adapter-integration.md index e29dbfaf..63bf15a3 100644 --- a/docs/guides/devops-adapter-integration.md +++ b/docs/guides/devops-adapter-integration.md @@ -19,7 +19,26 @@ SpecFact CLI supports **bidirectional synchronization** between OpenSpec change - **Issue Creation**: Export OpenSpec change proposals as GitHub Issues (or other DevOps backlog items) - **Progress Tracking**: Automatically detect code changes and add progress comments to issues -- **Standup Comments**: Use `specfact backlog daily --post` with `--yesterday`, `--today`, `--blockers` to post a standup summary as a comment on the linked issue (GitHub/ADO adapters that support comments). Standup config: set defaults via env (`SPECFACT_STANDUP_STATE`, `SPECFACT_STANDUP_LIMIT`, `SPECFACT_STANDUP_ASSIGNEE`, `SPECFACT_STANDUP_SPRINT_END`) or optional `.specfact/standup.yaml` (e.g. `default_state`, `limit`, `sprint`, `show_priority`, `suggest_next`). Iteration/sprint and sprint end date support depend on the adapter (ADO supports current iteration and iteration path; see adapter docs). Use `--blockers-first` and config `show_priority`/`show_value` for time-critical and value-driven standups. **Interactive review** (`--interactive`): step-through stories with arrow-key selection; detail view shows **existing comments annotated to each issue** when the adapter implements `get_comments(item)` (GitHub adapter supports it). **Value score / suggested next**: when BacklogItem has `story_points`, `business_value`, and `priority`, use `--suggest-next` or config `suggest_next` to show suggested next item (business_value / (story_points × priority)). **Standup summary prompt** (`--summarize` or `--summarize-to PATH`): output a prompt (instruction + filter context + standup data) for slash command or Copilot to generate a standup summary. **Slash prompt** `specfact.backlog-daily` (or `specfact.daily`): use with IDE/Copilot for interactive team walkthrough story-by-story (current focus, issues/open questions, discussion notes as comments); prompt file at `resources/prompts/specfact.backlog-daily.md`. **Sprint goal** is stored in your board/sprint settings and is not displayed or edited by the CLI. +- **Standup Comments**: Use `specfact backlog daily --post` with `--yesterday`, `--today`, `--blockers` to post + a standup summary as a comment on the linked issue (GitHub/ADO adapters that support comments). Standup + config: set defaults via env (`SPECFACT_STANDUP_STATE`, `SPECFACT_STANDUP_LIMIT`, + `SPECFACT_STANDUP_ASSIGNEE`, `SPECFACT_STANDUP_SPRINT_END`) or optional `.specfact/standup.yaml` + (e.g. `default_state`, `limit`, `sprint`, `show_priority`, `suggest_next`). Iteration/sprint and sprint + end date support depend on the adapter (ADO supports current iteration and iteration path; see adapter + docs). Use `--blockers-first` and config `show_priority`/`show_value` for time-critical and value-driven + standups. **Interactive review** (`--interactive`): step-through stories with arrow-key selection; detail + view shows **existing comments annotated to each issue** when the adapter implements `get_comments(item)` + (GitHub adapter supports it). **Comment annotations in exports**: add `--comments` (alias + `--annotations`) to include descriptions and comment annotations in `--copilot-export` and + `--summarize`/`--summarize-to` outputs when the adapter supports fetching comments. **Value score / + suggested next**: when BacklogItem has `story_points`, `business_value`, and `priority`, use + `--suggest-next` or config `suggest_next` to show suggested next item (business_value / (story_points × + priority)). **Standup summary prompt** (`--summarize` or `--summarize-to PATH`): output a prompt + (instruction + filter context + standup data) for slash command or Copilot to generate a standup summary. + **Slash prompt** `specfact.backlog-daily` (or `specfact.daily`): use with IDE/Copilot for interactive + team walkthrough story-by-story (current focus, issues/open questions, discussion notes as comments); + prompt file at `resources/prompts/specfact.backlog-daily.md`. **Sprint goal** is stored in your + board/sprint settings and is not displayed or edited by the CLI. - **Content Sanitization**: Protect internal information when syncing to public repositories - **Separate Repository Support**: Handle cases where OpenSpec proposals and source code are in different repositories diff --git a/openspec/config.yaml b/openspec/config.yaml index d827b4a4..db12cae3 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -8,7 +8,8 @@ context: | Testing: pytest, CrossHair (symbolic execution), Hypothesis (property-based) Distribution: uvx, PyPI, Docker - Philosophy: Brownfield-first legacy modernization tool. Reverse-engineer contracts from existing code, then enforce to prevent regressions. Offline-first, no vendor lock-in, no cloud dependencies. + Philosophy: Brownfield-first legacy modernization tool. Reverse-engineer contracts from existing code, + then enforce to prevent regressions. Offline-first, no vendor lock-in, no cloud dependencies. Architecture patterns: - Bridge Adapter: Tool-agnostic adapters (GitHub, GitLab, Linear, Jira, Spec-Kit, OpenSpec) @@ -29,20 +30,32 @@ context: | Logging: Use common.logger_setup.get_logger() (avoid print()) Naming: snake_case (files/modules/functions), PascalCase (classes), UPPER_SNAKE_CASE (constants) - Documentation (critical for every change): User-facing docs are published at https://docs.specfact.io (GitHub Pages). Source: docs/ with Jekyll front-matter (layout, title, permalink, description), docs/index.md as landing, docs/_layouts/default.html for sidebar/menu navigation. README.md is the repo entry point. + Documentation (critical for every change): User-facing docs are published at https://docs.specfact.io + (GitHub Pages). Source: docs/ with Jekyll front-matter (layout, title, permalink, description), + docs/index.md as landing, docs/_layouts/default.html for sidebar/menu navigation. README.md is the repo + entry point. - Every change must include documentation research and review: - - (1) Identifies affected documentation: docs/ (reference, guides, adapters, getting-started), README.md, docs/index.md. - - (2) Updates or adds content so docs remain a great resource for new and existing users (learn, adopt, understand). - - (3) If adding or moving pages: ensure front-matter (layout, title, permalink, description) is correct and update docs/_layouts/default.html sidebar navigation so the new or moved page appears in the menu. + - (1) Identifies affected documentation: docs/ (reference, guides, adapters, getting-started), + README.md, docs/index.md. + - (2) Updates or adds content so docs remain a great resource for new and existing users + (learn, adopt, understand). + - (3) If adding or moving pages: ensure front-matter (layout, title, permalink, description) is + correct and update docs/_layouts/default.html sidebar navigation so the new or moved page appears + in the menu. - Docs are published at https://docs.specfact.io (GitHub Pages). - Contract requirements: ALL public APIs MUST have @icontract (@require/@ensure) and @beartype decorators - Testing: Contract-first (primary), minimum 80% coverage, unit/integration/E2E tests required for all changes + Contract requirements: ALL public APIs MUST have @icontract (@require/@ensure) and @beartype + decorators + Testing: Contract-first (primary), minimum 80% coverage, unit/integration/E2E tests required for all + changes - Development discipline (SDD + TDD): SpecFact CLI adds the validation layer; we develop SpecFact itself using the same discipline to prove it works. Order is strict: + Development discipline (SDD + TDD): SpecFact CLI adds the validation layer; we develop SpecFact itself + using the same discipline to prove it works. Order is strict: - (1) Specs first—spec deltas define behavior (Given/When/Then). - - (2) Tests second—write unit/integration tests from spec scenarios (one or more tests per scenario); run tests and expect failure. - - (3) Code last—implement until tests pass and behavior satisfies the spec. Code must batch (satisfy) both (a) spec scenarios and (b) tests. + - (2) Tests second—write unit/integration tests from spec scenarios (one or more tests per scenario); + run tests and expect failure. + - (3) Code last—implement until tests pass and behavior satisfies the spec. Code must batch (satisfy) + both (a) spec scenarios and (b) tests. - If the pattern does not work in practice, adjust the process until it does. # Per-artifact rules (only injected into matching artifacts) @@ -55,10 +68,18 @@ rules: - Address offline-first constraint (no cloud dependencies) - Include rollback plan for risky changes - Check for conflicts with existing bridge adapters or plugin registry - - "Documentation impact (required for every change): Consider effect on docs published at https://docs.specfact.io. Identify affected areas: docs/ (reference, guides, adapters, getting-started), docs/index.md, README.md, docs/_layouts/default.html (sidebar/navigation). - - If the change is user-facing or alters API/CLI behavior, state in Impact which docs will be updated or added so new and existing users can learn, adopt, and understand the change." - - "For public-facing changes, include Source Tracking section with GitHub issue reference (format: ## Source Tracking with - **GitHub Issue**: #, - **Issue URL**: , - **Repository**: /, - **Last Synced Status**: ). - - After creation, update proposal.md Source Tracking section with issue number, URL, repository, and status." + - |- + Documentation impact (required for every change): Consider effect on docs published at + https://docs.specfact.io. Identify affected areas: docs/ (reference, guides, adapters, + getting-started), docs/index.md, README.md, docs/_layouts/default.html (sidebar/navigation). + - If the change is user-facing or alters API/CLI behavior, state in Impact which docs will be + updated or added so new and existing users can learn, adopt, and understand the change. + - |- + For public-facing changes, include Source Tracking section with GitHub issue reference + (format: ## Source Tracking with - **GitHub Issue**: #, - **Issue URL**: , + - **Repository**: /, - **Last Synced Status**: ). + - After creation, update proposal.md Source Tracking section with issue number, URL, repository, + and status. - Source tracking: Only track public repos (specfact-cli, platform-frontend). Skip for internal repos (specfact-cli-internal) specs: @@ -77,29 +98,42 @@ rules: - Include fallback strategies for offline scenarios tasks: - - Enforce SDD+TDD order: - - (1) Branch creation (first). - - (2) Write/add spec deltas if not already done. - - (3) Write tests from spec scenarios—translate each Given/When/Then scenario into test cases; run tests and expect failure (no implementation yet). - - (4) Implement code until tests pass and behavior satisfies the spec; code must batch (satisfy) both (a) spec scenarios and (b) tests. - - (5) Quality gates (format, lint, type-check). - - (6) Documentation research and review (see below). - - (7) PR creation (last). - - "Documentation research and review (required for every change): Include a task that: - - (1) Identifies affected documentation: docs/ (reference, guides, adapters, getting-started), README.md, docs/index.md. - - (2) Updates or adds content so docs remain a great resource for new and existing users (learn, adopt, understand). - - (3) If adding or moving pages: ensure front-matter (layout, title, permalink, description) is correct and update docs/_layouts/default.html sidebar navigation so the new or moved page appears in the menu. - - Docs are published at https://docs.specfact.io (GitHub Pages)." + - Enforce SDD+TDD order: + - (1) Branch creation (first). + - (2) Write/add spec deltas if not already done. + - (3) Write tests from spec scenarios—translate each Given/When/Then scenario into test cases; + run tests and expect failure (no implementation yet). + - (4) Implement code until tests pass and behavior satisfies the spec; code must batch (satisfy) + both (a) spec scenarios and (b) tests. + - (5) Quality gates (format, lint, type-check). + - (6) Documentation research and review (see below). + - (7) PR creation (last). + - |- + Documentation research and review (required for every change): Include a task that: + - (1) Identifies affected documentation: docs/ (reference, guides, adapters, getting-started), + README.md, docs/index.md. + - (2) Updates or adds content so docs remain a great resource for new and existing users + (learn, adopt, understand). + - (3) If adding or moving pages: ensure front-matter (layout, title, permalink, description) is + correct and update docs/_layouts/default.html sidebar navigation so the new or moved page + appears in the menu. + - Docs are published at https://docs.specfact.io (GitHub Pages). - Break into 2-hour maximum chunks - Include contract decorator tasks (@icontract, @beartype) for all public APIs - - Test tasks MUST come before implementation tasks: write tests derived from specs first, then implement. Do not implement before tests exist for the changed behavior. + - >- + Test tasks MUST come before implementation tasks: write tests derived from specs first, then + implement. Do not implement before tests exist for the changed behavior. - Include quality gate tasks: format, lint, type-check, test coverage - Reference existing test patterns in tests/unit/, tests/integration/, tests/e2e/ - - "Version and changelog (required before PR): Include a task that - - (1) bumps patch version when the change is a fix, or minor/major per semver when adding features or breaking; - - (2) syncs version in pyproject.toml, setup.py, src/__init__.py, src/specfact_cli/__init__.py; - - (3) adds a CHANGELOG.md entry under a new [X.Y.Z] - YYYY-MM-DD section with Fixed/Added/Changed as appropriate. - - Place this task after quality gates and documentation, before PR creation." + - |- + Version and changelog (required before PR): Include a task that + - (1) bumps patch version when the change is a fix, or minor/major per semver when adding + features or breaking; + - (2) syncs version in pyproject.toml, setup.py, src/__init__.py, + src/specfact_cli/__init__.py; + - (3) adds a CHANGELOG.md entry under a new [X.Y.Z] - YYYY-MM-DD section with Fixed/Added/Changed + as appropriate. + - Place this task after quality gates and documentation, before PR creation. - Include git workflow tasks: branch creation (first task), PR creation (last task) - For public-facing changes in public repos (specfact-cli, platform-frontend): - Include GitHub issue creation task with format: diff --git a/pyproject.toml b/pyproject.toml index 168a1cb7..5eec8f8b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "specfact-cli" -version = "0.26.16" +version = "0.26.17" description = "Brownfield-first CLI: Reverse engineer legacy Python → specs → enforced contracts. Automate legacy code documentation and prevent modernization regressions." readme = "README.md" requires-python = ">=3.11" diff --git a/setup.py b/setup.py index 3e64b21e..8d7568ee 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ if __name__ == "__main__": _setup = setup( name="specfact-cli", - version="0.26.16", + version="0.26.17", description="SpecFact CLI - Spec -> Contract -> Sentinel tool for contract-driven development", packages=find_packages(where="src"), package_dir={"": "src"}, diff --git a/src/__init__.py b/src/__init__.py index 2fc0e6a2..13b7517a 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -3,4 +3,4 @@ """ # Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py -__version__ = "0.26.16" +__version__ = "0.26.17" diff --git a/src/specfact_cli/__init__.py b/src/specfact_cli/__init__.py index 4debe5aa..65cecab6 100644 --- a/src/specfact_cli/__init__.py +++ b/src/specfact_cli/__init__.py @@ -9,6 +9,6 @@ - Validating reproducibility """ -__version__ = "0.26.16" +__version__ = "0.26.17" __all__ = ["__version__"] diff --git a/src/specfact_cli/commands/backlog_commands.py b/src/specfact_cli/commands/backlog_commands.py index 0f6462cf..d29d1e5a 100644 --- a/src/specfact_cli/commands/backlog_commands.py +++ b/src/specfact_cli/commands/backlog_commands.py @@ -378,20 +378,66 @@ def _format_daily_item_detail(item: BacklogItem, comments: list[str]) -> str: return "\n".join(parts) +def _collect_comment_annotations( + adapter: str, + items: list[BacklogItem], + *, + repo_owner: str | None, + repo_name: str | None, + github_token: str | None, + ado_org: str | None, + ado_project: str | None, + ado_token: str | None, +) -> dict[str, list[str]]: + """ + Collect comment annotations for backlog items when the adapter supports get_comments(). + + Returns a mapping of item ID -> list of comment strings. Returns empty dict if not supported. + """ + comments_by_item_id: dict[str, list[str]] = {} + try: + adapter_kwargs = _build_adapter_kwargs( + adapter, + repo_owner=repo_owner, + repo_name=repo_name, + github_token=github_token, + ado_org=ado_org, + ado_project=ado_project, + ado_token=ado_token, + ) + registry = AdapterRegistry() + adapter_instance = registry.get_adapter(adapter, **adapter_kwargs) + if not isinstance(adapter_instance, BacklogAdapter): + return comments_by_item_id + get_comments_fn = getattr(adapter_instance, "get_comments", None) + if not callable(get_comments_fn): + return comments_by_item_id + for item in items: + with contextlib.suppress(Exception): + raw = get_comments_fn(item) + comments_by_item_id[item.id] = list(raw) if isinstance(raw, list) else [] + except Exception: + return comments_by_item_id + return comments_by_item_id + + @beartype def _build_copilot_export_content( items: list[BacklogItem], include_value_score: bool = False, + include_comments: bool = False, + comments_by_item_id: dict[str, list[str]] | None = None, ) -> str: """ Build Markdown content for Copilot export: one section per item. Per item: ID, title, status, assignees, last updated, progress summary (standup fields), - blockers, and optionally value score. + blockers, optional value score, and optionally description/comments when enabled. """ lines: list[str] = [] lines.append("# Daily standup – Copilot export") lines.append("") + comments_map = comments_by_item_id or {} for item in items: lines.append(f"## {item.id} - {item.title}") lines.append("") @@ -402,11 +448,26 @@ def _build_copilot_export_content( item.updated_at.strftime("%Y-%m-%d %H:%M") if hasattr(item.updated_at, "strftime") else str(item.updated_at) ) lines.append(f"- **Last updated:** {updated}") + if include_comments: + body = (item.body_markdown or "").strip() + if body: + snippet = body[:_SUMMARIZE_BODY_TRUNCATE] + if len(body) > _SUMMARIZE_BODY_TRUNCATE: + snippet += "\n..." + lines.append("- **Description:**") + for line in snippet.splitlines(): + lines.append(f" {line}" if line else " ") yesterday, today, blockers = _parse_standup_from_body(item.body_markdown or "") if yesterday or today: lines.append(f"- **Progress:** Yesterday: {yesterday or '—'}; Today: {today or '—'}") if blockers: lines.append(f"- **Blockers:** {blockers}") + if include_comments: + item_comments = comments_map.get(item.id, []) + if item_comments: + lines.append("- **Comments (annotations):**") + for c in item_comments: + lines.append(f" - {c}") if item.story_points is not None: lines.append(f"- **Story points:** {item.story_points}") if item.priority is not None: @@ -559,7 +620,7 @@ def _run_interactive_daily( console.print(Panel(detail, title=f"Story: {item.id}", border_style="cyan")) if suggest_next and n > 1: - pending = [i for i in items if not i.assignees or item.story_points is not None] + pending = [i for i in items if not i.assignees or i.story_points is not None] if pending: best: BacklogItem | None = None best_score: float = -1.0 @@ -1030,6 +1091,12 @@ def daily( "--copilot-export", help="Write summarized progress per story to a file for Copilot slash-command use during standup.", ), + include_comments: bool = typer.Option( + False, + "--comments", + "--annotations", + help="Include item comments/annotations in summarize/copilot export (adapter must support get_comments).", + ), summarize: bool = typer.Option( False, "--summarize", @@ -1118,10 +1185,28 @@ def daily( console.print("[yellow]No backlog items found.[/yellow]") return + comments_by_item_id: dict[str, list[str]] = {} + if include_comments and (copilot_export is not None or summarize or summarize_to is not None): + comments_by_item_id = _collect_comment_annotations( + adapter, + filtered, + repo_owner=repo_owner, + repo_name=repo_name, + github_token=github_token, + ado_org=ado_org, + ado_project=ado_project, + ado_token=ado_token, + ) + if copilot_export is not None: include_score = suggest_next or bool(standup_config.get("suggest_next")) export_path = Path(copilot_export) - content = _build_copilot_export_content(filtered, include_value_score=include_score) + content = _build_copilot_export_content( + filtered, + include_value_score=include_score, + include_comments=include_comments, + comments_by_item_id=comments_by_item_id or None, + ) export_path.write_text(content, encoding="utf-8") console.print(f"[dim]Exported {len(filtered)} item(s) to {export_path}[/dim]") @@ -1134,27 +1219,6 @@ def daily( "assignee": effective_assignee or "—", "limit": effective_limit, } - comments_by_item_id: dict[str, list[str]] = {} - try: - adapter_kwargs_sum = _build_adapter_kwargs( - adapter, - repo_owner=repo_owner, - repo_name=repo_name, - github_token=github_token, - ado_org=ado_org, - ado_project=ado_project, - ado_token=ado_token, - ) - registry_sum = AdapterRegistry() - adapter_instance_sum = registry_sum.get_adapter(adapter, **adapter_kwargs_sum) - get_comments_fn = getattr(adapter_instance_sum, "get_comments", None) - if callable(get_comments_fn): - for it in filtered: - with contextlib.suppress(Exception): - raw = get_comments_fn(it) - comments_by_item_id[it.id] = list(raw) if isinstance(raw, list) else [] - except Exception: - pass content = _build_summarize_prompt_content( filtered, filter_context=filter_ctx, diff --git a/tests/unit/commands/test_backlog_daily.py b/tests/unit/commands/test_backlog_daily.py index 923e7d9b..053949b3 100644 --- a/tests/unit/commands/test_backlog_daily.py +++ b/tests/unit/commands/test_backlog_daily.py @@ -20,6 +20,7 @@ from __future__ import annotations +import re from datetime import UTC, datetime from pathlib import Path from unittest.mock import MagicMock @@ -44,6 +45,12 @@ runner = CliRunner() +def _strip_ansi(text: str) -> str: + """Remove ANSI escape codes from CLI output.""" + ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") + return ansi_escape.sub("", text) + + def _item( id_: str = "1", title: str = "Item", @@ -388,6 +395,27 @@ def test_copilot_export_idempotent_format(self) -> None: assert "Title" in content assert "- " in content or "* " in content or "\n" in content + def test_copilot_export_includes_description_and_comments_when_enabled(self) -> None: + """When enabled, Copilot export includes description and comment annotations.""" + items = [ + _item( + "1", + "Story one", + state="open", + body_markdown="This is the issue description and context.", + ), + ] + comments_by_id = {"1": ["Comment from Alice: In progress.", "Comment from Bob: Blocked on API."]} + content = _build_copilot_export_content( + items, + include_value_score=False, + include_comments=True, + comments_by_item_id=comments_by_id, + ) + assert "Description" in content and "issue description" in content + assert "Comments" in content or "annotations" in content + assert "In progress" in content and "Blocked on API" in content + class TestFormatDailyItemDetail: """Scenario: Interactive detail view refine-like (13.1).""" @@ -429,6 +457,13 @@ def test_daily_help_shows_summarize(self) -> None: assert result.exit_code == 0 assert "summarize" in result.output.lower() + def test_daily_help_shows_comment_annotations(self) -> None: + """Backlog daily has --comments/--annotations option for exports.""" + result = runner.invoke(app, ["backlog", "daily", "--help-advanced"]) + assert result.exit_code == 0 + output = _strip_ansi(result.output) + assert "--comments" in output or "--annotations" in output + class TestBuildSummarizePromptContent: """Scenario: --summarize outputs prompt with filter context and per-item data (22.1)."""