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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions openspec/changes/add-feedback-command/proposal.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
## Why

Users and agents need a simple way to submit feedback about OpenSpec directly from the CLI. Currently there's no mechanism to collect user feedback, feature requests, or bug reports in a way that enables follow-up conversation.
Users and agents need a simple way to submit feedback about OpenSpec directly from the CLI. Currently there's no mechanism to collect user feedback, feature requests, or bug reports in a way that enables follow-up conversation. Using GitHub Issues allows us to track feedback, prevent spam via GitHub auth, and enables outreach to users.

## What Changes

- Add `openspec feedback <message>` CLI command
- Add GitHub Device OAuth flow for user authentication
- Create GitHub Issues in the openspec repository for each feedback submission
- Add `/feedback` skill for agent-assisted feedback with context enrichment and anonymization
- Leverage `gh` CLI for GitHub authentication and issue creation
- Add `/feedback` skill for agent-assisted feedback with context enrichment
- Ensure cross-platform compatibility (macOS, Linux, Windows)

## Impact

- Affected specs: New `cli-feedback` capability
- Affected code:
- `src/cli/index.ts` - Register feedback command
- `src/commands/feedback.ts` - Command implementation
- `src/auth/github.ts` - GitHub OAuth device flow
- `src/commands/feedback.ts` - Command implementation using `gh` CLI
- `src/core/templates/skill-templates.ts` - Feedback skill template
- `src/core/completions/command-registry.ts` - Shell completions
- External dependency: Requires `gh` CLI installed and authenticated
159 changes: 80 additions & 79 deletions openspec/changes/add-feedback-command/specs/cli-feedback/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,75 @@

### Requirement: Feedback command

The system SHALL provide an `openspec feedback` command that creates a GitHub Issue in the openspec repository with the user's feedback.
The system SHALL provide an `openspec feedback` command that creates a GitHub Issue in the openspec repository using the `gh` CLI. The system SHALL use `execFileSync` with argument arrays to prevent shell injection vulnerabilities.

#### Scenario: Simple feedback submission

- **WHEN** user executes `openspec feedback "Great tool!"`
- **THEN** the system creates a GitHub Issue with title "Feedback: Great tool!"
- **THEN** the system executes `gh issue create` with title "Feedback: Great tool!"
- **AND** the issue is created in the openspec repository
- **AND** the issue has the `feedback` label
- **AND** the system displays the created issue URL

#### Scenario: Rich feedback with body
#### Scenario: Safe command execution

- **WHEN** submitting feedback via `gh` CLI
- **THEN** the system uses `execFileSync` with separate arguments array
- **AND** user input is NOT passed through a shell
- **AND** shell metacharacters (quotes, backticks, $(), etc.) are treated as literal text

#### Scenario: Feedback with body

- **WHEN** user executes `openspec feedback "Title here" --body "Detailed description..."`
- **THEN** the system creates a GitHub Issue with the specified title
- **AND** the issue body contains the detailed description
- **AND** the issue body includes metadata (OpenSpec version, platform)

#### Scenario: Multiline message

- **WHEN** user provides a multiline message (first line as title, rest as body)
- **THEN** the system uses the first line as the issue title
- **AND** the remaining lines become the issue body

### Requirement: GitHub authentication

The system SHALL authenticate users via GitHub Device OAuth flow before submitting feedback.

#### Scenario: First-time authentication

- **WHEN** user runs `openspec feedback` for the first time
- **AND** no GitHub token is stored
- **THEN** the system initiates GitHub Device OAuth flow
- **AND** displays a URL and code for the user to authorize
- **AND** polls for authorization completion
- **AND** stores the token in global config on success

#### Scenario: Cached authentication

- **WHEN** user runs `openspec feedback`
- **AND** a valid GitHub token is stored
- **THEN** the system uses the cached token without re-authentication

#### Scenario: Token refresh

- **WHEN** the stored GitHub token is expired or invalid
- **THEN** the system initiates a new Device OAuth flow
- **AND** updates the stored token on success
- **AND** the issue body includes metadata (OpenSpec version, platform, timestamp)

#### Scenario: Authentication cancellation
### Requirement: GitHub CLI dependency

- **WHEN** user cancels the OAuth flow (Ctrl+C)
- **THEN** the system exits gracefully without storing any token
- **AND** displays a message indicating feedback was not submitted
The system SHALL use `gh` CLI for automatic feedback submission when available, and provide a manual submission fallback when `gh` is not installed or not authenticated. The system SHALL use platform-appropriate commands to detect `gh` CLI availability.

### Requirement: GitHub token storage
#### Scenario: Missing gh CLI with fallback

