@nikitadmitrieff/feedback-chat 0.1.3 → 0.2.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.
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/deploy-agent.ts
4
+ import prompts from "prompts";
5
+ import { existsSync, readFileSync } from "fs";
6
+ import { join, resolve } from "path";
7
+ import { execSync } from "child_process";
8
+ function checkCommand(cmd) {
9
+ try {
10
+ execSync(`which ${cmd}`, { stdio: "ignore" });
11
+ return true;
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
16
+ function readEnvFile(cwd) {
17
+ const envPath = join(cwd, ".env.local");
18
+ if (!existsSync(envPath)) return {};
19
+ const content = readFileSync(envPath, "utf-8");
20
+ const vars = {};
21
+ for (const line of content.split("\n")) {
22
+ const match = line.match(/^([A-Z_]+)=(.+)$/);
23
+ if (match) vars[match[1]] = match[2];
24
+ }
25
+ return vars;
26
+ }
27
+ async function main() {
28
+ const cwd = resolve(process.cwd());
29
+ console.error();
30
+ console.error(" feedback-chat agent deployment script generator");
31
+ console.error(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
32
+ console.error();
33
+ const hasRailway = checkCommand("railway");
34
+ const hasGh = checkCommand("gh");
35
+ if (!hasRailway) {
36
+ console.error(" \u2717 Railway CLI not found. Install: npm install -g @railway/cli");
37
+ process.exit(1);
38
+ }
39
+ if (!hasGh) {
40
+ console.error(" \u2717 GitHub CLI not found. Install: https://cli.github.com/");
41
+ process.exit(1);
42
+ }
43
+ const envVars = readEnvFile(cwd);
44
+ const githubToken = envVars["GITHUB_TOKEN"] || "";
45
+ const githubRepo = envVars["GITHUB_REPO"] || "";
46
+ const anthropicKey = envVars["ANTHROPIC_API_KEY"] || "";
47
+ if (!githubToken || !githubRepo) {
48
+ console.error(" \u2717 GITHUB_TOKEN and GITHUB_REPO must be set in .env.local");
49
+ console.error(" Run `npx feedback-chat init` first with the +GitHub or +Pipeline tier.");
50
+ process.exit(1);
51
+ }
52
+ const { authMethod } = await prompts({
53
+ type: "select",
54
+ name: "authMethod",
55
+ message: "Claude authentication for the agent",
56
+ choices: [
57
+ {
58
+ title: "Claude Max subscription ($0/run)",
59
+ description: "Uses OAuth credentials from your local keychain",
60
+ value: "max"
61
+ },
62
+ {
63
+ title: "API key (pay per token)",
64
+ description: "Uses ANTHROPIC_API_KEY from .env.local",
65
+ value: "api"
66
+ }
67
+ ]
68
+ });
69
+ if (!authMethod) {
70
+ console.error(" Cancelled.");
71
+ process.exit(0);
72
+ }
73
+ let credentialsJson = "";
74
+ if (authMethod === "max") {
75
+ console.error();
76
+ console.error(" To get your Claude credentials, run:");
77
+ console.error(' security find-generic-password -s "Claude Code-credentials" -a "$USER" -w');
78
+ console.error();
79
+ console.error(" Copy the JSON output (the claudeAiOauth portion).");
80
+ console.error();
81
+ const { creds } = await prompts({
82
+ type: "text",
83
+ name: "creds",
84
+ message: "Paste your Claude credentials JSON (or press Enter to include a placeholder)"
85
+ });
86
+ credentialsJson = creds || "${CLAUDE_CREDENTIALS_JSON}";
87
+ }
88
+ const webhookSecret = "$(openssl rand -hex 32)";
89
+ const envLocalPath = join(cwd, ".env.local");
90
+ const authLine = authMethod === "max" ? `
91
+ CLAUDE_CREDENTIALS_JSON='${credentialsJson.replace(/'/g, "'\\''")}'` : anthropicKey ? `
92
+ ANTHROPIC_API_KEY="${anthropicKey}"` : "";
93
+ const script = `#!/usr/bin/env bash
94
+ set -euo pipefail
95
+
96
+ # \u2500\u2500 feedback-chat agent deployment script \u2500\u2500
97
+ # Generated by: npx feedback-chat deploy-agent
98
+ # Review this script before running it.
99
+
100
+ echo "==> Cloning feedback-chat agent..."
101
+ TMPDIR=$(mktemp -d)
102
+ trap 'rm -rf "$TMPDIR"' EXIT
103
+ git clone --depth 1 https://github.com/NikitaDmitrieff/feedback-chat "$TMPDIR/feedback-chat"
104
+ cd "$TMPDIR/feedback-chat/packages/agent"
105
+
106
+ echo "==> Creating Railway project..."
107
+ railway init
108
+
109
+ echo "==> First deploy (creates the service)..."
110
+ DEPLOY_OUTPUT=$(railway up --detach 2>&1)
111
+ echo "$DEPLOY_OUTPUT"
112
+
113
+ echo "==> Waiting for service to register..."
114
+ sleep 5
115
+
116
+ echo "==> Finding and linking service..."
117
+ SERVICE_NAME=$(railway service status --all 2>&1 | grep -oE '^[a-z][-a-z0-9]*' | head -1)
118
+ if [ -z "$SERVICE_NAME" ]; then
119
+ echo "\u2717 Could not detect service name. Run 'railway service status --all' manually."
120
+ exit 1
121
+ fi
122
+ echo " Linking service: $SERVICE_NAME"
123
+ railway service link "$SERVICE_NAME"
124
+
125
+ echo "==> Setting environment variables..."
126
+ WEBHOOK_SECRET=${webhookSecret}
127
+ railway variables set \\
128
+ GITHUB_TOKEN="${githubToken}" \\
129
+ GITHUB_REPO="${githubRepo}" \\
130
+ WEBHOOK_SECRET="$WEBHOOK_SECRET"${authLine ? ` \\${authLine}` : ""}
131
+
132
+ echo "==> Getting public domain..."
133
+ DOMAIN_OUTPUT=$(railway domain 2>&1)
134
+ AGENT_URL=$(echo "$DOMAIN_OUTPUT" | grep -oE 'https://[^ ]+')
135
+ if [ -z "$AGENT_URL" ]; then
136
+ echo "\u2717 Could not extract domain URL. Output was:"
137
+ echo "$DOMAIN_OUTPUT"
138
+ exit 1
139
+ fi
140
+ echo " Agent URL: $AGENT_URL"
141
+
142
+ echo "==> Setting up GitHub webhook..."
143
+ REPO_OWNER=$(echo "${githubRepo}" | cut -d/ -f1)
144
+ REPO_NAME=$(echo "${githubRepo}" | cut -d/ -f2)
145
+ gh api "repos/$REPO_OWNER/$REPO_NAME/hooks" \\
146
+ -f name=web -f active=true \\
147
+ -f "config[url]=$AGENT_URL/webhook/github" \\
148
+ -f "config[content_type]=json" \\
149
+ -f "config[secret]=$WEBHOOK_SECRET" \\
150
+ -f 'events[]=issues'
151
+
152
+ echo "==> Updating consumer .env.local..."
153
+ echo "AGENT_URL=$AGENT_URL" >> "${envLocalPath}"
154
+
155
+ echo ""
156
+ echo "==> Done! Summary:"
157
+ echo " Agent URL: $AGENT_URL"
158
+ echo " Webhook: $AGENT_URL/webhook/github"
159
+ echo " Webhook secret: $WEBHOOK_SECRET"
160
+ echo ""
161
+ echo " Next steps:"
162
+ echo " 1. Wait for Railway deploy to finish"
163
+ echo " 2. Verify: curl $AGENT_URL/health"
164
+ echo " 3. Test by submitting feedback through the widget"
165
+ `;
166
+ process.stdout.write(script);
167
+ console.error();
168
+ console.error(" Script generated! To run it:");
169
+ console.error(" npx feedback-chat deploy-agent | bash");
170
+ console.error(" Or save and review first:");
171
+ console.error(" npx feedback-chat deploy-agent > deploy.sh && chmod +x deploy.sh && cat deploy.sh");
172
+ console.error();
173
+ }
174
+ main().catch((err) => {
175
+ console.error(err);
176
+ process.exit(1);
177
+ });
package/dist/cli/init.js CHANGED
@@ -4,27 +4,79 @@
4
4
  import prompts from "prompts";
5
5
  import { existsSync, writeFileSync, appendFileSync, readFileSync, mkdirSync } from "fs";
6
6
  import { join, resolve } from "path";
7
- var CHAT_ROUTE_TEMPLATE = (hasGithub) => `import { createFeedbackHandler } from '@nikitadmitrieff/feedback-chat/server'
7
+ import { execSync } from "child_process";
8
+ var CHAT_ROUTE_TEMPLATE = (tier) => `import { createFeedbackHandler } from '@nikitadmitrieff/feedback-chat/server'
8
9
 
9
10
  const handler = createFeedbackHandler({
10
- password: process.env.FEEDBACK_PASSWORD!,${hasGithub ? `
11
+ password: process.env.FEEDBACK_PASSWORD!,${tier !== "chat" ? `
11
12
  github: {
12
13
  token: process.env.GITHUB_TOKEN!,
13
14
  repo: process.env.GITHUB_REPO!,
14
15
  },` : ""}
16
+ // projectContext: 'Describe your app here so the AI gives better responses',
15
17
  })
16
18
 
17
19
  export const POST = handler.POST
18
20
  `;
19
- var STATUS_ROUTE_TEMPLATE = `import { createStatusHandler } from '@nikitadmitrieff/feedback-chat/server'
21
+ var STATUS_ROUTE_TEMPLATE = (tier) => {
22
+ if (tier === "chat") {
23
+ return `import { createStatusHandler } from '@nikitadmitrieff/feedback-chat/server'
20
24
 
21
25
  const handler = createStatusHandler({
22
26
  password: process.env.FEEDBACK_PASSWORD!,
23
27
  })
24
28
 
25
29
  export const { GET, POST } = handler
30
+ `;
31
+ }
32
+ if (tier === "github") {
33
+ return `import { createStatusHandler } from '@nikitadmitrieff/feedback-chat/server'
34
+
35
+ const handler = createStatusHandler({
36
+ password: process.env.FEEDBACK_PASSWORD!,
37
+ github: {
38
+ token: process.env.GITHUB_TOKEN!,
39
+ repo: process.env.GITHUB_REPO!,
40
+ },
41
+ })
42
+
43
+ export const { GET, POST } = handler
44
+ `;
45
+ }
46
+ return `import { createStatusHandler } from '@nikitadmitrieff/feedback-chat/server'
47
+
48
+ const handler = createStatusHandler({
49
+ password: process.env.FEEDBACK_PASSWORD!,
50
+ github: {
51
+ token: process.env.GITHUB_TOKEN!,
52
+ repo: process.env.GITHUB_REPO!,
53
+ },
54
+ agentUrl: process.env.AGENT_URL,
55
+ })
56
+
57
+ export const { GET, POST } = handler
58
+ `;
59
+ };
60
+ var FEEDBACK_BUTTON_TEMPLATE = `'use client'
61
+
62
+ import { useState } from 'react'
63
+ import { FeedbackPanel } from '@nikitadmitrieff/feedback-chat'
64
+ import '@nikitadmitrieff/feedback-chat/styles.css'
65
+
66
+ export function FeedbackButton() {
67
+ const [open, setOpen] = useState(false)
68
+ return <FeedbackPanel isOpen={open} onToggle={() => setOpen(!open)} />
69
+ }
26
70
  `;
27
71
  var SOURCE_DIRECTIVE = '@source "../node_modules/@nikitadmitrieff/feedback-chat/dist/**/*.js";';
72
+ var GITHUB_LABELS = [
73
+ { name: "feedback-bot", color: "0E8A16", description: "Created by feedback widget" },
74
+ { name: "auto-implement", color: "1D76DB", description: "Agent should implement this" },
75
+ { name: "in-progress", color: "FBCA04", description: "Agent is working on this" },
76
+ { name: "agent-failed", color: "D93F0B", description: "Agent build/lint failed" },
77
+ { name: "preview-pending", color: "C5DEF5", description: "PR ready, preview deploying" },
78
+ { name: "rejected", color: "E4E669", description: "User rejected changes" }
79
+ ];
28
80
  function findAppDir(cwd) {
29
81
  const candidates = [
30
82
  join(cwd, "src", "app"),
@@ -84,12 +136,65 @@ function appendEnvVar(envPath, key, value) {
84
136
  appendFileSync(envPath, `${key}=${value}
85
137
  `);
86
138
  }
139
+ function checkReactVersion(cwd) {
140
+ const reactPkgPath = join(cwd, "node_modules", "react", "package.json");
141
+ if (!existsSync(reactPkgPath)) return;
142
+ try {
143
+ const pkg = JSON.parse(readFileSync(reactPkgPath, "utf-8"));
144
+ const version = pkg.version;
145
+ if (version === "19.1.0" || version === "19.1.1") {
146
+ console.error(` \u2717 react@${version} detected \u2014 @ai-sdk/react excludes this version.`);
147
+ console.error(" Fix: npm install react@latest react-dom@latest");
148
+ console.error();
149
+ process.exit(1);
150
+ }
151
+ } catch {
152
+ }
153
+ }
154
+ function hasGhCli() {
155
+ try {
156
+ execSync("which gh", { stdio: "ignore" });
157
+ return true;
158
+ } catch {
159
+ return false;
160
+ }
161
+ }
162
+ function createGitHubLabels(cwd) {
163
+ if (!hasGhCli()) {
164
+ console.log(" \u26A0 GitHub CLI (gh) not found. Create these labels manually:");
165
+ console.log();
166
+ for (const label of GITHUB_LABELS) {
167
+ console.log(` gh label create ${label.name} --color ${label.color} --description "${label.description}" --force`);
168
+ }
169
+ console.log();
170
+ return;
171
+ }
172
+ console.log(" Creating GitHub labels...");
173
+ for (const label of GITHUB_LABELS) {
174
+ try {
175
+ execSync(
176
+ `gh label create ${label.name} --color ${label.color} --description "${label.description}" --force`,
177
+ { cwd, stdio: "ignore" }
178
+ );
179
+ console.log(` Created label: ${label.name}`);
180
+ } catch {
181
+ console.log(` \u26A0 Could not create label: ${label.name}`);
182
+ }
183
+ }
184
+ }
185
+ function detectComponentsDir(cwd) {
186
+ if (existsSync(join(cwd, "src", "app"))) {
187
+ return join(cwd, "src", "components");
188
+ }
189
+ return join(cwd, "components");
190
+ }
87
191
  async function main() {
88
192
  const cwd = resolve(process.cwd());
89
193
  console.log();
90
194
  console.log(" feedback-chat setup wizard");
91
195
  console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
92
196
  console.log();
197
+ checkReactVersion(cwd);
93
198
  const appDir = findAppDir(cwd);
94
199
  if (!appDir) {
95
200
  console.error(" Could not find app/ or src/app/ directory.");
@@ -98,7 +203,26 @@ async function main() {
98
203
  }
99
204
  console.log(` Found Next.js app directory: ${appDir}`);
100
205
  console.log();
101
- console.log(" \u2500\u2500 Widget Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
206
+ console.log(" \u2500\u2500 Tier Selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
207
+ console.log();
208
+ const tierAnswer = await prompts({
209
+ type: "select",
210
+ name: "tier",
211
+ message: "Choose your tier",
212
+ choices: [
213
+ { title: "Chat only (AI conversations, localStorage persistence)", value: "chat" },
214
+ { title: "+ GitHub (Chat + auto-creates GitHub issues)", value: "github" },
215
+ { title: "+ Pipeline (Chat + GitHub + agent \u2192 PR \u2192 preview \u2192 approve)", value: "pipeline" }
216
+ ],
217
+ initial: 0
218
+ });
219
+ if (tierAnswer.tier === void 0) {
220
+ console.log(" Cancelled.");
221
+ process.exit(0);
222
+ }
223
+ const tier = tierAnswer.tier;
224
+ console.log();
225
+ console.log(" \u2500\u2500 Widget Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
102
226
  console.log();
103
227
  const widgetAnswers = await prompts([
104
228
  {
@@ -116,23 +240,17 @@ async function main() {
116
240
  console.log(" Cancelled.");
117
241
  process.exit(0);
118
242
  }
119
- console.log();
120
- console.log(" \u2500\u2500 GitHub Integration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
121
- console.log();
122
- const githubAnswer = await prompts({
123
- type: "confirm",
124
- name: "enabled",
125
- message: "Enable GitHub issues? (feedback creates issues for tracking)",
126
- initial: true
127
- });
128
243
  let githubToken = "";
129
244
  let githubRepo = "";
130
- if (githubAnswer.enabled) {
245
+ if (tier !== "chat") {
246
+ console.log();
247
+ console.log(" \u2500\u2500 GitHub Integration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
248
+ console.log();
131
249
  const ghAnswers = await prompts([
132
250
  {
133
251
  type: "password",
134
252
  name: "token",
135
- message: "GitHub token (needs repo scope)"
253
+ message: "GitHub token (needs repo scope, must start with ghp_)"
136
254
  },
137
255
  {
138
256
  type: "text",
@@ -143,7 +261,18 @@ async function main() {
143
261
  githubToken = ghAnswers.token || "";
144
262
  githubRepo = ghAnswers.repo || "";
145
263
  }
146
- const hasGithub = !!(githubToken && githubRepo);
264
+ let agentUrl = "";
265
+ if (tier === "pipeline") {
266
+ console.log();
267
+ console.log(" \u2500\u2500 Agent Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
268
+ console.log();
269
+ const agentAnswer = await prompts({
270
+ type: "text",
271
+ name: "url",
272
+ message: "Agent URL (e.g., https://your-agent.railway.app)"
273
+ });
274
+ agentUrl = agentAnswer.url || "";
275
+ }
147
276
  let overwrite = false;
148
277
  const chatRoutePath = join(appDir, "api", "feedback", "chat", "route.ts");
149
278
  const statusRoutePath = join(appDir, "api", "feedback", "status", "route.ts");
@@ -157,12 +286,17 @@ async function main() {
157
286
  overwrite = overwriteAnswer.overwrite ?? false;
158
287
  }
159
288
  console.log();
160
- if (safeWriteFile(chatRoutePath, CHAT_ROUTE_TEMPLATE(hasGithub), overwrite)) {
289
+ if (safeWriteFile(chatRoutePath, CHAT_ROUTE_TEMPLATE(tier), overwrite)) {
161
290
  console.log(` Created ${chatRoutePath}`);
162
291
  }
163
- if (safeWriteFile(statusRoutePath, STATUS_ROUTE_TEMPLATE, overwrite)) {
292
+ if (safeWriteFile(statusRoutePath, STATUS_ROUTE_TEMPLATE(tier), overwrite)) {
164
293
  console.log(` Created ${statusRoutePath}`);
165
294
  }
295
+ const componentsDir = detectComponentsDir(cwd);
296
+ const feedbackButtonPath = join(componentsDir, "FeedbackButton.tsx");
297
+ if (safeWriteFile(feedbackButtonPath, FEEDBACK_BUTTON_TEMPLATE, overwrite)) {
298
+ console.log(` Created ${feedbackButtonPath}`);
299
+ }
166
300
  const globalsCss = findGlobalsCss(cwd);
167
301
  if (globalsCss) {
168
302
  if (injectSourceDirective(globalsCss)) {
@@ -178,28 +312,43 @@ async function main() {
178
312
  const envPath = join(cwd, ".env.local");
179
313
  appendEnvVar(envPath, "ANTHROPIC_API_KEY", widgetAnswers.apiKey);
180
314
  appendEnvVar(envPath, "FEEDBACK_PASSWORD", widgetAnswers.password);
181
- if (hasGithub) {
182
- appendEnvVar(envPath, "GITHUB_TOKEN", githubToken);
183
- appendEnvVar(envPath, "GITHUB_REPO", githubRepo);
315
+ if (tier !== "chat") {
316
+ if (githubToken) appendEnvVar(envPath, "GITHUB_TOKEN", githubToken);
317
+ if (githubRepo) appendEnvVar(envPath, "GITHUB_REPO", githubRepo);
318
+ }
319
+ if (tier === "pipeline" && agentUrl) {
320
+ appendEnvVar(envPath, "AGENT_URL", agentUrl);
184
321
  }
185
322
  console.log(` Updated ${envPath}`);
323
+ if (tier !== "chat") {
324
+ console.log();
325
+ createGitHubLabels(cwd);
326
+ }
186
327
  console.log();
187
- console.log(" \u2500\u2500 Add to your layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
328
+ console.log(" \u2500\u2500 Next Steps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
188
329
  console.log();
189
- console.log(" // Create a client component (e.g., components/FeedbackButton.tsx):");
190
- console.log(" 'use client'");
191
- console.log(" import { useState } from 'react'");
192
- console.log(" import { FeedbackPanel } from '@nikitadmitrieff/feedback-chat'");
193
- console.log(" import '@nikitadmitrieff/feedback-chat/styles.css'");
330
+ const usesSrc = existsSync(join(cwd, "src", "app"));
331
+ const importPath = usesSrc ? "@/components/FeedbackButton" : "@/components/FeedbackButton";
332
+ console.log(" 1. Add to your layout.tsx:");
194
333
  console.log();
195
- console.log(" export function FeedbackButton() {");
196
- console.log(" const [open, setOpen] = useState(false)");
197
- console.log(" return <FeedbackPanel isOpen={open} onToggle={() => setOpen(!open)} />");
198
- console.log(" }");
334
+ console.log(` import { FeedbackButton } from '${importPath}'`);
199
335
  console.log();
200
- console.log(" // Then in your layout.tsx:");
201
- console.log(" import { FeedbackButton } from '@/components/FeedbackButton'");
202
- console.log(" // Inside <body>: <FeedbackButton />");
336
+ console.log(" // Inside <body>:");
337
+ console.log(" <FeedbackButton />");
338
+ console.log();
339
+ if (tier === "chat") {
340
+ console.log(" 2. Run npm run dev and open the app.");
341
+ console.log(" Click the feedback bar at the bottom, enter your password, and chat.");
342
+ } else if (tier === "github") {
343
+ console.log(" 2. Run npm run dev and open the app.");
344
+ console.log(" Submit feedback to see issues created on your repo.");
345
+ } else {
346
+ console.log(" 2. Run npm run dev and open the app.");
347
+ console.log(" Submit feedback to see issues created on your repo.");
348
+ console.log();
349
+ console.log(" 3. Deploy the agent service:");
350
+ console.log(" See docs/agent-deployment.md or run: npx feedback-chat deploy-agent");
351
+ }
203
352
  console.log();
204
353
  console.log(" Done.");
205
354
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikitadmitrieff/feedback-chat",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/client/index.js",
6
6
  "types": "./dist/client/index.d.ts",
@@ -21,7 +21,8 @@
21
21
  }
22
22
  },
23
23
  "bin": {
24
- "feedback-chat": "./dist/cli/init.js"
24
+ "feedback-chat": "./dist/cli/init.js",
25
+ "feedback-chat-deploy-agent": "./dist/cli/deploy-agent.js"
25
26
  },
26
27
  "files": ["dist", "README.md"],
27
28
  "scripts": {