@embeddables/cli 0.8.1 → 0.8.2
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/compiler/reverse.d.ts.map +1 -1
- package/dist/compiler/reverse.js +19 -1
- package/package.json +2 -1
- package/dist/command-history.d.ts +0 -13
- package/dist/command-history.d.ts.map +0 -1
- package/dist/command-history.js +0 -34
- package/dist/commands/diff.d.ts +0 -76
- package/dist/commands/diff.d.ts.map +0 -1
- package/dist/commands/diff.js +0 -653
- package/dist/commands/feedback.d.ts +0 -29
- package/dist/commands/feedback.d.ts.map +0 -1
- package/dist/commands/feedback.js +0 -267
- package/dist/compiler/flatten.js +0 -1
- package/dist/helpers/TEMP helpers file.d.ts +0 -1
- package/dist/helpers/TEMP helpers file.d.ts.map +0 -1
- package/dist/helpers/TEMP helpers file.js +0 -1
- package/dist/workbench/cloudflare-worker/README.md +0 -31
- package/dist/workbench/cloudflare-worker/public/workbench.css +0 -1614
- package/dist/workbench/cloudflare-worker/public/workbench.js +0 -77
- package/dist/workbench/cloudflare-worker/worker.js +0 -40
- package/dist/workbench/cloudflare-worker/wrangler.toml +0 -10
- package/dist/workbench/workbench.css +0 -1614
- package/dist/workbench/workbench.js +0 -77
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { execSync } from 'node:child_process';
|
|
5
|
-
import * as Sentry from '@sentry/node';
|
|
6
|
-
import { createLogger } from '../logger.js';
|
|
7
|
-
import * as stdout from '../stdout.js';
|
|
8
|
-
import { prompt } from '../helpers/prompt.js';
|
|
9
|
-
import { readProjectConfig } from '../config/index.js';
|
|
10
|
-
import { getLastHistoryEntry } from '../command-history.js';
|
|
11
|
-
import { getSentryContextFromEmbeddableConfig, setSentryContext } from '../sentry-context.js';
|
|
12
|
-
const logger = createLogger('runFeedback');
|
|
13
|
-
const VALID_CATEGORIES = new Set(['cli', 'ai', 'compiler', 'other']);
|
|
14
|
-
export async function runFeedback(opts) {
|
|
15
|
-
// 1. Resolve message
|
|
16
|
-
let message = opts.message;
|
|
17
|
-
if (!message) {
|
|
18
|
-
const res = await prompt({
|
|
19
|
-
type: 'text',
|
|
20
|
-
name: 'value',
|
|
21
|
-
message: "What's your feedback?",
|
|
22
|
-
});
|
|
23
|
-
message = res.value?.trim();
|
|
24
|
-
if (!message) {
|
|
25
|
-
stdout.warn('No feedback provided.');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// 2. Resolve sentiment
|
|
30
|
-
let sentiment;
|
|
31
|
-
if (opts.positive) {
|
|
32
|
-
sentiment = 'positive';
|
|
33
|
-
}
|
|
34
|
-
else if (opts.negative) {
|
|
35
|
-
sentiment = 'negative';
|
|
36
|
-
}
|
|
37
|
-
else if (!opts.message) {
|
|
38
|
-
const res = await prompt({
|
|
39
|
-
type: 'select',
|
|
40
|
-
name: 'value',
|
|
41
|
-
message: 'Was this positive or negative?',
|
|
42
|
-
choices: [
|
|
43
|
-
{ title: '👍 Positive', value: 'positive' },
|
|
44
|
-
{ title: '👎 Negative', value: 'negative' },
|
|
45
|
-
],
|
|
46
|
-
});
|
|
47
|
-
sentiment = res.value === 'positive' ? 'positive' : 'negative';
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
sentiment = 'negative';
|
|
51
|
-
}
|
|
52
|
-
// 3. Resolve category
|
|
53
|
-
let category = opts.category;
|
|
54
|
-
if (category && !VALID_CATEGORIES.has(category)) {
|
|
55
|
-
stdout.warn(`Invalid category "${category}". Must be one of: cli, ai, compiler, other`);
|
|
56
|
-
category = undefined;
|
|
57
|
-
}
|
|
58
|
-
if (!category && !opts.message) {
|
|
59
|
-
const res = await prompt({
|
|
60
|
-
type: 'select',
|
|
61
|
-
name: 'value',
|
|
62
|
-
message: 'Which area does this relate to?',
|
|
63
|
-
choices: [
|
|
64
|
-
{ title: 'CLI command', value: 'cli' },
|
|
65
|
-
{ title: 'AI prompts', value: 'ai' },
|
|
66
|
-
{ title: 'Compiler', value: 'compiler' },
|
|
67
|
-
{ title: 'Other', value: 'other' },
|
|
68
|
-
],
|
|
69
|
-
});
|
|
70
|
-
category = res.value || undefined;
|
|
71
|
-
}
|
|
72
|
-
// 4. Collect context
|
|
73
|
-
const context = collectFeedbackContext();
|
|
74
|
-
// 5. Set Sentry context and send
|
|
75
|
-
Sentry.setTag('feedback.sentiment', sentiment);
|
|
76
|
-
if (category)
|
|
77
|
-
Sentry.setTag('feedback.category', category);
|
|
78
|
-
Sentry.setContext('feedback', {
|
|
79
|
-
sentiment,
|
|
80
|
-
category: category ?? null,
|
|
81
|
-
});
|
|
82
|
-
if (context.cliVersion)
|
|
83
|
-
Sentry.setTag('cli.version', context.cliVersion);
|
|
84
|
-
if (context.nodeVersion)
|
|
85
|
-
Sentry.setTag('node.version', context.nodeVersion);
|
|
86
|
-
if (context.platform)
|
|
87
|
-
Sentry.setTag('os.platform', context.platform);
|
|
88
|
-
if (context.arch)
|
|
89
|
-
Sentry.setTag('os.arch', context.arch);
|
|
90
|
-
Sentry.setContext('environment', {
|
|
91
|
-
cliVersion: context.cliVersion ?? null,
|
|
92
|
-
nodeVersion: context.nodeVersion ?? null,
|
|
93
|
-
platform: context.platform ?? null,
|
|
94
|
-
osRelease: context.osRelease ?? null,
|
|
95
|
-
arch: context.arch ?? null,
|
|
96
|
-
});
|
|
97
|
-
if (context.projectId || context.orgId) {
|
|
98
|
-
setSentryContext({
|
|
99
|
-
project: context.projectId
|
|
100
|
-
? { id: context.projectId, title: context.projectName ?? null }
|
|
101
|
-
: undefined,
|
|
102
|
-
org: context.orgId ? { id: context.orgId, title: context.orgName ?? null } : undefined,
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
if (context.embeddableId) {
|
|
106
|
-
const embCtx = getSentryContextFromEmbeddableConfig(context.embeddableId);
|
|
107
|
-
setSentryContext({
|
|
108
|
-
embeddable: { id: context.embeddableId },
|
|
109
|
-
...embCtx,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
if (context.lastCommand) {
|
|
113
|
-
Sentry.setContext('lastCommand', context.lastCommand);
|
|
114
|
-
}
|
|
115
|
-
Sentry.setContext('git', {
|
|
116
|
-
branch: context.gitBranch ?? null,
|
|
117
|
-
dirty: context.gitDirty ?? null,
|
|
118
|
-
});
|
|
119
|
-
if (context.aiTool) {
|
|
120
|
-
Sentry.setTag('ai.tool', context.aiTool);
|
|
121
|
-
Sentry.setContext('ai', { tool: context.aiTool });
|
|
122
|
-
}
|
|
123
|
-
Sentry.captureFeedback({
|
|
124
|
-
message,
|
|
125
|
-
email: context.userEmail ?? undefined,
|
|
126
|
-
name: context.userName ?? undefined,
|
|
127
|
-
});
|
|
128
|
-
await Sentry.flush(5000);
|
|
129
|
-
// 6. Show confirmation
|
|
130
|
-
stdout.gap();
|
|
131
|
-
const icon = sentiment === 'positive' ? '👍' : '👎';
|
|
132
|
-
stdout.success(`Feedback sent ${icon}`);
|
|
133
|
-
stdout.dim('Thanks for helping us improve!');
|
|
134
|
-
logger.info('feedback sent', {
|
|
135
|
-
sentiment,
|
|
136
|
-
category: category ?? 'none',
|
|
137
|
-
hasEmail: !!context.userEmail,
|
|
138
|
-
messageLength: message.length,
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
export function collectFeedbackContext() {
|
|
142
|
-
const ctx = {};
|
|
143
|
-
// User email from auth (best effort, no await — read sync from file)
|
|
144
|
-
try {
|
|
145
|
-
const authPath = path.join(os.homedir(), '.embeddables', 'auth.json');
|
|
146
|
-
if (fs.existsSync(authPath)) {
|
|
147
|
-
const raw = JSON.parse(fs.readFileSync(authPath, 'utf8'));
|
|
148
|
-
if (raw.access_token && typeof raw.access_token === 'string') {
|
|
149
|
-
const payload = JSON.parse(Buffer.from(raw.access_token.split('.')[1], 'base64').toString());
|
|
150
|
-
if (typeof payload.email === 'string')
|
|
151
|
-
ctx.userEmail = payload.email;
|
|
152
|
-
if (typeof payload.name === 'string')
|
|
153
|
-
ctx.userName = payload.name;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
// auth not available — fine
|
|
159
|
-
}
|
|
160
|
-
// CLI version
|
|
161
|
-
try {
|
|
162
|
-
const pkgPath = path.join(path.dirname(new URL(import.meta.url).pathname), '..', 'package.json');
|
|
163
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
164
|
-
if (typeof pkg.version === 'string')
|
|
165
|
-
ctx.cliVersion = pkg.version;
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
// ignore
|
|
169
|
-
}
|
|
170
|
-
// Node / OS
|
|
171
|
-
ctx.nodeVersion = process.version;
|
|
172
|
-
ctx.platform = process.platform;
|
|
173
|
-
ctx.osRelease = os.release();
|
|
174
|
-
ctx.arch = process.arch;
|
|
175
|
-
// Project config
|
|
176
|
-
try {
|
|
177
|
-
const config = readProjectConfig();
|
|
178
|
-
if (config?.project_id)
|
|
179
|
-
ctx.projectId = config.project_id;
|
|
180
|
-
if (config?.project_name)
|
|
181
|
-
ctx.projectName = config.project_name;
|
|
182
|
-
if (config?.org_id)
|
|
183
|
-
ctx.orgId = config.org_id;
|
|
184
|
-
if (config?.org_title)
|
|
185
|
-
ctx.orgName = config.org_title;
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// ignore
|
|
189
|
-
}
|
|
190
|
-
// Embeddable ID (first local embeddable found)
|
|
191
|
-
try {
|
|
192
|
-
const embeddablesDir = 'embeddables';
|
|
193
|
-
if (fs.existsSync(embeddablesDir)) {
|
|
194
|
-
const entries = fs.readdirSync(embeddablesDir, { withFileTypes: true });
|
|
195
|
-
const firstDir = entries.find((e) => e.isDirectory());
|
|
196
|
-
if (firstDir)
|
|
197
|
-
ctx.embeddableId = firstDir.name;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
catch {
|
|
201
|
-
// ignore
|
|
202
|
-
}
|
|
203
|
-
// Last CLI command
|
|
204
|
-
try {
|
|
205
|
-
const last = getLastHistoryEntry();
|
|
206
|
-
if (last) {
|
|
207
|
-
ctx.lastCommand = { ...last };
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
// ignore
|
|
212
|
-
}
|
|
213
|
-
// Git branch
|
|
214
|
-
try {
|
|
215
|
-
ctx.gitBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
216
|
-
encoding: 'utf8',
|
|
217
|
-
timeout: 3000,
|
|
218
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
219
|
-
}).trim();
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
// not in a git repo
|
|
223
|
-
}
|
|
224
|
-
// Git dirty
|
|
225
|
-
try {
|
|
226
|
-
const status = execSync('git status --porcelain', {
|
|
227
|
-
encoding: 'utf8',
|
|
228
|
-
timeout: 3000,
|
|
229
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
230
|
-
}).trim();
|
|
231
|
-
ctx.gitDirty = status.length > 0;
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
// not in a git repo
|
|
235
|
-
}
|
|
236
|
-
// AI tool detection
|
|
237
|
-
ctx.aiTool = detectAiTool();
|
|
238
|
-
return ctx;
|
|
239
|
-
}
|
|
240
|
-
export function detectAiTool() {
|
|
241
|
-
const envChecks = [
|
|
242
|
-
['CURSOR_', 'cursor'],
|
|
243
|
-
['CLAUDE_', 'claude-code'],
|
|
244
|
-
['WINDSURF_', 'windsurf'],
|
|
245
|
-
];
|
|
246
|
-
for (const [prefix, name] of envChecks) {
|
|
247
|
-
for (const key of Object.keys(process.env)) {
|
|
248
|
-
if (key.startsWith(prefix))
|
|
249
|
-
return name;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
const dirChecks = [
|
|
253
|
-
['.cursor', 'cursor'],
|
|
254
|
-
['.claude', 'claude-code'],
|
|
255
|
-
['.windsurf', 'windsurf'],
|
|
256
|
-
];
|
|
257
|
-
for (const [dir, name] of dirChecks) {
|
|
258
|
-
try {
|
|
259
|
-
if (fs.existsSync(path.join(process.cwd(), dir)))
|
|
260
|
-
return name;
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
// ignore
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return undefined;
|
|
267
|
-
}
|
package/dist/compiler/flatten.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=TEMP%20helpers%20file.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TEMP helpers file.d.ts","sourceRoot":"","sources":["../../src/helpers/TEMP helpers file.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Embeddables Workbench - Cloudflare Worker
|
|
2
|
-
|
|
3
|
-
## Deploy
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npx wrangler login # One-time
|
|
7
|
-
npx wrangler deploy
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## Assets
|
|
11
|
-
|
|
12
|
-
- `public/workbench.js` - Main bundle
|
|
13
|
-
- `public/workbench.css` - Styles
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
|
|
17
|
-
Add `?workbench=true` to any engine preview URL:
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
https://engine.embeddables.com/preview/<id>?workbench=true
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The engine will inject the workbench from this CDN.
|
|
24
|
-
|
|
25
|
-
## Update
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npx embeddables build-workbench
|
|
29
|
-
cd dist/workbench/cloudflare-worker
|
|
30
|
-
npx wrangler deploy
|
|
31
|
-
```
|