The system SHALL securely store GitHub authentication tokens in the global config directory.
- **WHEN** user runs `openspec feedback "message"`
- **AND** `gh` CLI is not installed (not found in PATH)
- **THEN** the system displays warning: "GitHub CLI not found. Manual submission required."
- **AND** outputs structured feedback content with delimiters:
- "--- FORMATTED FEEDBACK ---"
- Title line
- Labels line
- Body content with metadata
- "--- END FEEDBACK ---"
- **AND** displays pre-filled GitHub issue URL for manual submission
- **AND** exits with zero code (successful fallback)

#### Scenario: Token persistence
#### Scenario: Cross-platform gh CLI detection on Unix

- **WHEN** GitHub authentication completes successfully
- **THEN** the system stores the access token in `~/.config/openspec/config.json`
- **AND** the token persists across CLI sessions
- **WHEN** system is running on macOS or Linux (platform is 'darwin' or 'linux')
- **AND** checking if `gh` CLI is installed
- **THEN** the system executes `which gh` command

#### Scenario: Token isolation
#### Scenario: Cross-platform gh CLI detection on Windows

- **WHEN** storing the GitHub token
- **THEN** the token is stored separately from telemetry configuration
- **AND** does not affect or depend on telemetry settings
- **WHEN** system is running on Windows (platform is 'win32')
- **AND** checking if `gh` CLI is installed
- **THEN** the system executes `where gh` command

### Requirement: Feedback always works

The system SHALL allow feedback submission regardless of telemetry settings.
#### Scenario: Unauthenticated gh CLI with fallback

#### Scenario: Feedback with telemetry disabled

- **WHEN** user has disabled telemetry via `OPENSPEC_TELEMETRY=0`
- **AND** user runs `openspec feedback "message"`
- **THEN** the feedback is still submitted to GitHub
- **AND** telemetry events are not sent
- **WHEN** user runs `openspec feedback "message"`
- **AND** `gh` CLI is installed but not authenticated
- **THEN** the system displays warning: "GitHub authentication required. Manual submission required."
- **AND** outputs structured feedback content (same format as missing gh CLI scenario)
- **AND** displays pre-filled GitHub issue URL for manual submission
- **AND** displays authentication instructions: "To auto-submit in the future: gh auth login"
- **AND** exits with zero code (successful fallback)

#### Scenario: Feedback in CI environment
#### Scenario: Authenticated gh CLI

- **WHEN** `CI=true` is set in the environment
- **AND** user runs `openspec feedback "message"`
- **THEN** the feedback submission proceeds normally
- **WHEN** user runs `openspec feedback "message"`
- **AND** `gh auth status` returns success (authenticated)
- **THEN** the system proceeds with feedback submission

### Requirement: Issue metadata

Expand All @@ -99,7 +83,13 @@ The system SHALL include relevant metadata in the GitHub Issue body.
- OpenSpec CLI version
- Platform (darwin, linux, win32)
- Submission timestamp
- Separator line indicating "Submitted via OpenSpec CLI"
- Separator line: "---\nSubmitted via OpenSpec CLI"

#### Scenario: Windows platform metadata

- **WHEN** creating a GitHub Issue for feedback on Windows
- **THEN** the issue body includes "Platform: win32"
- **AND** all platform detection uses Node.js `os.platform()` API

#### Scenario: No sensitive metadata

Expand All @@ -110,41 +100,52 @@ The system SHALL include relevant metadata in the GitHub Issue body.
- Environment variables
- IP addresses

### Requirement: Feedback always works

The system SHALL allow feedback submission regardless of telemetry settings.

#### Scenario: Feedback with telemetry disabled

- **WHEN** user has disabled telemetry via `OPENSPEC_TELEMETRY=0`
- **AND** user runs `openspec feedback "message"`
- **THEN** the feedback is still submitted via `gh` CLI
- **AND** telemetry events are not sent

#### Scenario: Feedback in CI environment

- **WHEN** `CI=true` is set in the environment
- **AND** user runs `openspec feedback "message"`
- **THEN** the feedback submission proceeds normally (if `gh` is available and authenticated)

### Requirement: Error handling

The system SHALL handle feedback submission errors gracefully.

#### Scenario: Network failure
#### Scenario: gh CLI execution failure

- **WHEN** GitHub API is unreachable
- **THEN** the system displays a clear error message
- **AND** suggests checking network connectivity
- **AND** exits with non-zero code
- **WHEN** `gh issue create` command fails
- **THEN** the system displays the error output from `gh` CLI
- **AND** exits with the same exit code as `gh`

#### Scenario: GitHub API error
#### Scenario: Network failure

- **WHEN** GitHub API returns an error (rate limit, server error)
- **THEN** the system displays the error message from GitHub
- **WHEN** `gh` CLI reports network connectivity issues
- **THEN** the system displays the error message from `gh`
- **AND** suggests checking network connectivity
- **AND** exits with non-zero code

#### Scenario: Invalid token

- **WHEN** the stored token is revoked or invalid
- **THEN** the system clears the stored token
- **AND** initiates a new OAuth flow

