diff --git a/.claude/commands/issue-to-spec.md b/.claude/commands/issue-to-spec.md new file mode 100644 index 0000000..121b7a0 --- /dev/null +++ b/.claude/commands/issue-to-spec.md @@ -0,0 +1,101 @@ +--- +description: Fetch a Gitea issue and feed it into /speckit.specify as the feature description. +handoffs: + - label: Start speccing from this issue + agent: speckit.specify + prompt: "Create a spec from this issue" + send: true +--- + +## User Input + +```text +$ARGUMENTS +``` + +You **MUST** provide an issue number as the argument (e.g. `/issue-to-spec 42`). If `$ARGUMENTS` is empty or not a valid number, ask the user for the issue number. + +## Prerequisites + +1. Verify the `GITEA_TOKEN_ISSUES` environment variable is set: + +```bash +test -n "$GITEA_TOKEN_ISSUES" && echo "TOKEN_OK" || echo "TOKEN_MISSING" +``` + +If missing, tell the user to set it: +``` +export GITEA_TOKEN_ISSUES="your-gitea-personal-access-token" +``` +Then abort. + +2. Parse the git remote to extract the Gitea API base URL, owner, and repo: + +```bash +git config --get remote.origin.url +``` + +Expected format: `ssh://git@://.git` or `https:////.git` + +Extract: +- `GITEA_HOST` — the hostname +- `OWNER` — the repo owner/org +- `REPO` — the repo name (strip `.git` suffix) +- `API_BASE` — `https:///api/v1` + +## Execution + +### Step 1 — Fetch the issue + +```bash +curl -sf -H "Authorization: token $GITEA_TOKEN_ISSUES" "$API_BASE/repos/$OWNER/$REPO/issues/" +``` + +Extract from the JSON response: +- `title` — the issue title +- `body` — the issue body (markdown) +- `labels` — array of label names (if any) + +If the API call fails or returns no issue, abort with a clear error. + +### Step 2 — Fetch issue comments (if any) + +```bash +curl -sf -H "Authorization: token $GITEA_TOKEN_ISSUES" "$API_BASE/repos/$OWNER/$REPO/issues//comments" +``` + +If comments exist, append them to the context (they may contain clarifications or additional requirements discussed after the issue was created). + +### Step 3 — Compose the feature description + +Format the issue content into a feature description suitable for `/speckit.specify`: + +``` + + + + + +--- +Additional context from issue comments: +: +: +... +``` + +### Step 4 — Report and hand off + +Display a summary: +- Issue number and title +- Number of comments included +- The composed feature description + +Then hand off to `/speckit.specify` with the composed feature description as input. The handoff button in the UI will allow the user to proceed. + +## Behavior Rules + +- Never modify the issue on Gitea — this is a read-only operation. +- Include comment authors in the context so `/speckit.specify` can attribute requirements. +- If the issue body is empty, warn the user but still proceed with just the title. +- Strip HTML tags from the body/comments if present (Gitea sometimes includes rendered HTML). +- Use `curl` for all API calls — do not rely on `gh` CLI. diff --git a/.claude/commands/sync-issue.md b/.claude/commands/sync-issue.md new file mode 100644 index 0000000..8c8c4d0 --- /dev/null +++ b/.claude/commands/sync-issue.md @@ -0,0 +1,153 @@ +--- +description: Update a Gitea issue with business-level acceptance criteria extracted from the feature spec's user stories. +--- + +## User Input + +```text +$ARGUMENTS +``` + +You **MUST** provide an issue number as the argument (e.g. `/sync-issue 42`). If `$ARGUMENTS` is empty or not a valid number, ask the user for the issue number. + +## Prerequisites + +1. Verify the `GITEA_TOKEN_ISSUES` environment variable is set: + +```bash +test -n "$GITEA_TOKEN_ISSUES" && echo "TOKEN_OK" || echo "TOKEN_MISSING" +``` + +If missing, tell the user to set it: +``` +export GITEA_TOKEN_ISSUES="your-gitea-personal-access-token" +``` +Then abort. + +2. Parse the git remote to extract the Gitea API base URL, owner, and repo: + +```bash +git config --get remote.origin.url +``` + +Expected format: `ssh://git@://.git` or `https:////.git` + +Extract: +- `GITEA_HOST` — the hostname +- `OWNER` — the repo owner/org +- `REPO` — the repo name (strip `.git` suffix) +- `API_BASE` — `https:///api/v1` + +3. Locate the spec file. Run: + +```bash +.specify/scripts/bash/check-prerequisites.sh --json --paths-only +``` + +Parse `FEATURE_SPEC` from the output. If it fails, ask the user to ensure they're on a feature branch with a spec. For single quotes in args, use escape syntax: e.g `'I'\''m Groot'` (or double-quote if possible: `"I'm Groot"`). + +## Execution + +### Step 1 — Read the spec + +Load the spec file at `FEATURE_SPEC`. Parse the **User Scenarios & Testing** section, specifically: + +- Each `### User Story N - [Title]` block +- The **Acceptance Scenarios** numbered list within each story (Given/When/Then format) +- The **Edge Cases** section + +### Step 2 — Condense into business-level acceptance criteria + +For each user story, extract the acceptance scenarios and rewrite them as concise, business-level checkbox items. Group by user story title. + +**Transformation rules:** +- Strip Given/When/Then syntax — write as plain outcomes +- Remove implementation details (API names, database references, component names, file paths, config values, tool names) +- Focus on what the user **can do** or **can see** +- Keep each item to one line +- Preserve the grouping by user story for readability + +**Example transformation:** + +Input (from spec): +``` +**Given** no sources are cached, **When** the user clicks the import button in the top bar, +**Then** the stat block side panel opens showing a descriptive explanation, an editable +pre-filled base URL, and a "Load All" button. +``` + +Output (for issue): +``` +- [ ] Clicking the import button opens a panel with a description, editable URL, and "Load All" button +``` + +Also include edge cases as a separate group if they describe user-facing behavior. + +### Step 3 — Fetch the existing issue + +```bash +curl -sf -H "Authorization: token $GITEA_TOKEN_ISSUES" "$API_BASE/repos/$OWNER/$REPO/issues/" +``` + +Extract the current `body` from the response. + +### Step 4 — Update the issue body + +Merge the acceptance criteria into the existing issue body: + +- If the body already has an `## Acceptance Criteria` section, **replace** its contents (everything between `## Acceptance Criteria` and the next `##` heading or end of body). +- If the body does not have an `## Acceptance Criteria` section, insert it after the `## Summary` section (or at the end if no Summary exists). + +Preserve all other sections of the issue body unchanged. + +The acceptance criteria section should look like: + +```markdown +## Acceptance Criteria + +### +- [ ] +- [ ] + +### +- [ ] + +### Edge Cases +- [ ] +``` + +### Step 5 — Preview and confirm + +Show the user: +- The full updated issue body +- A diff summary of what changed (sections added/replaced) + +Ask for confirmation before updating. + +### Step 6 — Push the update + +On confirmation: + +```bash +curl -sf -X PATCH \ + -H "Authorization: token $GITEA_TOKEN_ISSUES" \ + -H "Content-Type: application/json" \ + "$API_BASE/repos/$OWNER/$REPO/issues/" \ + -d @- <<'PAYLOAD' +{ + "body": "" +} +PAYLOAD +``` + +Report success with the issue URL. + +## Behavior Rules + +- Never modify the issue title, labels, milestone, or assignees — only the body. +- Always preview before updating — never push without user confirmation. +- If the spec has no user stories or acceptance scenarios, abort with a clear message suggesting the user run `/speckit.specify` first. +- Acceptance criteria must be business-level. If you find yourself writing implementation details, rewrite at a higher level of abstraction. +- Use `curl` for all API calls — do not rely on `gh` CLI. +- Always use HEREDOC for the JSON payload to handle special characters in the body. +- Escape double quotes and newlines properly in the JSON body.