Skip to content

Commit c86985d

Browse files
authored
feat: add feedback command for submitting user feedback (Fission-AI#509)
* feat: add feedback command for submitting user feedback Implement `openspec feedback` command that creates GitHub Issues using the gh CLI. Includes graceful fallback to manual submission when gh is not available or not authenticated. Features: - Automatic gh CLI detection and authentication check - Graceful fallback with pre-filled issue URLs for manual submission - Automatic metadata inclusion (version, platform, timestamp) - /feedback skill for agent-assisted feedback with context enrichment - Comprehensive test coverage with mocked gh CLI calls * fix: address PR review comments for feedback command - Add Windows compatibility: use 'where gh' on Windows, 'which gh' on Unix/macOS - Fix shell injection vulnerability: replace execSync with execFileSync and argument arrays - Fix British English phrasing: "in future" → "in the future" - Reduce code duplication: extract formatTitle/formatBody to single location - Update tests to verify execFileSync usage and cross-platform command detection - Add spec scenarios for safe command execution and cross-platform support
1 parent bf4bc24 commit c86985d

8 files changed

Lines changed: 883 additions & 110 deletions

File tree

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
## Why
22

3-
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.
3+
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.
44

55
## What Changes
66

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

1212
## Impact
1313

1414
- Affected specs: New `cli-feedback` capability
1515
- Affected code:
1616
- `src/cli/index.ts` - Register feedback command
17-
- `src/commands/feedback.ts` - Command implementation
18-
- `src/auth/github.ts` - GitHub OAuth device flow
17+
- `src/commands/feedback.ts` - Command implementation using `gh` CLI
1918
- `src/core/templates/skill-templates.ts` - Feedback skill template
2019
- `src/core/completions/command-registry.ts` - Shell completions
20+
- External dependency: Requires `gh` CLI installed and authenticated

openspec/changes/add-feedback-command/specs/cli-feedback/spec.md

Lines changed: 80 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,91 +2,75 @@
22

33
### Requirement: Feedback command
44

5-
The system SHALL provide an `openspec feedback` command that creates a GitHub Issue in the openspec repository with the user's feedback.
5+
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.
66

77
#### Scenario: Simple feedback submission
88

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

14-
#### Scenario: Rich feedback with body
15+
#### Scenario: Safe command execution
16+
17+
- **WHEN** submitting feedback via `gh` CLI
18+
- **THEN** the system uses `execFileSync` with separate arguments array
19+
- **AND** user input is NOT passed through a shell
20+
- **AND** shell metacharacters (quotes, backticks, $(), etc.) are treated as literal text
21+
22+
#### Scenario: Feedback with body
1523

1624
- **WHEN** user executes `openspec feedback "Title here" --body "Detailed description..."`
1725
- **THEN** the system creates a GitHub Issue with the specified title
1826
- **AND** the issue body contains the detailed description
19-
- **AND** the issue body includes metadata (OpenSpec version, platform)
20-
21-
#### Scenario: Multiline message
22-
23-
- **WHEN** user provides a multiline message (first line as title, rest as body)
24-
- **THEN** the system uses the first line as the issue title
25-
- **AND** the remaining lines become the issue body
26-
27-
### Requirement: GitHub authentication
28-
29-
The system SHALL authenticate users via GitHub Device OAuth flow before submitting feedback.
30-
31-
#### Scenario: First-time authentication
32-
33-
- **WHEN** user runs `openspec feedback` for the first time
34-
- **AND** no GitHub token is stored
35-
- **THEN** the system initiates GitHub Device OAuth flow
36-
- **AND** displays a URL and code for the user to authorize
37-
- **AND** polls for authorization completion
38-
- **AND** stores the token in global config on success
39-
40-
#### Scenario: Cached authentication
41-
42-
- **WHEN** user runs `openspec feedback`
43-
- **AND** a valid GitHub token is stored
44-
- **THEN** the system uses the cached token without re-authentication
45-
46-
#### Scenario: Token refresh
47-
48-
- **WHEN** the stored GitHub token is expired or invalid
49-
- **THEN** the system initiates a new Device OAuth flow
50-
- **AND** updates the stored token on success
27+
- **AND** the issue body includes metadata (OpenSpec version, platform, timestamp)
5128

52-
#### Scenario: Authentication cancellation
29+
### Requirement: GitHub CLI dependency
5330

54-
- **WHEN** user cancels the OAuth flow (Ctrl+C)
55-
- **THEN** the system exits gracefully without storing any token
56-
- **AND** displays a message indicating feedback was not submitted
31+
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.
5732

58-
### Requirement: GitHub token storage
33+
#### Scenario: Missing gh CLI with fallback
5934

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

62-
#### Scenario: Token persistence
47+
#### Scenario: Cross-platform gh CLI detection on Unix
6348

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

68-
#### Scenario: Token isolation
53+
#### Scenario: Cross-platform gh CLI detection on Windows
6954

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

74-
### Requirement: Feedback always works
75-
76-
The system SHALL allow feedback submission regardless of telemetry settings.
59+
#### Scenario: Unauthenticated gh CLI with fallback
7760

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

85-
#### Scenario: Feedback in CI environment
69+
#### Scenario: Authenticated gh CLI
8670

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

9175
### Requirement: Issue metadata
9276

@@ -99,7 +83,13 @@ The system SHALL include relevant metadata in the GitHub Issue body.
9983
- OpenSpec CLI version
10084
- Platform (darwin, linux, win32)
10185
- Submission timestamp
102-
- Separator line indicating "Submitted via OpenSpec CLI"
86+
- Separator line: "---\nSubmitted via OpenSpec CLI"
87+
88+
#### Scenario: Windows platform metadata
89+
90+
- **WHEN** creating a GitHub Issue for feedback on Windows
91+
- **THEN** the issue body includes "Platform: win32"
92+
- **AND** all platform detection uses Node.js `os.platform()` API
10393

10494
#### Scenario: No sensitive metadata
10595

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

103+
### Requirement: Feedback always works
104+
105+
The system SHALL allow feedback submission regardless of telemetry settings.
106+
107+
#### Scenario: Feedback with telemetry disabled
108+
109+
- **WHEN** user has disabled telemetry via `OPENSPEC_TELEMETRY=0`
110+
- **AND** user runs `openspec feedback "message"`
111+
- **THEN** the feedback is still submitted via `gh` CLI
112+
- **AND** telemetry events are not sent
113+
114+
#### Scenario: Feedback in CI environment
115+
116+
- **WHEN** `CI=true` is set in the environment
117+
- **AND** user runs `openspec feedback "message"`
118+
- **THEN** the feedback submission proceeds normally (if `gh` is available and authenticated)
119+
113120
### Requirement: Error handling
114121

115122
The system SHALL handle feedback submission errors gracefully.
116123

117-
#### Scenario: Network failure
124+
#### Scenario: gh CLI execution failure
118125

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

124-
#### Scenario: GitHub API error
130+
#### Scenario: Network failure
125131

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

130-
#### Scenario: Invalid token
131-
132-
- **WHEN** the stored token is revoked or invalid
133-
- **THEN** the system clears the stored token
134-
- **AND** initiates a new OAuth flow
135-
136137
### Requirement: Feedback skill for agents
137138

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

140141
#### Scenario: Agent-initiated feedback
141142

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

149150
#### Scenario: Context enrichment
150151

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
1-
## 1. GitHub Authentication
1+
## 1. Feedback Command
22

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

8-
## 2. Feedback Command
11+
## 2. Shell Completions
912

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

16-
## 3. Shell Completions
16+
## 3. Feedback Skill
1717

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

21-
## 4. Feedback Skill
23+
## 4. Testing
2224

23-
- [ ] 4.1 Create feedback skill template in `skill-templates.ts`
24-
- [ ] 4.2 Document context gathering workflow
25-
- [ ] 4.3 Document anonymization rules
26-
- [ ] 4.4 Document user confirmation flow
27-
28-
## 5. Testing
29-
30-
- [ ] 5.1 Add unit tests for GitHub auth module
31-
- [ ] 5.2 Add unit tests for feedback command
32-
- [ ] 5.3 Add integration test for full feedback flow (mocked GitHub API)
25+
- [x] 4.1 Add unit tests for feedback command (mock `gh` subprocess calls)
26+
- [x] 4.2 Add integration test for full feedback flow with mocked `gh` CLI
27+
- [x] 4.3 Test error handling for missing `gh` CLI
28+
- [x] 4.4 Test error handling for unauthenticated `gh` session
29+
- [x] 4.5 Test cross-platform `gh` CLI detection (verify `which` on Unix, `where` on Windows)
30+
- [x] 4.6 Test platform metadata includes correct value for Windows (win32)

src/cli/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ChangeCommand } from '../commands/change.js';
1313
import { ValidateCommand } from '../commands/validate.js';
1414
import { ShowCommand } from '../commands/show.js';
1515
import { CompletionCommand } from '../commands/completion.js';
16+
import { FeedbackCommand } from '../commands/feedback.js';
1617
import { registerConfigCommand } from '../commands/config.js';
1718
import { registerArtifactWorkflowCommands } from '../commands/artifact-workflow.js';
1819
import { maybeShowTelemetryNotice, trackCommand, shutdown } from '../telemetry/index.js';
@@ -293,6 +294,22 @@ program
293294
}
294295
});
295296

297+
// Feedback command
298+
program
299+
.command('feedback <message>')
300+
.description('Submit feedback about OpenSpec')
301+
.option('--body <text>', 'Detailed description for the feedback')
302+
.action(async (message: string, options?: { body?: string }) => {
303+
try {
304+
const feedbackCommand = new FeedbackCommand();
305+
await feedbackCommand.execute(message, options);
306+
} catch (error) {
307+
console.log();
308+
ora().fail(`Error: ${(error as Error).message}`);
309+
process.exit(1);
310+
}
311+
});
312+
296313
// Completion command with subcommands
297314
const completionCmd = program
298315
.command('completion')

0 commit comments

Comments
 (0)