### Requirement: Feedback skill for agents

The system SHALL provide a `/feedback` skill that guides agents through collecting and submitting user feedback.

#### Scenario: Agent-initiated feedback

- **WHEN** user invokes `/feedback <message>` in an agent conversation
- **WHEN** user invokes `/feedback` in an agent conversation
- **THEN** the agent gathers context from the conversation
- **AND** drafts a feedback issue with enriched content
- **AND** anonymizes sensitive information
- **AND** presents the draft to the user for approval
- **AND** submits via `openspec feedback` on user confirmation
- **AND** submits via `openspec feedback` command on user confirmation

#### Scenario: Context enrichment

Expand Down
48 changes: 23 additions & 25 deletions openspec/changes/add-feedback-command/tasks.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
## 1. GitHub Authentication
## 1. Feedback Command

- [ ] 1.1 Create `src/auth/github.ts` module with Device OAuth flow
- [ ] 1.2 Implement token storage in global config (`~/.config/openspec/`)
- [ ] 1.3 Add `getGitHubAuth()` function that returns cached token or initiates auth
- [ ] 1.4 Add `clearGitHubAuth()` function for logout capability
- [x] 1.1 Create `src/commands/feedback.ts` with command implementation
- [x] 1.2 Check `gh` CLI availability using platform-appropriate command (`which` on Unix/macOS, `where` on Windows)
- [x] 1.3 Check GitHub auth status with `gh auth status`
- [x] 1.4 Execute `gh issue create` with formatted title and body using `execFileSync` to prevent shell injection
- [x] 1.5 Display issue URL returned by `gh` CLI
- [x] 1.6 Register `feedback <message>` command in `src/cli/index.ts`
- [x] 1.7 Ensure cross-platform compatibility (macOS, Linux, Windows)

## 2. Feedback Command
## 2. Shell Completions

- [ ] 2.1 Create `src/commands/feedback.ts` with command implementation
- [ ] 2.2 Register `feedback <message>` command in CLI
- [ ] 2.3 Implement `--body` flag for rich content (title + body)
- [ ] 2.4 Create GitHub Issue via API with `feedback` label
- [ ] 2.5 Display created issue URL on success
- [x] 2.1 Add `feedback` command to command registry
- [x] 2.2 Regenerate completion scripts for all shells

## 3. Shell Completions
## 3. Feedback Skill

- [ ] 3.1 Add `feedback` command to command registry
- [ ] 3.2 Regenerate completion scripts for all shells
- [x] 3.1 Create feedback skill template in `skill-templates.ts`
- [x] 3.2 Document context gathering workflow
- [x] 3.3 Document anonymization rules
- [x] 3.4 Document user confirmation flow

## 4. Feedback Skill
## 4. Testing

- [ ] 4.1 Create feedback skill template in `skill-templates.ts`
- [ ] 4.2 Document context gathering workflow
- [ ] 4.3 Document anonymization rules
- [ ] 4.4 Document user confirmation flow

## 5. Testing

- [ ] 5.1 Add unit tests for GitHub auth module
- [ ] 5.2 Add unit tests for feedback command
- [ ] 5.3 Add integration test for full feedback flow (mocked GitHub API)
- [x] 4.1 Add unit tests for feedback command (mock `gh` subprocess calls)
- [x] 4.2 Add integration test for full feedback flow with mocked `gh` CLI
- [x] 4.3 Test error handling for missing `gh` CLI
- [x] 4.4 Test error handling for unauthenticated `gh` session
- [x] 4.5 Test cross-platform `gh` CLI detection (verify `which` on Unix, `where` on Windows)
- [x] 4.6 Test platform metadata includes correct value for Windows (win32)
17 changes: 17 additions & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ChangeCommand } from '../commands/change.js';
import { ValidateCommand } from '../commands/validate.js';
import { ShowCommand } from '../commands/show.js';
import { CompletionCommand } from '../commands/completion.js';
import { FeedbackCommand } from '../commands/feedback.js';
import { registerConfigCommand } from '../commands/config.js';
import { registerArtifactWorkflowCommands } from '../commands/artifact-workflow.js';
import { maybeShowTelemetryNotice, trackCommand, shutdown } from '../telemetry/index.js';
Expand Down Expand Up @@ -293,6 +294,22 @@ program
}
});

// Feedback command
program
.command('feedback <message>')
.description('Submit feedback about OpenSpec')
.option('--body <text>', 'Detailed description for the feedback')
.action(async (message: string, options?: { body?: string }) => {
try {
const feedbackCommand = new FeedbackCommand();
await feedbackCommand.execute(message, options);
} catch (error) {
console.log();
ora().fail(`Error: ${(error as Error).message}`);
process.exit(1);
}
});

// Completion command with subcommands
const completionCmd = program
.command('completion')
Expand Down
Loading
Loading