feedbackbasket-cli 0.7.0 → 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 +4 -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 +2 -0
- package/dist/src/help.js +1 -0
- package/dist/src/types.d.ts +15 -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 +14 -0
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
|
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));
|
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
|
@@ -126,6 +126,21 @@ export interface FeedbackResponse {
|
|
|
126
126
|
feedback: Feedback[];
|
|
127
127
|
pagination: Pagination;
|
|
128
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
|
+
}
|
|
129
144
|
export interface BugReportsResponse {
|
|
130
145
|
bugReports: BugReport[];
|
|
131
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
|
|
@@ -143,6 +145,18 @@ feedbackbasket feedback update <id> --status UNDER_REVIEW --agent
|
|
|
143
145
|
feedbackbasket feedback note <id> "Reviewing — appears related to auth flow" --agent
|
|
144
146
|
```
|
|
145
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
|
+
|
|
146
160
|
### Investigate high-priority bugs
|
|
147
161
|
```bash
|
|
148
162
|
feedbackbasket bugs list --severity high --agent
|