@stephenov/feedbackwidget 0.3.1 → 0.4.1

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/dist/auto.js CHANGED
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  "use strict";
2
3
  "use client";
3
4
  var __create = Object.create;
package/dist/auto.mjs CHANGED
@@ -1,7 +1,8 @@
1
+ 'use client';
1
2
  "use client";
2
3
  import {
3
4
  FeedbackWidget
4
- } from "./chunk-QQLLK6MC.mjs";
5
+ } from "./chunk-WCFS4MGE.mjs";
5
6
 
6
7
  // src/auto.tsx
7
8
  import { useEffect, useState } from "react";
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  // src/utils.ts
2
4
  function cn(...classes) {
3
5
  return classes.filter(Boolean).join(" ");
package/dist/cli.js CHANGED
@@ -27,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  var import_http = __toESM(require("http"));
28
28
  var import_open = __toESM(require("open"));
29
29
  var import_crypto = require("crypto");
30
+ var import_child_process = require("child_process");
30
31
  var import_fs = __toESM(require("fs"));
31
32
  var import_path = __toESM(require("path"));
32
33
  var API_BASE = "https://feedbackwidget-api.vercel.app";
@@ -44,13 +45,6 @@ async function main() {
44
45
  }
45
46
  async function initProject() {
46
47
  console.log("\n\u{1F3A4} feedbackwidget - Voice-first feedback for your app\n");
47
- const existingKey = getStoredApiKey();
48
- if (existingKey) {
49
- console.log("\u2705 Already configured!");
50
- console.log(` API Key: ${existingKey.slice(0, 20)}...`);
51
- console.log("\n To reconfigure, delete .feedbackwidgetrc and run again.\n");
52
- return;
53
- }
54
48
  const state = (0, import_crypto.randomBytes)(16).toString("hex");
55
49
  const apiKey = await new Promise((resolve, reject) => {
56
50
  const server = import_http.default.createServer((req, res) => {
@@ -94,49 +88,44 @@ async function initProject() {
94
88
  reject(new Error("Authentication timed out"));
95
89
  }, 5 * 60 * 1e3);
96
90
  });
97
- const saved = saveApiKeyToEnv(apiKey);
98
- console.log("\u2705 Authenticated successfully!\n");
99
- console.log(` API Key: ${apiKey}
91
+ const snippet = `<FeedbackWidget apiKey="${apiKey}" />`;
92
+ let copied = false;
93
+ try {
94
+ await copyToClipboard(snippet);
95
+ copied = true;
96
+ } catch {
97
+ }
98
+ console.log("\u2705 Authenticated!\n");
99
+ console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
100
+ console.log(" Your API Key:\n");
101
+ console.log(` ${apiKey}
100
102
  `);
101
- if (saved) {
102
- console.log(` \u2713 Saved to ${saved}
103
+ console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
104
+ if (copied) {
105
+ console.log(" \u{1F4CB} Copied to clipboard!\n");
106
+ }
107
+ const framework = detectFramework();
108
+ console.log(" Add to your app:\n");
109
+ console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"\n');
110
+ console.log(` ${snippet}
103
111
  `);
104
- console.log(" Add ONE line to your app's root layout:\n");
105
- console.log(' import "@stephenov/feedbackwidget/auto"\n');
106
- } else {
107
- console.log(" Add to your .env.local (or .env):\n");
108
- console.log(` NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=${apiKey}
112
+ if (framework.name) {
113
+ console.log(` Detected: ${framework.name}
109
114
  `);
110
- console.log(" Then add to your app's root layout:\n");
111
- console.log(' import "@stephenov/feedbackwidget/auto"\n');
112
- }
113
- console.log(" Or use directly:\n");
114
- console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"');
115
- console.log(` <FeedbackWidget apiKey="${apiKey}" />
115
+ console.log(` Add to: ${framework.file}
116
116
  `);
117
- }
118
- async function whoami() {
119
- const apiKey = getStoredApiKey();
120
- if (!apiKey) {
121
- console.log("\nNot logged in. Run: npx @stephenov/feedbackwidget init\n");
122
- return;
123
- }
124
- try {
125
- const res = await fetch(`${API_BASE}/api/v1/validate`, {
126
- headers: { Authorization: `Bearer ${apiKey}` }
127
- });
128
- const data = await res.json();
129
- if (data.valid) {
130
- console.log(`
131
- Logged in as: ${data.project?.name || "Unknown"}`);
132
- console.log(`Plan: ${data.limits?.submissions || 100} submissions/month
117
+ if (framework.note) {
118
+ console.log(` Note: ${framework.note}
133
119
  `);
134
- } else {
135
- console.log("\nInvalid API key. Run: npx @stephenov/feedbackwidget init\n");
136
120
  }
137
- } catch {
138
- console.log("\nCouldn't verify API key. Check your connection.\n");
121
+ } else {
122
+ console.log(" Add to your root component (renders on every page)\n");
139
123
  }
124
+ console.log(" Dashboard: https://feedbackwidget-api.vercel.app/dashboard\n");
125
+ }
126
+ async function whoami() {
127
+ console.log("\nRun 'npx feedbackwidget init' to get your API key.\n");
128
+ console.log("Then check your dashboard at: https://feedbackwidget-api.vercel.app/dashboard\n");
140
129
  }
141
130
  function showHelp() {
142
131
  console.log(`
@@ -151,48 +140,6 @@ Usage:
151
140
  npx @stephenov/feedbackwidget whoami
152
141
  `);
153
142
  }
154
- function getStoredApiKey() {
155
- const envPath = import_path.default.join(process.cwd(), ".env.local");
156
- try {
157
- const content = import_fs.default.readFileSync(envPath, "utf-8");
158
- const match = content.match(/NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=(.+)/);
159
- return match ? match[1].trim() : null;
160
- } catch {
161
- return null;
162
- }
163
- }
164
- function saveApiKeyToEnv(apiKey) {
165
- const envVar = `NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=${apiKey}`;
166
- const envFiles = [".env.local", ".env"];
167
- for (const envFile of envFiles) {
168
- const envPath = import_path.default.join(process.cwd(), envFile);
169
- try {
170
- const content = import_fs.default.readFileSync(envPath, "utf-8");
171
- if (content.includes("NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=")) {
172
- const updated = content.replace(
173
- /NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=.*/,
174
- envVar
175
- );
176
- import_fs.default.writeFileSync(envPath, updated);
177
- } else {
178
- import_fs.default.appendFileSync(envPath, `
179
- ${envVar}
180
- `);
181
- }
182
- return envFile;
183
- } catch {
184
- continue;
185
- }
186
- }
187
- try {
188
- const envPath = import_path.default.join(process.cwd(), ".env.local");
189
- import_fs.default.writeFileSync(envPath, `${envVar}
190
- `);
191
- return ".env.local";
192
- } catch {
193
- return null;
194
- }
195
- }
196
143
  function successPage() {
197
144
  return `
198
145
  <!DOCTYPE html>
@@ -239,4 +186,86 @@ function errorPage(error) {
239
186
  </body>
240
187
  </html>`;
241
188
  }
189
+ function detectFramework() {
190
+ const cwd = process.cwd();
191
+ try {
192
+ const pkgPath = import_path.default.join(cwd, "package.json");
193
+ const pkg = JSON.parse(import_fs.default.readFileSync(pkgPath, "utf-8"));
194
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
195
+ if (deps.next && import_fs.default.existsSync(import_path.default.join(cwd, "app"))) {
196
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "app", "layout.tsx"))) {
197
+ return { name: "Next.js (App Router)", file: "app/layout.tsx", note: "Inside <body>, before {children}" };
198
+ }
199
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "app", "layout.js"))) {
200
+ return { name: "Next.js (App Router)", file: "app/layout.js", note: "Inside <body>, before {children}" };
201
+ }
202
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "app", "layout.tsx"))) {
203
+ return { name: "Next.js (App Router)", file: "src/app/layout.tsx", note: "Inside <body>, before {children}" };
204
+ }
205
+ }
206
+ if (deps.next && import_fs.default.existsSync(import_path.default.join(cwd, "pages"))) {
207
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "pages", "_app.tsx"))) {
208
+ return { name: "Next.js (Pages Router)", file: "pages/_app.tsx", note: "After <Component {...pageProps} />" };
209
+ }
210
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "pages", "_app.js"))) {
211
+ return { name: "Next.js (Pages Router)", file: "pages/_app.js", note: "After <Component {...pageProps} />" };
212
+ }
213
+ }
214
+ if (deps.vite && (deps.react || deps["@vitejs/plugin-react"])) {
215
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.tsx"))) {
216
+ return { name: "Vite + React", file: "src/App.tsx", note: "At end of App component" };
217
+ }
218
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.jsx"))) {
219
+ return { name: "Vite + React", file: "src/App.jsx", note: "At end of App component" };
220
+ }
221
+ }
222
+ if (deps["react-scripts"]) {
223
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.tsx"))) {
224
+ return { name: "Create React App", file: "src/App.tsx", note: "At end of App component" };
225
+ }
226
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.js"))) {
227
+ return { name: "Create React App", file: "src/App.js", note: "At end of App component" };
228
+ }
229
+ }
230
+ if (deps.astro) {
231
+ return { name: "Astro", file: "A React component", note: "Use client:load directive" };
232
+ }
233
+ if (deps["@remix-run/react"]) {
234
+ if (import_fs.default.existsSync(import_path.default.join(cwd, "app", "root.tsx"))) {
235
+ return { name: "Remix", file: "app/root.tsx", note: "Inside <body>" };
236
+ }
237
+ }
238
+ if (deps.react) {
239
+ return { name: "React", file: "Your App component", note: "Where it renders on every page" };
240
+ }
241
+ } catch {
242
+ }
243
+ return { name: null, file: "Your root component" };
244
+ }
245
+ async function copyToClipboard(text) {
246
+ return new Promise((resolve, reject) => {
247
+ const platform = process.platform;
248
+ let cmd;
249
+ let args = [];
250
+ if (platform === "darwin") {
251
+ cmd = "pbcopy";
252
+ } else if (platform === "linux") {
253
+ cmd = "xclip";
254
+ args = ["-selection", "clipboard"];
255
+ } else if (platform === "win32") {
256
+ cmd = "clip";
257
+ } else {
258
+ reject(new Error("Unsupported platform"));
259
+ return;
260
+ }
261
+ const proc = (0, import_child_process.spawn)(cmd, args);
262
+ proc.stdin.write(text);
263
+ proc.stdin.end();
264
+ proc.on("close", (code) => {
265
+ if (code === 0) resolve();
266
+ else reject(new Error(`Clipboard failed with code ${code}`));
267
+ });
268
+ proc.on("error", reject);
269
+ });
270
+ }
242
271
  main().catch(console.error);
package/dist/cli.mjs CHANGED
@@ -4,6 +4,7 @@
4
4
  import http from "http";
5
5
  import open from "open";
6
6
  import { randomBytes } from "crypto";
7
+ import { spawn } from "child_process";
7
8
  import fs from "fs";
8
9
  import path from "path";
9
10
  var API_BASE = "https://feedbackwidget-api.vercel.app";
@@ -21,13 +22,6 @@ async function main() {
21
22
  }
22
23
  async function initProject() {
23
24
  console.log("\n\u{1F3A4} feedbackwidget - Voice-first feedback for your app\n");
24
- const existingKey = getStoredApiKey();
25
- if (existingKey) {
26
- console.log("\u2705 Already configured!");
27
- console.log(` API Key: ${existingKey.slice(0, 20)}...`);
28
- console.log("\n To reconfigure, delete .feedbackwidgetrc and run again.\n");
29
- return;
30
- }
31
25
  const state = randomBytes(16).toString("hex");
32
26
  const apiKey = await new Promise((resolve, reject) => {
33
27
  const server = http.createServer((req, res) => {
@@ -71,49 +65,44 @@ async function initProject() {
71
65
  reject(new Error("Authentication timed out"));
72
66
  }, 5 * 60 * 1e3);
73
67
  });
74
- const saved = saveApiKeyToEnv(apiKey);
75
- console.log("\u2705 Authenticated successfully!\n");
76
- console.log(` API Key: ${apiKey}
68
+ const snippet = `<FeedbackWidget apiKey="${apiKey}" />`;
69
+ let copied = false;
70
+ try {
71
+ await copyToClipboard(snippet);
72
+ copied = true;
73
+ } catch {
74
+ }
75
+ console.log("\u2705 Authenticated!\n");
76
+ console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
77
+ console.log(" Your API Key:\n");
78
+ console.log(` ${apiKey}
77
79
  `);
78
- if (saved) {
79
- console.log(` \u2713 Saved to ${saved}
80
+ console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
81
+ if (copied) {
82
+ console.log(" \u{1F4CB} Copied to clipboard!\n");
83
+ }
84
+ const framework = detectFramework();
85
+ console.log(" Add to your app:\n");
86
+ console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"\n');
87
+ console.log(` ${snippet}
80
88
  `);
81
- console.log(" Add ONE line to your app's root layout:\n");
82
- console.log(' import "@stephenov/feedbackwidget/auto"\n');
83
- } else {
84
- console.log(" Add to your .env.local (or .env):\n");
85
- console.log(` NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=${apiKey}
89
+ if (framework.name) {
90
+ console.log(` Detected: ${framework.name}
86
91
  `);
87
- console.log(" Then add to your app's root layout:\n");
88
- console.log(' import "@stephenov/feedbackwidget/auto"\n');
89
- }
90
- console.log(" Or use directly:\n");
91
- console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"');
92
- console.log(` <FeedbackWidget apiKey="${apiKey}" />
92
+ console.log(` Add to: ${framework.file}
93
93
  `);
94
- }
95
- async function whoami() {
96
- const apiKey = getStoredApiKey();
97
- if (!apiKey) {
98
- console.log("\nNot logged in. Run: npx @stephenov/feedbackwidget init\n");
99
- return;
100
- }
101
- try {
102
- const res = await fetch(`${API_BASE}/api/v1/validate`, {
103
- headers: { Authorization: `Bearer ${apiKey}` }
104
- });
105
- const data = await res.json();
106
- if (data.valid) {
107
- console.log(`
108
- Logged in as: ${data.project?.name || "Unknown"}`);
109
- console.log(`Plan: ${data.limits?.submissions || 100} submissions/month
94
+ if (framework.note) {
95
+ console.log(` Note: ${framework.note}
110
96
  `);
111
- } else {
112
- console.log("\nInvalid API key. Run: npx @stephenov/feedbackwidget init\n");
113
97
  }
114
- } catch {
115
- console.log("\nCouldn't verify API key. Check your connection.\n");
98
+ } else {
99
+ console.log(" Add to your root component (renders on every page)\n");
116
100
  }
101
+ console.log(" Dashboard: https://feedbackwidget-api.vercel.app/dashboard\n");
102
+ }
103
+ async function whoami() {
104
+ console.log("\nRun 'npx feedbackwidget init' to get your API key.\n");
105
+ console.log("Then check your dashboard at: https://feedbackwidget-api.vercel.app/dashboard\n");
117
106
  }
118
107
  function showHelp() {
119
108
  console.log(`
@@ -128,48 +117,6 @@ Usage:
128
117
  npx @stephenov/feedbackwidget whoami
129
118
  `);
130
119
  }
131
- function getStoredApiKey() {
132
- const envPath = path.join(process.cwd(), ".env.local");
133
- try {
134
- const content = fs.readFileSync(envPath, "utf-8");
135
- const match = content.match(/NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=(.+)/);
136
- return match ? match[1].trim() : null;
137
- } catch {
138
- return null;
139
- }
140
- }
141
- function saveApiKeyToEnv(apiKey) {
142
- const envVar = `NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=${apiKey}`;
143
- const envFiles = [".env.local", ".env"];
144
- for (const envFile of envFiles) {
145
- const envPath = path.join(process.cwd(), envFile);
146
- try {
147
- const content = fs.readFileSync(envPath, "utf-8");
148
- if (content.includes("NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=")) {
149
- const updated = content.replace(
150
- /NEXT_PUBLIC_FEEDBACKWIDGET_API_KEY=.*/,
151
- envVar
152
- );
153
- fs.writeFileSync(envPath, updated);
154
- } else {
155
- fs.appendFileSync(envPath, `
156
- ${envVar}
157
- `);
158
- }
159
- return envFile;
160
- } catch {
161
- continue;
162
- }
163
- }
164
- try {
165
- const envPath = path.join(process.cwd(), ".env.local");
166
- fs.writeFileSync(envPath, `${envVar}
167
- `);
168
- return ".env.local";
169
- } catch {
170
- return null;
171
- }
172
- }
173
120
  function successPage() {
174
121
  return `
175
122
  <!DOCTYPE html>
@@ -216,4 +163,86 @@ function errorPage(error) {
216
163
  </body>
217
164
  </html>`;
218
165
  }
166
+ function detectFramework() {
167
+ const cwd = process.cwd();
168
+ try {
169
+ const pkgPath = path.join(cwd, "package.json");
170
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
171
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
172
+ if (deps.next && fs.existsSync(path.join(cwd, "app"))) {
173
+ if (fs.existsSync(path.join(cwd, "app", "layout.tsx"))) {
174
+ return { name: "Next.js (App Router)", file: "app/layout.tsx", note: "Inside <body>, before {children}" };
175
+ }
176
+ if (fs.existsSync(path.join(cwd, "app", "layout.js"))) {
177
+ return { name: "Next.js (App Router)", file: "app/layout.js", note: "Inside <body>, before {children}" };
178
+ }
179
+ if (fs.existsSync(path.join(cwd, "src", "app", "layout.tsx"))) {
180
+ return { name: "Next.js (App Router)", file: "src/app/layout.tsx", note: "Inside <body>, before {children}" };
181
+ }
182
+ }
183
+ if (deps.next && fs.existsSync(path.join(cwd, "pages"))) {
184
+ if (fs.existsSync(path.join(cwd, "pages", "_app.tsx"))) {
185
+ return { name: "Next.js (Pages Router)", file: "pages/_app.tsx", note: "After <Component {...pageProps} />" };
186
+ }
187
+ if (fs.existsSync(path.join(cwd, "pages", "_app.js"))) {
188
+ return { name: "Next.js (Pages Router)", file: "pages/_app.js", note: "After <Component {...pageProps} />" };
189
+ }
190
+ }
191
+ if (deps.vite && (deps.react || deps["@vitejs/plugin-react"])) {
192
+ if (fs.existsSync(path.join(cwd, "src", "App.tsx"))) {
193
+ return { name: "Vite + React", file: "src/App.tsx", note: "At end of App component" };
194
+ }
195
+ if (fs.existsSync(path.join(cwd, "src", "App.jsx"))) {
196
+ return { name: "Vite + React", file: "src/App.jsx", note: "At end of App component" };
197
+ }
198
+ }
199
+ if (deps["react-scripts"]) {
200
+ if (fs.existsSync(path.join(cwd, "src", "App.tsx"))) {
201
+ return { name: "Create React App", file: "src/App.tsx", note: "At end of App component" };
202
+ }
203
+ if (fs.existsSync(path.join(cwd, "src", "App.js"))) {
204
+ return { name: "Create React App", file: "src/App.js", note: "At end of App component" };
205
+ }
206
+ }
207
+ if (deps.astro) {
208
+ return { name: "Astro", file: "A React component", note: "Use client:load directive" };
209
+ }
210
+ if (deps["@remix-run/react"]) {
211
+ if (fs.existsSync(path.join(cwd, "app", "root.tsx"))) {
212
+ return { name: "Remix", file: "app/root.tsx", note: "Inside <body>" };
213
+ }
214
+ }
215
+ if (deps.react) {
216
+ return { name: "React", file: "Your App component", note: "Where it renders on every page" };
217
+ }
218
+ } catch {
219
+ }
220
+ return { name: null, file: "Your root component" };
221
+ }
222
+ async function copyToClipboard(text) {
223
+ return new Promise((resolve, reject) => {
224
+ const platform = process.platform;
225
+ let cmd;
226
+ let args = [];
227
+ if (platform === "darwin") {
228
+ cmd = "pbcopy";
229
+ } else if (platform === "linux") {
230
+ cmd = "xclip";
231
+ args = ["-selection", "clipboard"];
232
+ } else if (platform === "win32") {
233
+ cmd = "clip";
234
+ } else {
235
+ reject(new Error("Unsupported platform"));
236
+ return;
237
+ }
238
+ const proc = spawn(cmd, args);
239
+ proc.stdin.write(text);
240
+ proc.stdin.end();
241
+ proc.on("close", (code) => {
242
+ if (code === 0) resolve();
243
+ else reject(new Error(`Clipboard failed with code ${code}`));
244
+ });
245
+ proc.on("error", reject);
246
+ });
247
+ }
219
248
  main().catch(console.error);
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import {
2
3
  FeedbackApiClient,
3
4
  FeedbackPanel,
@@ -8,7 +9,7 @@ import {
8
9
  createApiClient,
9
10
  formatDuration,
10
11
  isVoiceSupported
11
- } from "./chunk-QQLLK6MC.mjs";
12
+ } from "./chunk-WCFS4MGE.mjs";
12
13
 
13
14
  // src/hooks/useFeedback.ts
14
15
  import { useState, useCallback, useMemo } from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stephenov/feedbackwidget",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Voice-first feedback widget with AI analysis, GitHub, and Slack integration",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -25,8 +25,8 @@
25
25
  "dist"
26
26
  ],
27
27
  "scripts": {
28
- "build": "tsup src/index.ts src/auto.tsx src/cli.ts --format cjs,esm --dts --clean",
29
- "dev": "tsup src/index.ts src/auto.tsx src/cli.ts --format cjs,esm --dts --watch",
28
+ "build": "tsup",
29
+ "dev": "tsup --watch",
30
30
  "lint": "eslint src/",
31
31
  "clean": "rm -rf dist"
32
32
  },