feedbackbasket-cli 0.12.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +289 -0
- package/README.md +44 -2
- package/dist/src/capabilities.d.ts +38 -0
- package/dist/src/capabilities.js +6 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +5 -1
- package/dist/src/commands/auth.d.ts +1 -0
- package/dist/src/commands/auth.js +6 -1
- package/dist/src/commands/feedback-bulk-update.js +3 -0
- package/dist/src/commands/feedback-delete.js +2 -6
- package/dist/src/commands/feedback-note.js +34 -2
- package/dist/src/commands/feedback-reply.js +3 -0
- package/dist/src/commands/mobile.js +1 -0
- package/dist/src/commands/projects.js +2 -6
- package/dist/src/commands/team.js +4 -8
- package/dist/src/commands/widget.js +1 -0
- package/dist/src/confirmation.d.ts +2 -0
- package/dist/src/confirmation.js +11 -0
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.js +2 -1
- package/package.json +8 -3
- package/skills/feedbackbasket/SKILL.md +34 -18
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## [3.0.0] - 2026-08-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added all 31 versioned product-operation mappings, including note update and note deletion.
|
|
10
|
+
- Added contract checks for commands, HTTP paths, confirmations, documentation, and package release safety.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- High-impact agent commands now need `--yes`.
|
|
15
|
+
- The CLI version now matches the MCP and agent contract version.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [0.12.0] - 2026-07-13
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Conversation controls** - enable or disable website visitor replies and native in-app follow-up replies independently from the CLI
|
|
24
|
+
- **Threaded conversation output** - `feedback replies` now shows both team messages and visitor follow-ups in chronological order
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **Mobile conversation guidance** - mobile status, breadcrumbs, README, and the packaged skill now cover SDK unread badges and same-thread replies
|
|
29
|
+
- **Agent thread safety** - agents preserve follow-up context on the original feedback item instead of creating duplicate feedback entries
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## [0.11.0] - 2026-07-13
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Autonomous mobile setup** - `mobile setup`, `status`, `bundle-ids`, and `verify` let agents configure and confirm native or hosted mobile feedback without using the dashboard
|
|
38
|
+
- **Safe mobile lifecycle controls** - mobile integrations can be disabled or have their publishable project key rotated through explicit confirmation commands
|
|
39
|
+
- **Mobile setup guidance** - agent output includes Swift package details, hosted-form configuration, supported frameworks, and connection metadata
|
|
40
|
+
- **Native in-app replies** - the CLI recognizes mobile reply threads and supports `--delivery in-app` for responses displayed by the Swift SDK
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **Publishable key safety** - mobile project keys are masked by default and are returned only when `--include-publishable-key` is explicitly supplied
|
|
45
|
+
- **Safe mobile breadcrumbs** - generated follow-up commands fall back to resolved project IDs when a typed project reference contains shell-active characters
|
|
46
|
+
- **Agent skill coverage** - the packaged skill now detects mobile frameworks, performs CLI-backed setup, protects private CLI/API credentials, and verifies SDK heartbeats
|
|
47
|
+
- **Reply-channel guidance** - feedback details distinguish native in-app replies from website-widget replies so agents choose the correct delivery method
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## [0.10.0] - 2026-07-10
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- **Waitlist capture mode** - `widget settings --capture-mode waitlist|feedback` switches the installed project script between waitlist and feedback capture
|
|
56
|
+
- **Waitlist management** - `waitlist list` supports search and pagination, while `waitlist export` provides the dashboard CSV from the terminal
|
|
57
|
+
- **Widget security settings** - configure automatic error tracking and visitor-approved console error sharing from the CLI
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- **Inline widget trigger safety** - docs and packaged skill now explicitly tell agents to use `openFeedbackForm()` instead of internal widget methods such as `open()` or `openModal()`
|
|
62
|
+
- **Waitlist integration guidance** - `widget script`, README, and the packaged skill explain how to annotate existing forms for waitlist capture
|
|
63
|
+
- **Native HTTP client** - removed Axios and its transitive dependency tree in favor of Node's built-in `fetch`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## [0.9.3] - 2026-06-19
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
|
|
71
|
+
- **Agent issue filing guidance** - the packaged skill now explains how agents should file discovered issues into the right FeedbackBasket project with short descriptions and structured metadata
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## [0.9.2] - 2026-06-12
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- **Project URL safety** - `projects create` and `projects update --url` now require explicit confirmation before saving localhost URLs, and agent mode requires `--allow-local-url`
|
|
80
|
+
- **Packaged skill docs** - agents now ask for the real website URL instead of using localhost, and keep basic modal feedback as the default unless guided feedback is requested
|
|
81
|
+
- **Widget project selection** - agents now resolve the FeedbackBasket project for the current app instead of relying on the CLI default project when installing widgets
|
|
82
|
+
- **Widget guidance** - README, help text, and breadcrumbs no longer nudge users to enable guided feedback by default
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## [0.9.1] - 2026-06-12
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- **Inline widget trigger guidance** - `widget script` now shows custom button examples for inline widgets, including trigger-aware popup anchoring
|
|
91
|
+
- **Packaged skill docs** - agents now use `openFeedbackForm({ trigger: event.currentTarget })` when installing custom inline trigger buttons
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## [0.9.0] - 2026-06-11
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- **Widget reply delivery** - `feedback reply` now supports `--delivery email|widget|both` so agents can reply in the widget thread, by email, or both
|
|
100
|
+
- **Widget thread visibility** - `feedback show` now includes whether feedback has an active widget thread
|
|
101
|
+
|
|
102
|
+
### Changed
|
|
103
|
+
|
|
104
|
+
- **Agent reply safety guidance** - the packaged skill now requires agents to verify reply delivery method before responding
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## [0.8.0] - 2026-06-11
|
|
109
|
+
|
|
110
|
+
### Added
|
|
111
|
+
|
|
112
|
+
- **`feedbackbasket feedback create`** - create feedback from the terminal with project, type, category, status, email, page URL, metadata, and agent JSON output support
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- **Agent reply safety guidance** - the packaged skill now tells agents to ask for a reply-to email before sending email replies when no project default is configured, and to use widget/dashboard replies for widget-only feedback
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## [0.7.0] - 2026-06-10
|
|
121
|
+
|
|
122
|
+
### Added
|
|
123
|
+
|
|
124
|
+
- **Prefilled email widget settings** - `widget settings` can now configure read-only prefilled emails and hide the email field only when a runtime email is provided
|
|
125
|
+
- **Feedback metadata output** - `feedback show` displays submitted widget metadata when available, and agent JSON output includes the metadata payload returned by the API
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## [0.6.1] - 2026-06-08
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- **Attachment links in feedback output** — `feedback show` now displays submitted screenshot/image URLs, and feedback/bug JSON responses include attachment metadata for agents
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## [0.6.0] - 2026-06-07
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
|
|
141
|
+
- **`feedbackbasket widget flow`** — view, enable, reset, or apply JSON configs for guided feedback types and follow-up questions
|
|
142
|
+
- **Expanded widget settings flags** — configure button size, radius, icon, email visibility, attachments, branding, z-index, and guided mode from the CLI
|
|
143
|
+
- **Submitted details in feedback output** — `feedback show` now displays visitor-selected feedback type and follow-up answers
|
|
144
|
+
|
|
145
|
+
### Changed
|
|
146
|
+
|
|
147
|
+
- **Agent skill docs** — updated widget setup guidance so agents can customize guided feedback flows during installation
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## [0.5.0] - 2026-05-10
|
|
152
|
+
|
|
153
|
+
### Added
|
|
154
|
+
|
|
155
|
+
- **`feedbackbasket login --manual`** — authenticate remote servers by approving in a browser and pasting the generated CLI token back into the terminal
|
|
156
|
+
|
|
157
|
+
### Changed
|
|
158
|
+
|
|
159
|
+
- **Clearer manual-login guidance** — `--manual` is documented as the flow for servers that cannot receive the localhost browser callback, while still requiring outbound HTTPS
|
|
160
|
+
- **CLI token validation** — login now rejects MCP API keys (`fb_key_...`) with a clear hint because CLI login requires `fb_cli_...` tokens
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## [0.4.0] - 2026-04-15
|
|
165
|
+
|
|
166
|
+
### Added
|
|
167
|
+
|
|
168
|
+
- **`feedback reply <id> "<content>"`** — send an email reply directly to the feedback submitter. The customer receives a branded email with your reply and the original feedback, and their response goes to the configured reply-to address
|
|
169
|
+
- **`feedback replies <id>`** — list all replies sent for a feedback item (content, reply-to, who sent it, timestamp)
|
|
170
|
+
- **`--reply-to <email>` on `feedback reply`** — override the project's default reply-to for a single reply
|
|
171
|
+
- **`--reply-to <email>` on `projects update`** — set or clear the default reply-to email for a project (e.g. `projects update myapp --reply-to vlad@example.com`)
|
|
172
|
+
- **Interactive reply-to prompt** — when sending a reply with no `--reply-to` and no project default, the CLI asks the human whether to use their account email or enter a custom one (agent mode returns a clear error asking the agent to pass `--reply-to` or set a project default)
|
|
173
|
+
- **`replyToEmail` in project detail** — `projects show` now displays the configured reply-to address
|
|
174
|
+
|
|
175
|
+
### API Endpoints
|
|
176
|
+
|
|
177
|
+
- `POST /api/v1/feedback/:id/replies` — send reply (requires `full` scope)
|
|
178
|
+
- `GET /api/v1/feedback/:id/replies` — list replies
|
|
179
|
+
- `PATCH /api/v1/projects/:id` — now accepts `replyToEmail` in the body
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## [0.3.5] - 2026-03-27
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- **Name resolution for `--project` flag**: `feedback list --project prontoshoot` and `bugs list --project prontoshoot` now resolve names to IDs — previously returned empty results when using names
|
|
188
|
+
|
|
189
|
+
### Changed
|
|
190
|
+
|
|
191
|
+
- **Project name in list output**: Bug list and feedback list now show the project name (in green) instead of just the ID — much easier to scan across projects
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## [0.3.3] - 2026-03-27
|
|
196
|
+
|
|
197
|
+
### Added
|
|
198
|
+
|
|
199
|
+
- **`--all` flag**: `feedback list --all` and `bugs list --all` to query across all projects, bypassing the default project filter
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## [0.3.2] - 2026-03-27
|
|
204
|
+
|
|
205
|
+
### Changed
|
|
206
|
+
|
|
207
|
+
- **Custom help output**: Basecamp-style grouped sections (CORE COMMANDS, SHORTCUTS, SEARCH & EXPORT, AUTH & CONFIG, FLAGS, EXAMPLES, LEARN MORE)
|
|
208
|
+
- **Short flags**: `-j` for `--json`, `-q` for `--quiet`, `-m` for `--md`
|
|
209
|
+
- **Branded header**: "FeedbackBasket CLI v0.3.2" with logo in help output
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## [0.3.1] - 2026-03-27
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
|
|
217
|
+
- **Login redirect flow**: Users who aren't logged in are now seamlessly redirected back to the CLI authorize page after login — no more needing to click the link twice
|
|
218
|
+
|
|
219
|
+
### Added
|
|
220
|
+
|
|
221
|
+
- **Skills repo**: Standalone [feedbackbasket-skills](https://github.com/deifos/feedbackbasket-skills) repo with install.md and enhanced SKILL.md
|
|
222
|
+
- **CLI docs page**: New `/docs/cli` page on feedbackbasket.com with full command reference and terminal demo
|
|
223
|
+
- **Landing page updates**: CLI feature card, dark terminal mockup, "Agent-Ready CLI" positioning
|
|
224
|
+
- **Published to npm**: `npm install -g feedbackbasket-cli` now available
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## [0.3.0] - 2026-03-26
|
|
229
|
+
|
|
230
|
+
### Added
|
|
231
|
+
|
|
232
|
+
- **Feedback delete**: `feedback delete <id>` — permanently remove feedback items with confirmation prompt
|
|
233
|
+
- **Bulk status update**: `feedback bulk-update --status CLOSED --ids id1,id2,id3` — update multiple items at once
|
|
234
|
+
- **Feedback export**: `feedback export [project] --format csv|md|json` — export all feedback to CSV, Markdown, or JSON
|
|
235
|
+
- **Widget management**: `widget settings [project]` — view and update widget configuration (color, label, position, messages, etc.)
|
|
236
|
+
- **Widget embed code**: `widget script [project]` — get the embed script tag ready to paste into HTML
|
|
237
|
+
- **Team management**: `team list`, `team role <id> --role admin`, `team remove <id>` — manage organization members
|
|
238
|
+
- **Note edit/delete**: API support for editing and deleting feedback notes (via PATCH/DELETE endpoints)
|
|
239
|
+
|
|
240
|
+
### Changed
|
|
241
|
+
|
|
242
|
+
- **Feedback commands expanded**: `feedback` now has 8 subcommands (list, show, search, update, note, delete, bulk-update, export)
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## [0.2.0] - 2026-03-26
|
|
247
|
+
|
|
248
|
+
### Added
|
|
249
|
+
|
|
250
|
+
- **Project CRUD**: `projects create`, `projects show`, `projects update`, `projects delete` — full project management from the CLI
|
|
251
|
+
- **Name resolution**: All project commands accept name or ID (e.g. `projects show feedbackbasket` instead of passing a cuid)
|
|
252
|
+
- **Fuzzy matching**: Typo suggestions ("Did you mean: feedbackbasket?") and ambiguity detection when multiple projects match
|
|
253
|
+
- **Top-level aliases**: `feedbackbasket login` and `feedbackbasket logout` (no need to type `auth login`)
|
|
254
|
+
- **Project alias**: `feedbackbasket project` works as alias for `feedbackbasket projects`
|
|
255
|
+
- **Onboarding wizard**: Multi-step first-login flow — authenticate, select default project, install Claude Code skill
|
|
256
|
+
- **Default project**: Set during onboarding or via config — auto-applied to `feedback list`, `bugs list`, etc. (override with `--project`)
|
|
257
|
+
|
|
258
|
+
### Changed
|
|
259
|
+
|
|
260
|
+
- **Full access by default**: Auth login now defaults to `--scope full` (like Basecamp), no more read-only by default
|
|
261
|
+
- **Brand colors**: All terminal output uses FeedbackBasket green (#22c55e) accent instead of generic cyan
|
|
262
|
+
- **Centralized theme**: New `src/output/theme.ts` with brand colors, semantic helpers, and logo renderer
|
|
263
|
+
- **Doctor command**: Now shows branded "FeedbackBasket CLI Diagnostics" header with logo
|
|
264
|
+
- **Login flow**: Shows branded "FeedbackBasket CLI" header with green URL during browser auth
|
|
265
|
+
- **Better error messages**: Auth and project fetch errors now show the actual error message instead of silent failures
|
|
266
|
+
- **Delete confirmation**: `projects delete` prompts for confirmation in interactive mode (skipped with `--yes` or `--agent`)
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## [0.1.0] - 2026-03-25
|
|
271
|
+
|
|
272
|
+
### Added
|
|
273
|
+
|
|
274
|
+
- Initial release of the FeedbackBasket CLI
|
|
275
|
+
- **Authentication**: Browser-based OAuth flow (`auth login`) and manual token input (`auth login --token`)
|
|
276
|
+
- **Auth management**: `auth status`, `auth logout`, `auth token` commands
|
|
277
|
+
- **Projects**: `projects list` — view all accessible projects with feedback stats
|
|
278
|
+
- **Feedback**: `feedback list` with filtering (--project, --category, --status, --sentiment, --search, --limit, --offset, --notes)
|
|
279
|
+
- **Feedback detail**: `feedback show <id>` — view single feedback item with full details
|
|
280
|
+
- **Feedback search**: `feedback search <query>` — cross-project text search
|
|
281
|
+
- **Feedback write**: `feedback update <id>` — update status, category, sentiment (requires full scope)
|
|
282
|
+
- **Feedback notes**: `feedback note <id> "<content>"` — add internal notes (requires full scope)
|
|
283
|
+
- **Bug reports**: `bugs list` with severity/status filtering, `bugs stats` for summary
|
|
284
|
+
- **Diagnostics**: `doctor` command — health checks for auth, connectivity, and integrations
|
|
285
|
+
- **Agent integration**: `setup claude` — install SKILL.md for Claude Code
|
|
286
|
+
- **Output modes**: Auto-detect (styled TTY / JSON piped), `--json` (envelope with breadcrumbs), `--quiet`/`--agent` (raw data), `--md` (Markdown)
|
|
287
|
+
- **JSON envelope**: Basecamp-inspired `{ ok, data, summary, breadcrumbs }` response format
|
|
288
|
+
- **Structured errors**: Error codes, exit codes, and recovery hints
|
|
289
|
+
- **Credential storage**: `~/.config/feedbackbasket/credentials.json` with `FEEDBACKBASKET_TOKEN` env var support
|
package/README.md
CHANGED
|
@@ -26,7 +26,9 @@ feedbackbasket feedback create "Login button is broken" --project myapp --type b
|
|
|
26
26
|
feedbackbasket bugs list --severity high
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
The first time you log in, a setup wizard walks you through selecting a default project and installing the Claude Code skill.
|
|
29
|
+
The first time you log in, a setup wizard walks you through selecting a default project and installing the Claude Code skill.
|
|
30
|
+
|
|
31
|
+
The CLI uses agent surface version `3.0.0`. CLI login accepts only private CLI credentials. It does not accept MCP keys. Use `--yes` for high-impact commands in agent or machine mode. Interactive use can show a confirmation prompt.
|
|
30
32
|
|
|
31
33
|
## Agent Usage
|
|
32
34
|
|
|
@@ -50,7 +52,47 @@ When installing or configuring a widget for the current app, agents should not r
|
|
|
50
52
|
feedbackbasket setup claude
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
<!-- BEGIN GENERATED AGENT CAPABILITIES -->
|
|
56
|
+
## Agent capability contract
|
|
57
|
+
|
|
58
|
+
Agent surface version: `3.0.0`. The CLI and both MCP transports implement the same 31 product operations.
|
|
59
|
+
|
|
60
|
+
| Product operation | CLI command | MCP tool | Required access | Confirm |
|
|
61
|
+
| --- | --- | --- | --- | --- |
|
|
62
|
+
| `projects.list` | `projects list` | `list_projects` | `read:projects` | No |
|
|
63
|
+
| `projects.get` | `projects show` | `get_project` | `read:projects; allowed project` | No |
|
|
64
|
+
| `projects.create` | `projects create` | `create_project` | `write:projects; unrestricted key` | No |
|
|
65
|
+
| `projects.update` | `projects update` | `update_project` | `write:projects; allowed project` | No |
|
|
66
|
+
| `projects.delete` | `projects delete` | `delete_project` | `write:projects; allowed project` | Yes |
|
|
67
|
+
| `feedback.list` | `feedback list` | `get_feedback` | `read:feedback; allowed project` | No |
|
|
68
|
+
| `feedback.get` | `feedback show` | `get_feedback_item` | `read:feedback; allowed project` | No |
|
|
69
|
+
| `feedback.search` | `feedback search` | `search_feedback` | `read:feedback; allowed project` | No |
|
|
70
|
+
| `feedback.create` | `feedback create` | `create_feedback` | `write:feedback; allowed project` | No |
|
|
71
|
+
| `feedback.update` | `feedback update` | `update_feedback` | `write:feedback; allowed project` | No |
|
|
72
|
+
| `feedback.delete` | `feedback delete` | `delete_feedback` | `write:feedback; allowed project` | Yes |
|
|
73
|
+
| `feedback.bulkUpdate` | `feedback bulk-update` | `bulk_update_feedback` | `write:feedback; allowed project` | Yes |
|
|
74
|
+
| `feedback.export` | `feedback export` | `export_feedback` | `read:feedback; allowed project` | No |
|
|
75
|
+
| `bugs.list` | `bugs list` | `get_bug_reports` | `read:feedback; allowed project` | No |
|
|
76
|
+
| `bugs.stats` | `bugs stats` | `get_bug_stats` | `read:feedback; allowed project` | No |
|
|
77
|
+
| `notes.create` | `feedback note` | `create_feedback_note` | `write:notes; allowed project` | No |
|
|
78
|
+
| `notes.update` | `feedback note update` | `update_feedback_note` | `write:notes; allowed project` | No |
|
|
79
|
+
| `notes.delete` | `feedback note delete` | `delete_feedback_note` | `write:notes; allowed project` | Yes |
|
|
80
|
+
| `replies.list` | `feedback replies` | `list_feedback_replies` | `read:feedback; allowed project` | No |
|
|
81
|
+
| `replies.send` | `feedback reply` | `send_feedback_reply` | `write:replies; allowed project` | Yes |
|
|
82
|
+
| `widget.getSettings` | `widget settings` | `get_widget_settings` | `read:projects; allowed project` | No |
|
|
83
|
+
| `widget.updateSettings` | `widget update`<br>`widget flow` | `update_widget_settings` | `write:widget; allowed project` | No |
|
|
84
|
+
| `widget.getScript` | `widget script` | `get_widget_script` | `read:projects; allowed project` | No |
|
|
85
|
+
| `mobile.get` | `mobile status`<br>`mobile verify` | `get_mobile_integration` | `read:projects; allowed project` | No |
|
|
86
|
+
| `mobile.update` | `mobile setup`<br>`mobile bundle`<br>`mobile conversations`<br>`mobile disable` | `update_mobile_integration` | `write:mobile; allowed project` | No |
|
|
87
|
+
| `mobile.rotateKey` | `mobile rotate-key` | `rotate_mobile_project_key` | `write:mobile; allowed project` | Yes |
|
|
88
|
+
| `waitlist.list` | `waitlist list` | `get_waitlist` | `read:feedback; allowed project` | No |
|
|
89
|
+
| `waitlist.export` | `waitlist export` | `export_waitlist` | `read:feedback; allowed project` | No |
|
|
90
|
+
| `team.list` | `team list` | `list_team_members` | `write:team; unrestricted key` | No |
|
|
91
|
+
| `team.updateRole` | `team role` | `update_team_member_role` | `write:team; unrestricted key` | Yes |
|
|
92
|
+
| `team.remove` | `team remove` | `remove_team_member` | `write:team; unrestricted key` | Yes |
|
|
93
|
+
<!-- END GENERATED AGENT CAPABILITIES -->
|
|
94
|
+
|
|
95
|
+
## Commands
|
|
54
96
|
|
|
55
97
|
### Authentication
|
|
56
98
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ProductOperationId } from 'feedbackbasket-agent-contract';
|
|
2
|
+
export declare const CLI_CAPABILITIES: readonly {
|
|
3
|
+
operationId: ProductOperationId;
|
|
4
|
+
commands: readonly string[];
|
|
5
|
+
}[];
|
|
6
|
+
export declare const CLI_EXEMPTIONS: ({
|
|
7
|
+
readonly id: "auth";
|
|
8
|
+
readonly surface: "cli";
|
|
9
|
+
readonly reason: "Authentication is local CLI credential management, not a product operation.";
|
|
10
|
+
} | {
|
|
11
|
+
readonly id: "login";
|
|
12
|
+
readonly surface: "cli";
|
|
13
|
+
readonly reason: "The login shortcut starts the local CLI authentication flow.";
|
|
14
|
+
} | {
|
|
15
|
+
readonly id: "logout";
|
|
16
|
+
readonly surface: "cli";
|
|
17
|
+
readonly reason: "Logout removes a local CLI credential.";
|
|
18
|
+
} | {
|
|
19
|
+
readonly id: "doctor";
|
|
20
|
+
readonly surface: "cli";
|
|
21
|
+
readonly reason: "Doctor checks local CLI configuration and connectivity.";
|
|
22
|
+
} | {
|
|
23
|
+
readonly id: "setup";
|
|
24
|
+
readonly surface: "cli";
|
|
25
|
+
readonly reason: "Setup installs local agent guidance and does not change FeedbackBasket product data.";
|
|
26
|
+
} | {
|
|
27
|
+
readonly id: "output";
|
|
28
|
+
readonly surface: "cli";
|
|
29
|
+
readonly reason: "Output flags change terminal formatting only.";
|
|
30
|
+
} | {
|
|
31
|
+
readonly id: "initialize";
|
|
32
|
+
readonly surface: "mcp";
|
|
33
|
+
readonly reason: "MCP initialization is a transport protocol operation.";
|
|
34
|
+
} | {
|
|
35
|
+
readonly id: "resources";
|
|
36
|
+
readonly surface: "mcp";
|
|
37
|
+
readonly reason: "Public MCP resources describe the service and do not access customer product data.";
|
|
38
|
+
})[];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { PARITY_EXEMPTIONS, PRODUCT_OPERATIONS, } from 'feedbackbasket-agent-contract';
|
|
2
|
+
export const CLI_CAPABILITIES = PRODUCT_OPERATIONS.map((operation) => ({
|
|
3
|
+
operationId: operation.id,
|
|
4
|
+
commands: operation.cli.commands,
|
|
5
|
+
}));
|
|
6
|
+
export const CLI_EXEMPTIONS = PARITY_EXEMPTIONS.filter(({ surface }) => surface === 'cli');
|
package/dist/src/cli.d.ts
CHANGED
package/dist/src/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ function resolveFormat(opts) {
|
|
|
27
27
|
function getWriter() {
|
|
28
28
|
return writer;
|
|
29
29
|
}
|
|
30
|
-
export function
|
|
30
|
+
export function createProgram() {
|
|
31
31
|
const program = new Command('feedbackbasket')
|
|
32
32
|
.version(VERSION, '-v, --version')
|
|
33
33
|
.description('Command-line interface for FeedbackBasket')
|
|
@@ -71,6 +71,10 @@ export function run() {
|
|
|
71
71
|
program.addCommand(createSetupCommand(getWriter));
|
|
72
72
|
// Global error handler
|
|
73
73
|
program.exitOverride();
|
|
74
|
+
return program;
|
|
75
|
+
}
|
|
76
|
+
export function run() {
|
|
77
|
+
const program = createProgram();
|
|
74
78
|
(async () => {
|
|
75
79
|
try {
|
|
76
80
|
await program.parseAsync(process.argv);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import type { OutputWriter } from '../output/writer.js';
|
|
3
3
|
export declare function createAuthCommand(getWriter: () => OutputWriter): Command;
|
|
4
|
+
export declare function resolveAuthScope(value: string): 'read' | 'full';
|
|
4
5
|
export declare function createLoginCommand(getWriter: () => OutputWriter): Command;
|
|
5
6
|
export declare function createLogoutCommand(getWriter: () => OutputWriter): Command;
|
|
@@ -23,7 +23,7 @@ export function createAuthCommand(getWriter) {
|
|
|
23
23
|
.action(async (opts) => {
|
|
24
24
|
const writer = getWriter();
|
|
25
25
|
const config = loadConfig();
|
|
26
|
-
const scope = opts.scope
|
|
26
|
+
const scope = resolveAuthScope(opts.scope);
|
|
27
27
|
const isInteractive = !writer.isMachineOutput() && process.stdin.isTTY;
|
|
28
28
|
// ── Step 1: Authentication ──
|
|
29
29
|
if (isInteractive) {
|
|
@@ -294,6 +294,11 @@ export function createAuthCommand(getWriter) {
|
|
|
294
294
|
});
|
|
295
295
|
return auth;
|
|
296
296
|
}
|
|
297
|
+
export function resolveAuthScope(value) {
|
|
298
|
+
if (value === 'read' || value === 'full')
|
|
299
|
+
return value;
|
|
300
|
+
throw errUsage('Scope must be "read" or "full"');
|
|
301
|
+
}
|
|
297
302
|
// Top-level aliases: `feedbackbasket login` and `feedbackbasket logout`
|
|
298
303
|
export function createLoginCommand(getWriter) {
|
|
299
304
|
return new Command('login')
|
|
@@ -4,11 +4,13 @@ import { AuthManager } from '../auth/manager.js';
|
|
|
4
4
|
import { loadConfig } from '../config/config.js';
|
|
5
5
|
import { errAuth, errUsage } from '../output/errors.js';
|
|
6
6
|
import { brand } from '../output/theme.js';
|
|
7
|
+
import { requireHighImpactConfirmation } from '../confirmation.js';
|
|
7
8
|
export function createFeedbackBulkUpdateCommand(getWriter) {
|
|
8
9
|
return new Command('bulk-update')
|
|
9
10
|
.description('Update status for multiple feedback items at once')
|
|
10
11
|
.requiredOption('--status <status>', 'New status (OPEN, UNDER_REVIEW, PLANNED, IN_PROGRESS, COMPLETE, CLOSED)')
|
|
11
12
|
.requiredOption('--ids <ids>', 'Comma-separated feedback IDs')
|
|
13
|
+
.option('--yes', 'Confirm the bulk update')
|
|
12
14
|
.action(async (opts) => {
|
|
13
15
|
const writer = getWriter();
|
|
14
16
|
const client = requireClient();
|
|
@@ -16,6 +18,7 @@ export function createFeedbackBulkUpdateCommand(getWriter) {
|
|
|
16
18
|
if (ids.length === 0) {
|
|
17
19
|
throw errUsage('At least one ID is required', 'Example: --ids id1,id2,id3');
|
|
18
20
|
}
|
|
21
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), `Update ${ids.length} feedback item${ids.length === 1 ? '' : 's'}?`, '--yes is required for a bulk update in machine mode.');
|
|
19
22
|
const result = await client.bulkUpdateStatus(ids, opts.status);
|
|
20
23
|
if (!writer.isMachineOutput()) {
|
|
21
24
|
console.log(` ${brand.success('✓')} Updated ${result.updated} feedback items to ${brand.bold(result.status)}`);
|
|
@@ -4,7 +4,7 @@ import { AuthManager } from '../auth/manager.js';
|
|
|
4
4
|
import { loadConfig } from '../config/config.js';
|
|
5
5
|
import { errAuth } from '../output/errors.js';
|
|
6
6
|
import { brand } from '../output/theme.js';
|
|
7
|
-
import {
|
|
7
|
+
import { requireHighImpactConfirmation } from '../confirmation.js';
|
|
8
8
|
export function createFeedbackDeleteCommand(getWriter) {
|
|
9
9
|
return new Command('delete')
|
|
10
10
|
.argument('<id>', 'Feedback ID to delete')
|
|
@@ -16,12 +16,8 @@ export function createFeedbackDeleteCommand(getWriter) {
|
|
|
16
16
|
if (!opts.yes && !writer.isMachineOutput() && process.stdin.isTTY) {
|
|
17
17
|
console.log(` ${brand.warning('Warning:')} This will permanently delete feedback ${brand.bold(id)}`);
|
|
18
18
|
console.log();
|
|
19
|
-
const confirmed = await confirm(' Delete this feedback?', false);
|
|
20
|
-
if (!confirmed) {
|
|
21
|
-
console.log(brand.muted(' Cancelled.'));
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
19
|
}
|
|
20
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), 'Delete this feedback?', '--yes is required to delete feedback in machine mode.');
|
|
25
21
|
const result = await client.deleteFeedback(id);
|
|
26
22
|
if (!writer.isMachineOutput()) {
|
|
27
23
|
console.log(` ${brand.success('✓')} Deleted feedback ${id}`);
|
|
@@ -4,15 +4,19 @@ import { AuthManager } from '../auth/manager.js';
|
|
|
4
4
|
import { loadConfig } from '../config/config.js';
|
|
5
5
|
import { errAuth, errUsage } from '../output/errors.js';
|
|
6
6
|
import { brand } from '../output/theme.js';
|
|
7
|
+
import { requireHighImpactConfirmation } from '../confirmation.js';
|
|
7
8
|
export function createFeedbackNoteCommand(getWriter) {
|
|
8
|
-
|
|
9
|
-
.argument('
|
|
9
|
+
const note = new Command('note')
|
|
10
|
+
.argument('[id]', 'Feedback ID to add a note to')
|
|
10
11
|
.argument('[content]', 'Note content (or use --content)')
|
|
11
12
|
.description('Add an internal note to a feedback item')
|
|
12
13
|
.option('--content <text>', 'Note content (alternative to positional argument)')
|
|
13
14
|
.action(async (id, contentArg, opts) => {
|
|
14
15
|
const writer = getWriter();
|
|
15
16
|
const content = contentArg ?? opts.content;
|
|
17
|
+
if (!id) {
|
|
18
|
+
throw errUsage('Feedback ID is required', 'Example: feedbackbasket feedback note <id> "Your note here"');
|
|
19
|
+
}
|
|
16
20
|
if (!content) {
|
|
17
21
|
throw errUsage('Note content is required', 'Example: feedbackbasket feedback note <id> "Your note here"');
|
|
18
22
|
}
|
|
@@ -30,6 +34,34 @@ export function createFeedbackNoteCommand(getWriter) {
|
|
|
30
34
|
],
|
|
31
35
|
});
|
|
32
36
|
});
|
|
37
|
+
note
|
|
38
|
+
.command('update <feedbackId> <noteId>')
|
|
39
|
+
.description('Update an internal feedback note')
|
|
40
|
+
.requiredOption('--content <text>', 'New note content')
|
|
41
|
+
.action(async (feedbackId, noteId, opts) => {
|
|
42
|
+
const writer = getWriter();
|
|
43
|
+
const client = requireClient();
|
|
44
|
+
const result = await client.updateNote(feedbackId, noteId, opts.content);
|
|
45
|
+
writer.ok(result, {
|
|
46
|
+
summary: `Updated note ${noteId}`,
|
|
47
|
+
breadcrumbs: [{ action: 'View feedback', cmd: `feedbackbasket feedback show ${feedbackId}` }],
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
note
|
|
51
|
+
.command('delete <feedbackId> <noteId>')
|
|
52
|
+
.description('Delete an internal feedback note')
|
|
53
|
+
.option('--yes', 'Confirm note deletion')
|
|
54
|
+
.action(async (feedbackId, noteId, opts) => {
|
|
55
|
+
const writer = getWriter();
|
|
56
|
+
const client = requireClient();
|
|
57
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), `Delete note ${noteId}?`, '--yes is required to delete a note in machine mode.');
|
|
58
|
+
const result = await client.deleteNote(feedbackId, noteId);
|
|
59
|
+
writer.ok(result, {
|
|
60
|
+
summary: `Deleted note ${noteId}`,
|
|
61
|
+
breadcrumbs: [{ action: 'View feedback', cmd: `feedbackbasket feedback show ${feedbackId}` }],
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
return note;
|
|
33
65
|
}
|
|
34
66
|
function requireClient() {
|
|
35
67
|
const manager = new AuthManager();
|
|
@@ -5,6 +5,7 @@ import { loadConfig } from '../config/config.js';
|
|
|
5
5
|
import { errAuth, errUsage } from '../output/errors.js';
|
|
6
6
|
import { brand } from '../output/theme.js';
|
|
7
7
|
import { ask } from '../prompt.js';
|
|
8
|
+
import { requireHighImpactConfirmation } from '../confirmation.js';
|
|
8
9
|
const deliveryOptions = new Set(['email', 'widget', 'in-app', 'both']);
|
|
9
10
|
export function createFeedbackReplyCommand(getWriter) {
|
|
10
11
|
return new Command('reply')
|
|
@@ -14,6 +15,7 @@ export function createFeedbackReplyCommand(getWriter) {
|
|
|
14
15
|
.option('--content <text>', 'Reply content (alternative to positional argument)')
|
|
15
16
|
.option('--delivery <delivery>', 'Reply delivery (email, widget, in-app, both)', 'email')
|
|
16
17
|
.option('--reply-to <email>', 'Reply-to email for email delivery')
|
|
18
|
+
.option('--yes', 'Confirm that the reply can be sent')
|
|
17
19
|
.action(async (id, contentArg, opts) => {
|
|
18
20
|
const writer = getWriter();
|
|
19
21
|
const content = contentArg ?? opts.content;
|
|
@@ -61,6 +63,7 @@ export function createFeedbackReplyCommand(getWriter) {
|
|
|
61
63
|
if (sendsWidget && !feedback.hasWidgetAccess) {
|
|
62
64
|
throw errUsage('This feedback has no in-app or widget reply thread.', 'Use --delivery email for feedback with an email address, or ask the human how they want to respond.');
|
|
63
65
|
}
|
|
66
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), `Send this reply by ${delivery}?`, '--yes is required to send a reply in machine mode.');
|
|
64
67
|
const result = await client.sendReply(id, content, {
|
|
65
68
|
replyToEmail: replyTo,
|
|
66
69
|
destinations,
|
|
@@ -67,6 +67,7 @@ export function createMobileCommand(getWriter) {
|
|
|
67
67
|
});
|
|
68
68
|
mobile
|
|
69
69
|
.command('bundle-ids [project]')
|
|
70
|
+
.alias('bundle')
|
|
70
71
|
.description('Add or remove allowed iOS bundle IDs')
|
|
71
72
|
.option('--add <bundle-id>', 'Bundle ID to add (repeatable)', collect, [])
|
|
72
73
|
.option('--remove <bundle-id>', 'Bundle ID to remove (repeatable)', collect, [])
|
|
@@ -5,6 +5,7 @@ import { loadConfig } from '../config/config.js';
|
|
|
5
5
|
import { errAuth, errUsage } from '../output/errors.js';
|
|
6
6
|
import { brand, divider } from '../output/theme.js';
|
|
7
7
|
import { confirm } from '../prompt.js';
|
|
8
|
+
import { requireHighImpactConfirmation } from '../confirmation.js';
|
|
8
9
|
import { resolveProject } from '../resolve.js';
|
|
9
10
|
export function createProjectsCommand(getWriter) {
|
|
10
11
|
const projects = new Command('projects')
|
|
@@ -139,17 +140,12 @@ export function createProjectsCommand(getWriter) {
|
|
|
139
140
|
const resolved = await resolveProject(client, idOrName);
|
|
140
141
|
const id = resolved.id;
|
|
141
142
|
const projectName = resolved.name;
|
|
142
|
-
// Confirmation (skip in agent mode or --yes)
|
|
143
143
|
if (!opts.yes && !writer.isMachineOutput() && process.stdin.isTTY) {
|
|
144
144
|
console.log(` ${brand.warning('Warning:')} This will permanently delete project "${brand.bold(projectName)}"`);
|
|
145
145
|
console.log(` ${brand.muted('All feedback, notes, and settings will be lost.')}`);
|
|
146
146
|
console.log();
|
|
147
|
-
const confirmed = await confirm(` Delete "${projectName}"?`, false);
|
|
148
|
-
if (!confirmed) {
|
|
149
|
-
console.log(brand.muted(' Cancelled.'));
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
147
|
}
|
|
148
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), `Delete "${projectName}"?`, '--yes is required to delete a project in machine mode.');
|
|
153
149
|
const result = await client.deleteProject(id);
|
|
154
150
|
if (!writer.isMachineOutput()) {
|
|
155
151
|
console.log(` ${brand.success('✓')} Deleted project "${brand.bold(result.name)}"`);
|
|
@@ -4,7 +4,7 @@ import { AuthManager } from '../auth/manager.js';
|
|
|
4
4
|
import { loadConfig } from '../config/config.js';
|
|
5
5
|
import { errAuth, errUsage } from '../output/errors.js';
|
|
6
6
|
import { brand, divider } from '../output/theme.js';
|
|
7
|
-
import {
|
|
7
|
+
import { requireHighImpactConfirmation } from '../confirmation.js';
|
|
8
8
|
export function createTeamCommand(getWriter) {
|
|
9
9
|
const team = new Command('team')
|
|
10
10
|
.description('Manage organization members');
|
|
@@ -31,12 +31,14 @@ export function createTeamCommand(getWriter) {
|
|
|
31
31
|
.command('role <memberId>')
|
|
32
32
|
.description('Update a member\'s role')
|
|
33
33
|
.requiredOption('--role <role>', 'New role: admin or member')
|
|
34
|
+
.option('--yes', 'Confirm the role change')
|
|
34
35
|
.action(async (memberId, opts) => {
|
|
35
36
|
const writer = getWriter();
|
|
36
37
|
const client = requireClient();
|
|
37
38
|
if (!['admin', 'member'].includes(opts.role)) {
|
|
38
39
|
throw errUsage('Role must be "admin" or "member"');
|
|
39
40
|
}
|
|
41
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), `Change member ${memberId} to ${opts.role}?`, '--yes is required to change a team role in machine mode.');
|
|
40
42
|
const result = await client.updateMemberRole(memberId, opts.role);
|
|
41
43
|
if (!writer.isMachineOutput()) {
|
|
42
44
|
console.log(` ${brand.success('✓')} Updated ${brand.bold(result.name)} to ${brand.bold(result.role)}`);
|
|
@@ -57,13 +59,7 @@ export function createTeamCommand(getWriter) {
|
|
|
57
59
|
.action(async (memberId, opts) => {
|
|
58
60
|
const writer = getWriter();
|
|
59
61
|
const client = requireClient();
|
|
60
|
-
|
|
61
|
-
const confirmed = await confirm(` Remove member ${memberId}?`, false);
|
|
62
|
-
if (!confirmed) {
|
|
63
|
-
console.log(brand.muted(' Cancelled.'));
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
62
|
+
await requireHighImpactConfirmation(writer, Boolean(opts.yes), `Remove member ${memberId}?`, '--yes is required to remove a team member in machine mode.');
|
|
67
63
|
const result = await client.removeMember(memberId);
|
|
68
64
|
if (!writer.isMachineOutput()) {
|
|
69
65
|
console.log(` ${brand.success('✓')} Removed ${brand.bold(result.name)} (${result.email})`);
|
|
@@ -50,6 +50,7 @@ export function createWidgetCommand(getWriter) {
|
|
|
50
50
|
// --- widget settings ---
|
|
51
51
|
widget
|
|
52
52
|
.command('settings [project]')
|
|
53
|
+
.alias('update')
|
|
53
54
|
.description('View or update widget settings')
|
|
54
55
|
.option('--capture-mode <mode>', 'Capture mode (feedback, waitlist)')
|
|
55
56
|
.option('--color <hex>', 'Button color (e.g. #22c55e)')
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { errUsage } from './output/errors.js';
|
|
2
|
+
import { confirm } from './prompt.js';
|
|
3
|
+
export async function requireHighImpactConfirmation(writer, confirmedByFlag, question, hint) {
|
|
4
|
+
if (confirmedByFlag)
|
|
5
|
+
return;
|
|
6
|
+
if (writer.isMachineOutput() || !process.stdin.isTTY) {
|
|
7
|
+
throw errUsage(hint, `${hint} Re-run the command with --yes.`);
|
|
8
|
+
}
|
|
9
|
+
if (!(await confirm(` ${question}`, false)))
|
|
10
|
+
throw errUsage('Action cancelled');
|
|
11
|
+
}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION
|
|
2
|
-
export declare const USER_AGENT
|
|
1
|
+
export declare const VERSION: "3.0.0";
|
|
2
|
+
export declare const USER_AGENT: string;
|
package/dist/src/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feedbackbasket-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Command-line interface for FeedbackBasket — manage feedback and waitlists from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/cli.js",
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"test": "tsx --test tests/*.test.ts",
|
|
13
13
|
"dev": "tsx bin/feedbackbasket.ts",
|
|
14
14
|
"start": "node dist/bin/feedbackbasket.js",
|
|
15
|
-
"
|
|
15
|
+
"check:parity": "tsx scripts/check-parity.ts",
|
|
16
|
+
"docs:generate": "tsx scripts/generate-capabilities.ts",
|
|
17
|
+
"docs:check": "tsx scripts/generate-capabilities.ts --check",
|
|
18
|
+
"prepublishOnly": "npm run check:parity && npm run docs:check && npm test && npm run build"
|
|
16
19
|
},
|
|
17
20
|
"keywords": [
|
|
18
21
|
"feedbackbasket",
|
|
@@ -31,6 +34,7 @@
|
|
|
31
34
|
"dependencies": {
|
|
32
35
|
"chalk": "^5.3.0",
|
|
33
36
|
"commander": "^13.1.0",
|
|
37
|
+
"feedbackbasket-agent-contract": "3.0.0",
|
|
34
38
|
"open": "^10.1.0"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
@@ -44,6 +48,7 @@
|
|
|
44
48
|
"files": [
|
|
45
49
|
"dist/**/*",
|
|
46
50
|
"skills/**/*",
|
|
47
|
-
"README.md"
|
|
51
|
+
"README.md",
|
|
52
|
+
"CHANGELOG.md"
|
|
48
53
|
]
|
|
49
54
|
}
|
|
@@ -5,7 +5,9 @@ description: Manage FeedbackBasket projects, feedback, bugs, website widgets, mo
|
|
|
5
5
|
|
|
6
6
|
# FeedbackBasket CLI
|
|
7
7
|
|
|
8
|
-
Full command-line interface for managing feedback, waitlist signups, bug reports, projects, widgets, and teams in FeedbackBasket. Works with any AI agent that can run shell commands.
|
|
8
|
+
Full command-line interface for managing feedback, waitlist signups, bug reports, projects, widgets, and teams in FeedbackBasket. Works with any AI agent that can run shell commands.
|
|
9
|
+
|
|
10
|
+
The unified agent surface version is `3.0.0`. It has 31 product operations. The CLI, stdio MCP package, and live Streamable HTTP MCP server implement the same contract.
|
|
9
11
|
|
|
10
12
|
## Authentication
|
|
11
13
|
|
|
@@ -27,7 +29,17 @@ feedbackbasket doctor # Full diagnostics
|
|
|
27
29
|
| `--quiet` | Raw JSON data only | Scripting |
|
|
28
30
|
| `--md` | Markdown | Documentation |
|
|
29
31
|
|
|
30
|
-
**Agent rule**: Always use `--agent` for programmatic access. Parse the JSON output directly.
|
|
32
|
+
**Agent rule**: Always use `--agent` for programmatic access. Parse the JSON output directly.
|
|
33
|
+
|
|
34
|
+
## MCP Workflow Selection
|
|
35
|
+
|
|
36
|
+
Use the CLI when the agent has shell access and an existing CLI login. Use MCP when the host supports MCP tools. For MCP, use either the `feedbackbasket-mcp-server@3.0.0` stdio package or the direct Streamable HTTP endpoint at `https://feedbackbasket.com/.well-known/mcp`.
|
|
37
|
+
|
|
38
|
+
CLI credentials and MCP keys are private and are not interchangeable. Never put a credential in source, command arguments, logs, prompts, snapshots, generated files, or final responses. Use the host credential store or an environment variable.
|
|
39
|
+
|
|
40
|
+
MCP read keys can use read operations only. Full keys can use writes that their scopes permit. A project-restricted key can access only its allowed projects. Project creation and team operations need an unrestricted full key. If a write is denied, do not try a different security path. Ask the user for the required access.
|
|
41
|
+
|
|
42
|
+
High-impact operations need explicit approval. MCP calls must include `confirm: true`. CLI agent or machine commands must include `--yes`. These rules apply to project deletion, feedback deletion, bulk feedback updates, note deletion, replies, mobile key rotation, team role changes, and team removal.
|
|
31
43
|
|
|
32
44
|
## Quick Reference
|
|
33
45
|
|
|
@@ -121,16 +133,18 @@ feedbackbasket feedback search "crash on mobile" --project <id> --limit 10
|
|
|
121
133
|
# Write
|
|
122
134
|
feedbackbasket feedback create "Login button is broken" --content "Clicking Log in does nothing in Safari." --project <id> --type bug
|
|
123
135
|
feedbackbasket feedback create "Feature idea" --content "Let users export saved views." --project <id> --type feature --metadata source=agent
|
|
124
|
-
feedbackbasket feedback update <id> --status PLANNED --category BUG --sentiment NEGATIVE
|
|
125
|
-
feedbackbasket feedback note <id> "Investigating — appears related to auth flow"
|
|
126
|
-
feedbackbasket feedback
|
|
127
|
-
feedbackbasket feedback
|
|
136
|
+
feedbackbasket feedback update <id> --status PLANNED --category BUG --sentiment NEGATIVE
|
|
137
|
+
feedbackbasket feedback note <id> "Investigating — appears related to auth flow"
|
|
138
|
+
feedbackbasket feedback note update <id> <note-id> --content "Updated internal note"
|
|
139
|
+
feedbackbasket feedback note delete <id> <note-id> --yes
|
|
140
|
+
feedbackbasket feedback delete <id> --yes
|
|
141
|
+
feedbackbasket feedback bulk-update --status CLOSED --ids id1,id2,id3 --yes
|
|
128
142
|
|
|
129
143
|
# Reply to submitter by email, widget/in-app thread, or both
|
|
130
|
-
feedbackbasket feedback reply <id> "Thanks for reporting — we pushed a fix!" --delivery email --reply-to support@example.com
|
|
131
|
-
feedbackbasket feedback reply <id> "<content>" --delivery widget
|
|
132
|
-
feedbackbasket feedback reply <id> "<content>" --delivery in-app
|
|
133
|
-
feedbackbasket feedback reply <id> "<content>" --delivery both --reply-to support@example.com
|
|
144
|
+
feedbackbasket feedback reply <id> "Thanks for reporting — we pushed a fix!" --delivery email --reply-to support@example.com --yes
|
|
145
|
+
feedbackbasket feedback reply <id> "<content>" --delivery widget --yes
|
|
146
|
+
feedbackbasket feedback reply <id> "<content>" --delivery in-app --yes
|
|
147
|
+
feedbackbasket feedback reply <id> "<content>" --delivery both --reply-to support@example.com --yes
|
|
134
148
|
feedbackbasket feedback replies <id> # show the complete conversation
|
|
135
149
|
|
|
136
150
|
# Export
|
|
@@ -182,7 +196,9 @@ Waitlist mode keeps the same project script and binds to the host app's own anno
|
|
|
182
196
|
</form>
|
|
183
197
|
```
|
|
184
198
|
|
|
185
|
-
Email is required and name is optional.
|
|
199
|
+
The form must be served from the website origin saved on the FeedbackBasket project. Email is required and name is optional. The script binds forms already on the page and forms added later, uses native browser validation, disables submit controls during the request, and keeps the host app's styling.
|
|
200
|
+
|
|
201
|
+
Use `data-feedbackbasket-state="loading|success|error"` for custom UI. The bubbling `feedbackbasket:waitlist:success` event includes `detail.email` and `detail.duplicate`; `feedbackbasket:waitlist:error` includes `detail.message` and `detail.status`. Do not add a competing submit handler. Repeat submissions for the same project and email update the existing signup rather than creating a duplicate.
|
|
186
202
|
|
|
187
203
|
### Waitlist Signups
|
|
188
204
|
|
|
@@ -224,7 +240,7 @@ Use the basic widget experience by default: `displayMode` stays `modal`, and gui
|
|
|
224
240
|
### Team
|
|
225
241
|
```bash
|
|
226
242
|
feedbackbasket team list
|
|
227
|
-
feedbackbasket team role <memberId> --role admin
|
|
243
|
+
feedbackbasket team role <memberId> --role admin --yes
|
|
228
244
|
feedbackbasket team remove <memberId> --yes
|
|
229
245
|
```
|
|
230
246
|
|
|
@@ -316,10 +332,10 @@ feedbackbasket feedback show <id> --agent
|
|
|
316
332
|
```bash
|
|
317
333
|
# Agent reads context, asks which delivery method to use, then sends it
|
|
318
334
|
feedbackbasket feedback show <id> --agent # read email, replyChannel, project.replyToEmail
|
|
319
|
-
feedbackbasket feedback reply <id> "<drafted response>" --delivery widget --agent
|
|
320
|
-
feedbackbasket feedback reply <id> "<drafted response>" --delivery in-app --agent
|
|
321
|
-
feedbackbasket feedback reply <id> "<drafted response>" --delivery email --reply-to support@example.com --agent
|
|
322
|
-
feedbackbasket feedback reply <id> "<drafted response>" --delivery both --reply-to support@example.com --agent
|
|
335
|
+
feedbackbasket feedback reply <id> "<drafted response>" --delivery widget --yes --agent
|
|
336
|
+
feedbackbasket feedback reply <id> "<drafted response>" --delivery in-app --yes --agent
|
|
337
|
+
feedbackbasket feedback reply <id> "<drafted response>" --delivery email --reply-to support@example.com --yes --agent
|
|
338
|
+
feedbackbasket feedback reply <id> "<drafted response>" --delivery both --reply-to support@example.com --yes --agent
|
|
323
339
|
feedbackbasket feedback update <id> --status COMPLETE --agent
|
|
324
340
|
feedbackbasket feedback note <id> "Replied via CLI" --agent
|
|
325
341
|
```
|
|
@@ -381,10 +397,10 @@ Errors include hints:
|
|
|
381
397
|
## Invariants
|
|
382
398
|
|
|
383
399
|
- Always authenticate before data commands
|
|
384
|
-
- `--agent`
|
|
400
|
+
- `--agent` suppresses interactive prompts. High-impact operations still need `--yes`.
|
|
385
401
|
- Default project (set during login) is used when `--project` is not specified
|
|
386
402
|
- Project names resolve case-insensitively with fuzzy matching
|
|
387
403
|
- Write operations use full scope (granted by default during login)
|
|
388
404
|
- Feedback IDs are stable CUIDs — safe to reference across commands
|
|
389
405
|
- All timestamps are ISO 8601
|
|
390
|
-
- `--yes`
|
|
406
|
+
- `--yes` confirms all high-impact CLI operations in agent or machine mode
|