feedbackbasket-cli 0.6.1 → 0.8.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/README.md +7 -0
- package/dist/src/client.d.ts +2 -1
- package/dist/src/client.js +3 -0
- package/dist/src/commands/feedback-create.d.ts +3 -0
- package/dist/src/commands/feedback-create.js +120 -0
- package/dist/src/commands/feedback.js +13 -0
- package/dist/src/commands/widget.js +11 -0
- package/dist/src/help.js +1 -0
- package/dist/src/types.d.ts +18 -0
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
- package/skills/feedbackbasket/SKILL.md +18 -1
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ feedbackbasket login --manual
|
|
|
22
22
|
# Start exploring
|
|
23
23
|
feedbackbasket projects list
|
|
24
24
|
feedbackbasket feedback list
|
|
25
|
+
feedbackbasket feedback create "Login button is broken" --project myapp --type bug
|
|
25
26
|
feedbackbasket bugs list --severity high
|
|
26
27
|
```
|
|
27
28
|
|
|
@@ -35,6 +36,7 @@ Any AI agent with shell access (Claude Code, Codex, Cursor, OpenCode) can use th
|
|
|
35
36
|
# Agents should use --agent flag for raw JSON output
|
|
36
37
|
feedbackbasket projects list --agent
|
|
37
38
|
feedbackbasket feedback list --category BUG --agent
|
|
39
|
+
feedbackbasket feedback create "Login button is broken" --content "Clicking Log in does nothing in Safari." --project myapp --type bug --agent
|
|
38
40
|
feedbackbasket feedback update <id> --status PLANNED --agent
|
|
39
41
|
feedbackbasket widget script myproject --agent
|
|
40
42
|
```
|
|
@@ -87,6 +89,8 @@ feedbackbasket feedback show <id> # View detail, includ
|
|
|
87
89
|
feedbackbasket feedback search "crash on mobile" # Search shortcut
|
|
88
90
|
|
|
89
91
|
# Write
|
|
92
|
+
feedbackbasket feedback create "Title" --content "Body" --project myapp
|
|
93
|
+
feedbackbasket feedback create "Login bug" --content "Clicking Log in does nothing" --project myapp --type bug --page-url https://example.com/login
|
|
90
94
|
feedbackbasket feedback update <id> --status PLANNED # Update status
|
|
91
95
|
feedbackbasket feedback update <id> --category BUG # Update category
|
|
92
96
|
feedbackbasket feedback reply <id> "Thanks for reporting!" # Email the submitter
|
|
@@ -123,6 +127,7 @@ feedbackbasket widget settings myapp --position bottom-left --display modal
|
|
|
123
127
|
feedbackbasket widget settings myapp --email-required --intro "How can we improve?"
|
|
124
128
|
feedbackbasket widget settings myapp --button-radius 10 --button-size regular
|
|
125
129
|
feedbackbasket widget settings myapp --show-email --allow-attachments --guided
|
|
130
|
+
feedbackbasket widget settings myapp --email-read-only --hide-email-when-prefilled
|
|
126
131
|
|
|
127
132
|
# Configure guided feedback types and follow-up questions
|
|
128
133
|
feedbackbasket widget flow myapp
|
|
@@ -134,6 +139,8 @@ feedbackbasket widget flow myapp --config ./feedback-flow.json
|
|
|
134
139
|
feedbackbasket widget script myapp
|
|
135
140
|
```
|
|
136
141
|
|
|
142
|
+
Use `--email-read-only` and `--hide-email-when-prefilled` with runtime `userEmail` values from your app. These settings do not store visitor emails in FeedbackBasket widget settings.
|
|
143
|
+
|
|
137
144
|
`widget flow --config` accepts either a `feedbackFlow` object or a JSON object with a `feedbackFlow` key. V1 supports guided mode with `text`, `textarea`, and `single_choice` follow-up questions.
|
|
138
145
|
|
|
139
146
|
```json
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProjectsResponse, FeedbackResponse, BugReportsResponse, FeedbackParams, BugReportParams, UserProfile, Project, Feedback, WidgetSettings } from './types.js';
|
|
1
|
+
import type { ProjectsResponse, FeedbackResponse, BugReportsResponse, FeedbackParams, FeedbackCreateInput, FeedbackCreateResponse, BugReportParams, UserProfile, Project, Feedback, WidgetSettings } from './types.js';
|
|
2
2
|
export declare class FeedbackBasketClient {
|
|
3
3
|
private http;
|
|
4
4
|
constructor(token: string, baseUrl: string);
|
|
@@ -34,6 +34,7 @@ export declare class FeedbackBasketClient {
|
|
|
34
34
|
category?: string;
|
|
35
35
|
limit?: number;
|
|
36
36
|
}): Promise<FeedbackResponse>;
|
|
37
|
+
createFeedback(data: FeedbackCreateInput): Promise<FeedbackCreateResponse>;
|
|
37
38
|
getWidgetSettings(projectId: string): Promise<{
|
|
38
39
|
projectId: string;
|
|
39
40
|
projectName: string;
|
package/dist/src/client.js
CHANGED
|
@@ -50,6 +50,9 @@ export class FeedbackBasketClient {
|
|
|
50
50
|
async searchFeedback(query, opts = {}) {
|
|
51
51
|
return this.getFeedback({ search: query, ...opts });
|
|
52
52
|
}
|
|
53
|
+
async createFeedback(data) {
|
|
54
|
+
return this.request('POST', '/feedback', data);
|
|
55
|
+
}
|
|
53
56
|
// Widget
|
|
54
57
|
async getWidgetSettings(projectId) {
|
|
55
58
|
return this.request('GET', `/projects/${encodeURIComponent(projectId)}/widget`);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { FeedbackBasketClient } from '../client.js';
|
|
3
|
+
import { AuthManager } from '../auth/manager.js';
|
|
4
|
+
import { loadConfig } from '../config/config.js';
|
|
5
|
+
import { errAuth, errUsage } from '../output/errors.js';
|
|
6
|
+
import { brand } from '../output/theme.js';
|
|
7
|
+
import { resolveProject } from '../resolve.js';
|
|
8
|
+
const validTypes = new Set(['bug', 'feature', 'general']);
|
|
9
|
+
const validCategories = new Set(['BUG', 'FEATURE_REQUEST', 'IMPROVEMENT', 'QUESTION']);
|
|
10
|
+
const validStatuses = new Set(['OPEN', 'UNDER_REVIEW', 'PLANNED', 'IN_PROGRESS', 'COMPLETE', 'CLOSED']);
|
|
11
|
+
export function createFeedbackCreateCommand(getWriter) {
|
|
12
|
+
return new Command('create')
|
|
13
|
+
.argument('<title>', 'Short title or summary for the feedback')
|
|
14
|
+
.description('Create a new feedback item')
|
|
15
|
+
.requiredOption('--project <id-or-name>', 'Project ID or name')
|
|
16
|
+
.option('--content <body>', 'Longer feedback body')
|
|
17
|
+
.option('--type <type>', 'Feedback type (bug, feature, general)')
|
|
18
|
+
.option('--category <category>', 'Category (BUG, FEATURE_REQUEST, IMPROVEMENT, QUESTION)')
|
|
19
|
+
.option('--status <status>', 'Initial status (OPEN, UNDER_REVIEW, PLANNED, IN_PROGRESS, COMPLETE, CLOSED)')
|
|
20
|
+
.option('--email <email>', 'Submitter email')
|
|
21
|
+
.option('--page-url <url>', 'Page URL where the feedback applies')
|
|
22
|
+
.option('--metadata <key=value>', 'Metadata key/value pair (repeatable)', collectMetadata, [])
|
|
23
|
+
.action(async (title, opts) => {
|
|
24
|
+
const writer = getWriter();
|
|
25
|
+
const client = requireClient();
|
|
26
|
+
if (opts.type && !validTypes.has(opts.type)) {
|
|
27
|
+
throw errUsage('Invalid type. Must be one of: bug, feature, general', 'Example: feedbackbasket feedback create "Login is broken" --project myapp --type bug');
|
|
28
|
+
}
|
|
29
|
+
if (opts.category && !validCategories.has(opts.category)) {
|
|
30
|
+
throw errUsage('Invalid category. Must be one of: BUG, FEATURE_REQUEST, IMPROVEMENT, QUESTION');
|
|
31
|
+
}
|
|
32
|
+
if (opts.status && !validStatuses.has(opts.status)) {
|
|
33
|
+
throw errUsage('Invalid status. Must be one of: OPEN, UNDER_REVIEW, PLANNED, IN_PROGRESS, COMPLETE, CLOSED');
|
|
34
|
+
}
|
|
35
|
+
const project = await resolveProject(client, opts.project);
|
|
36
|
+
const content = composeContent(title, opts.content);
|
|
37
|
+
const metadata = parseMetadata(opts.metadata ?? []);
|
|
38
|
+
const result = await client.createFeedback({
|
|
39
|
+
projectId: project.id,
|
|
40
|
+
content,
|
|
41
|
+
type: opts.type,
|
|
42
|
+
category: opts.category,
|
|
43
|
+
status: opts.status,
|
|
44
|
+
email: opts.email,
|
|
45
|
+
pageUrl: opts.pageUrl,
|
|
46
|
+
metadata,
|
|
47
|
+
});
|
|
48
|
+
if (!writer.isMachineOutput()) {
|
|
49
|
+
console.log(` ${brand.success('[OK]')} Feedback created: ${brand.bold(result.id)}`);
|
|
50
|
+
console.log(` ${brand.muted('Project:')} ${project.name}`);
|
|
51
|
+
console.log(` ${brand.muted('URL:')} ${result.url}`);
|
|
52
|
+
console.log();
|
|
53
|
+
}
|
|
54
|
+
writer.ok(result, {
|
|
55
|
+
summary: `Created feedback ${result.id}`,
|
|
56
|
+
breadcrumbs: [
|
|
57
|
+
{ action: 'View feedback', cmd: `feedbackbasket feedback show ${result.id}` },
|
|
58
|
+
{ action: 'Update status', cmd: `feedbackbasket feedback update ${result.id} --status UNDER_REVIEW` },
|
|
59
|
+
{ action: 'List project feedback', cmd: `feedbackbasket feedback list --project ${project.id}` },
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function requireClient() {
|
|
65
|
+
const manager = new AuthManager();
|
|
66
|
+
const token = manager.resolveToken();
|
|
67
|
+
if (!token)
|
|
68
|
+
throw errAuth();
|
|
69
|
+
const config = loadConfig();
|
|
70
|
+
return new FeedbackBasketClient(token, config.baseUrl);
|
|
71
|
+
}
|
|
72
|
+
function composeContent(title, body) {
|
|
73
|
+
const cleanTitle = title.trim();
|
|
74
|
+
const cleanBody = body?.trim();
|
|
75
|
+
const content = cleanBody ? `${cleanTitle}\n\n${cleanBody}` : cleanTitle;
|
|
76
|
+
if (!content) {
|
|
77
|
+
throw errUsage('Feedback title is required');
|
|
78
|
+
}
|
|
79
|
+
if (content.length > 2000) {
|
|
80
|
+
throw errUsage('Feedback content must be 2000 characters or less');
|
|
81
|
+
}
|
|
82
|
+
return content;
|
|
83
|
+
}
|
|
84
|
+
function collectMetadata(value, previous) {
|
|
85
|
+
return previous.concat(value);
|
|
86
|
+
}
|
|
87
|
+
function parseMetadata(entries) {
|
|
88
|
+
if (entries.length === 0)
|
|
89
|
+
return undefined;
|
|
90
|
+
const metadata = {};
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const separator = entry.indexOf('=');
|
|
93
|
+
if (separator <= 0) {
|
|
94
|
+
throw errUsage(`Invalid metadata "${entry}"`, 'Use --metadata key=value, for example --metadata source=codex');
|
|
95
|
+
}
|
|
96
|
+
const key = entry.slice(0, separator).trim();
|
|
97
|
+
const rawValue = entry.slice(separator + 1).trim();
|
|
98
|
+
if (!key) {
|
|
99
|
+
throw errUsage('Metadata keys cannot be empty');
|
|
100
|
+
}
|
|
101
|
+
metadata[key] = parseMetadataValue(rawValue);
|
|
102
|
+
}
|
|
103
|
+
return metadata;
|
|
104
|
+
}
|
|
105
|
+
function parseMetadataValue(value) {
|
|
106
|
+
if (value === 'true')
|
|
107
|
+
return true;
|
|
108
|
+
if (value === 'false')
|
|
109
|
+
return false;
|
|
110
|
+
if (value === 'null')
|
|
111
|
+
return null;
|
|
112
|
+
if (value !== '' && Number.isFinite(Number(value)))
|
|
113
|
+
return Number(value);
|
|
114
|
+
try {
|
|
115
|
+
return JSON.parse(value);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -17,6 +17,7 @@ async function resolveProjectId(client, optProject, all) {
|
|
|
17
17
|
}
|
|
18
18
|
import { createFeedbackUpdateCommand } from './feedback-update.js';
|
|
19
19
|
import { createFeedbackNoteCommand } from './feedback-note.js';
|
|
20
|
+
import { createFeedbackCreateCommand } from './feedback-create.js';
|
|
20
21
|
import { createFeedbackDeleteCommand } from './feedback-delete.js';
|
|
21
22
|
import { createFeedbackBulkUpdateCommand } from './feedback-bulk-update.js';
|
|
22
23
|
import { createFeedbackExportCommand } from './feedback-export.js';
|
|
@@ -25,6 +26,7 @@ export function createFeedbackCommand(getWriter) {
|
|
|
25
26
|
const feedback = new Command('feedback')
|
|
26
27
|
.description('View and manage feedback');
|
|
27
28
|
// Write subcommands
|
|
29
|
+
feedback.addCommand(createFeedbackCreateCommand(getWriter));
|
|
28
30
|
feedback.addCommand(createFeedbackUpdateCommand(getWriter));
|
|
29
31
|
feedback.addCommand(createFeedbackNoteCommand(getWriter));
|
|
30
32
|
feedback.addCommand(createFeedbackReplyCommand(getWriter));
|
|
@@ -213,6 +215,11 @@ function renderFeedbackDetail(item) {
|
|
|
213
215
|
console.log(` ${attachment.url}`);
|
|
214
216
|
}
|
|
215
217
|
}
|
|
218
|
+
if (item.metadata && Object.keys(item.metadata).length > 0) {
|
|
219
|
+
console.log();
|
|
220
|
+
console.log(brand.bold('Metadata:'));
|
|
221
|
+
console.log(indentBlock(JSON.stringify(item.metadata, null, 2), ' '));
|
|
222
|
+
}
|
|
216
223
|
if (item.aiSummary) {
|
|
217
224
|
console.log();
|
|
218
225
|
console.log(brand.bold('AI Summary:'));
|
|
@@ -240,6 +247,12 @@ function formatFeedbackType(item) {
|
|
|
240
247
|
return undefined;
|
|
241
248
|
return item.feedbackType.emoji ? `${item.feedbackType.emoji} ${label}` : label;
|
|
242
249
|
}
|
|
250
|
+
function indentBlock(value, indent) {
|
|
251
|
+
return value
|
|
252
|
+
.split('\n')
|
|
253
|
+
.map((line) => `${indent}${line}`)
|
|
254
|
+
.join('\n');
|
|
255
|
+
}
|
|
243
256
|
function formatBytes(bytes) {
|
|
244
257
|
if (!Number.isFinite(bytes) || bytes < 0)
|
|
245
258
|
return '';
|
|
@@ -65,6 +65,10 @@ export function createWidgetCommand(getWriter) {
|
|
|
65
65
|
.option('--no-email-required', 'Make email optional')
|
|
66
66
|
.option('--show-email', 'Show the email field')
|
|
67
67
|
.option('--no-show-email', 'Hide the email field')
|
|
68
|
+
.option('--email-read-only', 'Lock the email field when userEmail is prefilled')
|
|
69
|
+
.option('--no-email-read-only', 'Allow editing prefilled email')
|
|
70
|
+
.option('--hide-email-when-prefilled', 'Hide the email field when userEmail is prefilled')
|
|
71
|
+
.option('--no-hide-email-when-prefilled', 'Show the email field even when userEmail is prefilled')
|
|
68
72
|
.option('--allow-attachments', 'Allow image attachments')
|
|
69
73
|
.option('--no-allow-attachments', 'Disable image attachments')
|
|
70
74
|
.option('--icon-only', 'Show only the icon, no label')
|
|
@@ -84,6 +88,7 @@ export function createWidgetCommand(getWriter) {
|
|
|
84
88
|
opts.success || opts.trigger || opts.display ||
|
|
85
89
|
opts.buttonRadius || opts.buttonSize || opts.icon ||
|
|
86
90
|
opts.emailRequired !== undefined || opts.showEmail !== undefined ||
|
|
91
|
+
opts.emailReadOnly !== undefined || opts.hideEmailWhenPrefilled !== undefined ||
|
|
87
92
|
opts.allowAttachments !== undefined || opts.iconOnly !== undefined ||
|
|
88
93
|
opts.showIcon !== undefined || opts.showBranding !== undefined ||
|
|
89
94
|
opts.zIndex || opts.guided || opts.disableGuided;
|
|
@@ -117,6 +122,10 @@ export function createWidgetCommand(getWriter) {
|
|
|
117
122
|
settings.emailRequired = opts.emailRequired;
|
|
118
123
|
if (opts.showEmail !== undefined)
|
|
119
124
|
settings.showEmailField = opts.showEmail;
|
|
125
|
+
if (opts.emailReadOnly !== undefined)
|
|
126
|
+
settings.emailReadOnly = opts.emailReadOnly;
|
|
127
|
+
if (opts.hideEmailWhenPrefilled !== undefined)
|
|
128
|
+
settings.hideEmailFieldWhenPrefilled = opts.hideEmailWhenPrefilled;
|
|
120
129
|
if (opts.allowAttachments !== undefined)
|
|
121
130
|
settings.allowAttachments = opts.allowAttachments;
|
|
122
131
|
if (opts.iconOnly !== undefined)
|
|
@@ -349,6 +358,8 @@ function renderWidgetSettings(projectName, settings) {
|
|
|
349
358
|
['Display Mode', String(settings.displayMode ?? '')],
|
|
350
359
|
['Show Email', String(settings.showEmailField ?? true)],
|
|
351
360
|
['Email Required', String(settings.emailRequired ?? false)],
|
|
361
|
+
['Email Read Only', String(settings.emailReadOnly ?? false)],
|
|
362
|
+
['Hide Prefilled Email', String(settings.hideEmailFieldWhenPrefilled ?? false)],
|
|
352
363
|
['Attachments', String(settings.allowAttachments ?? true)],
|
|
353
364
|
['Guided Flow', String(settings.feedbackFlow?.enabled ?? false)],
|
|
354
365
|
['Intro Message', String(settings.introMessage ?? '')],
|
package/dist/src/help.js
CHANGED
|
@@ -57,6 +57,7 @@ export function renderRootHelp() {
|
|
|
57
57
|
// Examples
|
|
58
58
|
lines.push(section(' EXAMPLES'));
|
|
59
59
|
lines.push(`${INDENT}${brand.muted('$')} feedbackbasket projects list`);
|
|
60
|
+
lines.push(`${INDENT}${brand.muted('$')} feedbackbasket feedback create "Login bug" --project myapp --type bug`);
|
|
60
61
|
lines.push(`${INDENT}${brand.muted('$')} feedbackbasket feedback list --category BUG --status OPEN`);
|
|
61
62
|
lines.push(`${INDENT}${brand.muted('$')} feedbackbasket bugs list --severity high`);
|
|
62
63
|
lines.push(`${INDENT}${brand.muted('$')} feedbackbasket widget script myapp`);
|
package/dist/src/types.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface WidgetSettings {
|
|
|
37
37
|
position?: string;
|
|
38
38
|
showEmailField?: boolean;
|
|
39
39
|
emailRequired?: boolean;
|
|
40
|
+
emailReadOnly?: boolean;
|
|
41
|
+
hideEmailFieldWhenPrefilled?: boolean;
|
|
40
42
|
allowAttachments?: boolean;
|
|
41
43
|
displayMode?: 'modal' | 'popup';
|
|
42
44
|
zIndex?: number;
|
|
@@ -76,6 +78,7 @@ export interface Feedback {
|
|
|
76
78
|
type: FeedbackFlowQuestionType;
|
|
77
79
|
value: string;
|
|
78
80
|
}> | null;
|
|
81
|
+
metadata?: Record<string, unknown> | null;
|
|
79
82
|
pageUrl?: string | null;
|
|
80
83
|
browser?: string | null;
|
|
81
84
|
os?: string | null;
|
|
@@ -123,6 +126,21 @@ export interface FeedbackResponse {
|
|
|
123
126
|
feedback: Feedback[];
|
|
124
127
|
pagination: Pagination;
|
|
125
128
|
}
|
|
129
|
+
export interface FeedbackCreateInput {
|
|
130
|
+
projectId: string;
|
|
131
|
+
content: string;
|
|
132
|
+
type?: 'bug' | 'feature' | 'general';
|
|
133
|
+
category?: FeedbackCategory;
|
|
134
|
+
status?: FeedbackStatus;
|
|
135
|
+
email?: string;
|
|
136
|
+
pageUrl?: string;
|
|
137
|
+
metadata?: Record<string, unknown>;
|
|
138
|
+
}
|
|
139
|
+
export interface FeedbackCreateResponse {
|
|
140
|
+
id: string;
|
|
141
|
+
url: string;
|
|
142
|
+
feedback: Feedback;
|
|
143
|
+
}
|
|
126
144
|
export interface BugReportsResponse {
|
|
127
145
|
bugReports: BugReport[];
|
|
128
146
|
stats: {
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
2
|
-
export declare const USER_AGENT = "FeedbackBasket-CLI/0.
|
|
1
|
+
export declare const VERSION = "0.8.0";
|
|
2
|
+
export declare const USER_AGENT = "FeedbackBasket-CLI/0.8.0";
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.8.0';
|
|
2
2
|
export const USER_AGENT = `FeedbackBasket-CLI/${VERSION}`;
|
package/package.json
CHANGED
|
@@ -62,6 +62,8 @@ feedbackbasket feedback show <id>
|
|
|
62
62
|
feedbackbasket feedback search "crash on mobile" --project <id> --limit 10
|
|
63
63
|
|
|
64
64
|
# Write
|
|
65
|
+
feedbackbasket feedback create "Login button is broken" --content "Clicking Log in does nothing in Safari." --project <id> --type bug
|
|
66
|
+
feedbackbasket feedback create "Feature idea" --content "Let users export saved views." --project <id> --type feature --metadata source=agent
|
|
65
67
|
feedbackbasket feedback update <id> --status PLANNED --category BUG --sentiment NEGATIVE
|
|
66
68
|
feedbackbasket feedback note <id> "Investigating — appears related to auth flow"
|
|
67
69
|
feedbackbasket feedback delete <id> --yes
|
|
@@ -97,6 +99,7 @@ feedbackbasket widget settings <project> --color "#22c55e" --label "Send Feedbac
|
|
|
97
99
|
feedbackbasket widget settings <project> --position bottom-left --display modal
|
|
98
100
|
feedbackbasket widget settings <project> --email-required --intro "How can we improve?"
|
|
99
101
|
feedbackbasket widget settings <project> --show-email --allow-attachments --guided
|
|
102
|
+
feedbackbasket widget settings <project> --email-read-only --hide-email-when-prefilled
|
|
100
103
|
|
|
101
104
|
# Guided feedback types and follow-up questions
|
|
102
105
|
feedbackbasket widget flow <project>
|
|
@@ -105,6 +108,8 @@ feedbackbasket widget flow <project> --reset-default --enable
|
|
|
105
108
|
feedbackbasket widget flow <project> --config ./feedback-flow.json
|
|
106
109
|
```
|
|
107
110
|
|
|
111
|
+
`email-read-only` and `hide-email-when-prefilled` control behavior only when the host app passes a runtime `userEmail` value. Do not store visitor emails in widget settings.
|
|
112
|
+
|
|
108
113
|
`widget flow --config` accepts either a `feedbackFlow` object or a JSON object with a `feedbackFlow` key. Use it when an agent needs to customize visitor choices such as Bug report, Feature request, and General feedback. Supported v1 question types are `text`, `textarea`, and `single_choice`.
|
|
109
114
|
|
|
110
115
|
### Team
|
|
@@ -140,11 +145,23 @@ feedbackbasket feedback update <id> --status UNDER_REVIEW --agent
|
|
|
140
145
|
feedbackbasket feedback note <id> "Reviewing — appears related to auth flow" --agent
|
|
141
146
|
```
|
|
142
147
|
|
|
148
|
+
### Capture new feedback without leaving the terminal
|
|
149
|
+
```bash
|
|
150
|
+
feedbackbasket feedback create "Login button is broken" \
|
|
151
|
+
--content "Clicking Log in does nothing in Safari." \
|
|
152
|
+
--project myapp \
|
|
153
|
+
--type bug \
|
|
154
|
+
--page-url https://example.com/login \
|
|
155
|
+
--metadata source=agent \
|
|
156
|
+
--agent
|
|
157
|
+
```
|
|
158
|
+
Agent mode returns the created feedback ID, dashboard URL, and feedback object. Created feedback is analyzed by AI and follows the project's notification settings.
|
|
159
|
+
|
|
143
160
|
### Investigate high-priority bugs
|
|
144
161
|
```bash
|
|
145
162
|
feedbackbasket bugs list --severity high --agent
|
|
146
163
|
feedbackbasket feedback show <id> --agent
|
|
147
|
-
# Response includes browser, OS, page URL, submitted feedback type, follow-up answers, attachment URLs, AI analysis, priority score
|
|
164
|
+
# Response includes browser, OS, page URL, submitted feedback type, follow-up answers, attachment URLs, metadata, AI analysis, priority score
|
|
148
165
|
```
|
|
149
166
|
|
|
150
167
|
### Close the loop — reply to the submitter
|