@embeddables/cli 0.8.0 → 0.8.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/auth/index.d.ts +43 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +102 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +210 -0
- package/dist/command-history.d.ts +13 -0
- package/dist/command-history.d.ts.map +1 -0
- package/dist/command-history.js +34 -0
- package/dist/commands/branch.d.ts +4 -0
- package/dist/commands/branch.d.ts.map +1 -0
- package/dist/commands/branch.js +67 -0
- package/dist/commands/build-workbench.d.ts +5 -0
- package/dist/commands/build-workbench.d.ts.map +1 -0
- package/dist/commands/build-workbench.js +116 -0
- package/dist/commands/build.d.ts +8 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +60 -0
- package/dist/commands/builder-open.d.ts +4 -0
- package/dist/commands/builder-open.d.ts.map +1 -0
- package/dist/commands/builder-open.js +74 -0
- package/dist/commands/dev.d.ts +12 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +226 -0
- package/dist/commands/diff.d.ts +76 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +653 -0
- package/dist/commands/experiments-connect.d.ts +6 -0
- package/dist/commands/experiments-connect.d.ts.map +1 -0
- package/dist/commands/experiments-connect.js +140 -0
- package/dist/commands/feedback.d.ts +29 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +267 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +384 -0
- package/dist/commands/inspect.d.ts +9 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +293 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +117 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +19 -0
- package/dist/commands/pull.d.ts +16 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +395 -0
- package/dist/commands/save.d.ts +30 -0
- package/dist/commands/save.d.ts.map +1 -0
- package/dist/commands/save.js +597 -0
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +50 -0
- package/dist/compiler/errors.d.ts +20 -0
- package/dist/compiler/errors.d.ts.map +1 -0
- package/dist/compiler/errors.js +35 -0
- package/dist/compiler/evalStatic.d.ts +3 -0
- package/dist/compiler/evalStatic.d.ts.map +1 -0
- package/dist/compiler/evalStatic.js +57 -0
- package/dist/compiler/flatten.js +1 -0
- package/dist/compiler/helpers/duplicateIds.d.ts +9 -0
- package/dist/compiler/helpers/duplicateIds.d.ts.map +1 -0
- package/dist/compiler/helpers/duplicateIds.js +71 -0
- package/dist/compiler/helpers/numericLeadingKeys.d.ts +8 -0
- package/dist/compiler/helpers/numericLeadingKeys.d.ts.map +1 -0
- package/dist/compiler/helpers/numericLeadingKeys.js +17 -0
- package/dist/compiler/index.d.ts +18 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +1272 -0
- package/dist/compiler/parsePage.d.ts +15 -0
- package/dist/compiler/parsePage.d.ts.map +1 -0
- package/dist/compiler/parsePage.js +654 -0
- package/dist/compiler/registry.d.ts +4 -0
- package/dist/compiler/registry.d.ts.map +1 -0
- package/dist/compiler/registry.js +44 -0
- package/dist/compiler/reverse.d.ts +23 -0
- package/dist/compiler/reverse.d.ts.map +1 -0
- package/dist/compiler/reverse.js +1920 -0
- package/dist/compiler/types.d.ts +21 -0
- package/dist/compiler/types.d.ts.map +1 -0
- package/dist/compiler/types.js +1 -0
- package/dist/components/index.d.ts +21 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +21 -0
- package/dist/components/primitives/BaseComponent.d.ts +33 -0
- package/dist/components/primitives/BaseComponent.d.ts.map +1 -0
- package/dist/components/primitives/BaseComponent.js +26 -0
- package/dist/components/primitives/BookMeeting.d.ts +18 -0
- package/dist/components/primitives/BookMeeting.d.ts.map +1 -0
- package/dist/components/primitives/BookMeeting.js +5 -0
- package/dist/components/primitives/Chart.d.ts +41 -0
- package/dist/components/primitives/Chart.d.ts.map +1 -0
- package/dist/components/primitives/Chart.js +5 -0
- package/dist/components/primitives/Container.d.ts +8 -0
- package/dist/components/primitives/Container.d.ts.map +1 -0
- package/dist/components/primitives/Container.js +5 -0
- package/dist/components/primitives/CustomButton.d.ts +37 -0
- package/dist/components/primitives/CustomButton.d.ts.map +1 -0
- package/dist/components/primitives/CustomButton.js +10 -0
- package/dist/components/primitives/CustomHTML.d.ts +8 -0
- package/dist/components/primitives/CustomHTML.d.ts.map +1 -0
- package/dist/components/primitives/CustomHTML.js +5 -0
- package/dist/components/primitives/FileUpload.d.ts +18 -0
- package/dist/components/primitives/FileUpload.d.ts.map +1 -0
- package/dist/components/primitives/FileUpload.js +16 -0
- package/dist/components/primitives/InputBox.d.ts +34 -0
- package/dist/components/primitives/InputBox.d.ts.map +1 -0
- package/dist/components/primitives/InputBox.js +25 -0
- package/dist/components/primitives/Lottie.d.ts +11 -0
- package/dist/components/primitives/Lottie.d.ts.map +1 -0
- package/dist/components/primitives/Lottie.js +5 -0
- package/dist/components/primitives/MediaEmbed.d.ts +13 -0
- package/dist/components/primitives/MediaEmbed.d.ts.map +1 -0
- package/dist/components/primitives/MediaEmbed.js +6 -0
- package/dist/components/primitives/MediaImage.d.ts +8 -0
- package/dist/components/primitives/MediaImage.d.ts.map +1 -0
- package/dist/components/primitives/MediaImage.js +5 -0
- package/dist/components/primitives/OptionSelector.d.ts +38 -0
- package/dist/components/primitives/OptionSelector.d.ts.map +1 -0
- package/dist/components/primitives/OptionSelector.js +8 -0
- package/dist/components/primitives/PaypalCheckout.d.ts +25 -0
- package/dist/components/primitives/PaypalCheckout.d.ts.map +1 -0
- package/dist/components/primitives/PaypalCheckout.js +5 -0
- package/dist/components/primitives/PlainText.d.ts +6 -0
- package/dist/components/primitives/PlainText.d.ts.map +1 -0
- package/dist/components/primitives/PlainText.js +5 -0
- package/dist/components/primitives/ProgressBar.d.ts +15 -0
- package/dist/components/primitives/ProgressBar.d.ts.map +1 -0
- package/dist/components/primitives/ProgressBar.js +5 -0
- package/dist/components/primitives/RichText.d.ts +6 -0
- package/dist/components/primitives/RichText.d.ts.map +1 -0
- package/dist/components/primitives/RichText.js +5 -0
- package/dist/components/primitives/RichTextMarkdown.d.ts +6 -0
- package/dist/components/primitives/RichTextMarkdown.d.ts.map +1 -0
- package/dist/components/primitives/RichTextMarkdown.js +5 -0
- package/dist/components/primitives/Rive.d.ts +16 -0
- package/dist/components/primitives/Rive.d.ts.map +1 -0
- package/dist/components/primitives/Rive.js +8 -0
- package/dist/components/primitives/StripeCheckout.d.ts +52 -0
- package/dist/components/primitives/StripeCheckout.d.ts.map +1 -0
- package/dist/components/primitives/StripeCheckout.js +5 -0
- package/dist/components/primitives/StripeCheckout2.d.ts +30 -0
- package/dist/components/primitives/StripeCheckout2.d.ts.map +1 -0
- package/dist/components/primitives/StripeCheckout2.js +7 -0
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +42 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +9 -0
- package/dist/helpers/TEMP helpers file.d.ts +1 -0
- package/dist/helpers/TEMP helpers file.d.ts.map +1 -0
- package/dist/helpers/TEMP helpers file.js +1 -0
- package/dist/helpers/dates.d.ts +5 -0
- package/dist/helpers/dates.d.ts.map +1 -0
- package/dist/helpers/dates.js +7 -0
- package/dist/helpers/json.d.ts +47 -0
- package/dist/helpers/json.d.ts.map +1 -0
- package/dist/helpers/json.js +622 -0
- package/dist/helpers/prompt.d.ts +15 -0
- package/dist/helpers/prompt.d.ts.map +1 -0
- package/dist/helpers/prompt.js +35 -0
- package/dist/helpers/utils.d.ts +13 -0
- package/dist/helpers/utils.d.ts.map +1 -0
- package/dist/helpers/utils.js +28 -0
- package/dist/logger.d.ts +11 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +21 -0
- package/dist/patches/prompts-escape.d.ts +14 -0
- package/dist/patches/prompts-escape.d.ts.map +1 -0
- package/dist/patches/prompts-escape.js +23 -0
- package/dist/prompts/branches.d.ts +20 -0
- package/dist/prompts/branches.d.ts.map +1 -0
- package/dist/prompts/branches.js +86 -0
- package/dist/prompts/embeddables.d.ts +43 -0
- package/dist/prompts/embeddables.d.ts.map +1 -0
- package/dist/prompts/embeddables.js +200 -0
- package/dist/prompts/experiments.d.ts +28 -0
- package/dist/prompts/experiments.d.ts.map +1 -0
- package/dist/prompts/experiments.js +89 -0
- package/dist/prompts/index.d.ts +11 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +6 -0
- package/dist/prompts/projects.d.ts +22 -0
- package/dist/prompts/projects.d.ts.map +1 -0
- package/dist/prompts/projects.js +92 -0
- package/dist/prompts/versions.d.ts +18 -0
- package/dist/prompts/versions.d.ts.map +1 -0
- package/dist/prompts/versions.js +95 -0
- package/dist/proxy/injectApiInterceptor.d.ts +6 -0
- package/dist/proxy/injectApiInterceptor.d.ts.map +1 -0
- package/dist/proxy/injectApiInterceptor.js +66 -0
- package/dist/proxy/injectReload.d.ts +2 -0
- package/dist/proxy/injectReload.d.ts.map +1 -0
- package/dist/proxy/injectReload.js +14 -0
- package/dist/proxy/injectWorkbench.d.ts +5 -0
- package/dist/proxy/injectWorkbench.d.ts.map +1 -0
- package/dist/proxy/injectWorkbench.js +22 -0
- package/dist/proxy/server.d.ts +11 -0
- package/dist/proxy/server.d.ts.map +1 -0
- package/dist/proxy/server.js +304 -0
- package/dist/proxy/sse.d.ts +5 -0
- package/dist/proxy/sse.d.ts.map +1 -0
- package/dist/proxy/sse.js +17 -0
- package/dist/sentry-context.d.ts +48 -0
- package/dist/sentry-context.d.ts.map +1 -0
- package/dist/sentry-context.js +156 -0
- package/dist/stdout.d.ts +61 -0
- package/dist/stdout.d.ts.map +1 -0
- package/dist/stdout.js +163 -0
- package/dist/types-builder.d.ts +800 -0
- package/dist/types-builder.d.ts.map +1 -0
- package/dist/types-builder.js +20 -0
- package/dist/workbench/ActionsPanel.d.ts +6 -0
- package/dist/workbench/ActionsPanel.d.ts.map +1 -0
- package/dist/workbench/ActionsPanel.js +47 -0
- package/dist/workbench/AutofillPanel.d.ts +6 -0
- package/dist/workbench/AutofillPanel.d.ts.map +1 -0
- package/dist/workbench/AutofillPanel.js +543 -0
- package/dist/workbench/ComputedFieldsPanel.d.ts +6 -0
- package/dist/workbench/ComputedFieldsPanel.d.ts.map +1 -0
- package/dist/workbench/ComputedFieldsPanel.js +31 -0
- package/dist/workbench/ExperimentsPanel.d.ts +6 -0
- package/dist/workbench/ExperimentsPanel.d.ts.map +1 -0
- package/dist/workbench/ExperimentsPanel.js +182 -0
- package/dist/workbench/FieldEditorPanel.d.ts +9 -0
- package/dist/workbench/FieldEditorPanel.d.ts.map +1 -0
- package/dist/workbench/FieldEditorPanel.js +650 -0
- package/dist/workbench/InspectorPanel.d.ts +6 -0
- package/dist/workbench/InspectorPanel.d.ts.map +1 -0
- package/dist/workbench/InspectorPanel.js +341 -0
- package/dist/workbench/PageNavigator.d.ts +6 -0
- package/dist/workbench/PageNavigator.d.ts.map +1 -0
- package/dist/workbench/PageNavigator.js +123 -0
- package/dist/workbench/SchemaPanel.d.ts +6 -0
- package/dist/workbench/SchemaPanel.d.ts.map +1 -0
- package/dist/workbench/SchemaPanel.js +222 -0
- package/dist/workbench/UserDataPanel.d.ts +6 -0
- package/dist/workbench/UserDataPanel.d.ts.map +1 -0
- package/dist/workbench/UserDataPanel.js +350 -0
- package/dist/workbench/WorkbenchApp.d.ts +7 -0
- package/dist/workbench/WorkbenchApp.d.ts.map +1 -0
- package/dist/workbench/WorkbenchApp.js +193 -0
- package/dist/workbench/cloudflare-worker/README.md +31 -0
- package/dist/workbench/cloudflare-worker/public/workbench.css +1614 -0
- package/dist/workbench/cloudflare-worker/public/workbench.js +77 -0
- package/dist/workbench/cloudflare-worker/worker.js +40 -0
- package/dist/workbench/cloudflare-worker/wrangler.toml +10 -0
- package/dist/workbench/index.d.ts +10 -0
- package/dist/workbench/index.d.ts.map +1 -0
- package/dist/workbench/index.js +44 -0
- package/dist/workbench/workbench.css +1614 -0
- package/dist/workbench/workbench.js +77 -0
- package/package.json +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isLoggedIn } from '../auth/index.js';
|
|
4
|
+
import { getProjectId, writeProjectConfig } from '../config/index.js';
|
|
5
|
+
import { promptForProject, promptForLocalEmbeddable, promptForExperiment, } from '../prompts/index.js';
|
|
6
|
+
import { createLogger, exit } from '../logger.js';
|
|
7
|
+
import { getSentryContextFromEmbeddableConfig, getSentryContextFromProjectConfig, setSentryContext, } from '../sentry-context.js';
|
|
8
|
+
import * as stdout from '../stdout.js';
|
|
9
|
+
import { inferEmbeddableFromCwd } from '../helpers/utils.js';
|
|
10
|
+
export async function runExperimentsConnect(opts) {
|
|
11
|
+
const logger = createLogger('runExperimentsConnect');
|
|
12
|
+
try {
|
|
13
|
+
await runExperimentsConnectInner(opts);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
stdout.error(`Connect failed: ${error.message}`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
stdout.error('Connect failed with an unexpected error.');
|
|
21
|
+
}
|
|
22
|
+
logger.error('experiments connect failed', {
|
|
23
|
+
message: error instanceof Error ? error.message : 'unexpected error',
|
|
24
|
+
});
|
|
25
|
+
await exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function runExperimentsConnectInner(opts) {
|
|
29
|
+
const logger = createLogger('runExperimentsConnect');
|
|
30
|
+
// 1. Check login (needed for fetching experiments from Supabase)
|
|
31
|
+
if (!isLoggedIn()) {
|
|
32
|
+
stdout.warn('Not logged in.');
|
|
33
|
+
stdout.dim('Run "embeddables login" first.');
|
|
34
|
+
logger.error('not logged in');
|
|
35
|
+
await exit(1);
|
|
36
|
+
}
|
|
37
|
+
// 2. Get project ID (needed for experiment list)
|
|
38
|
+
let projectId = getProjectId();
|
|
39
|
+
if (!projectId) {
|
|
40
|
+
stdout.step('No project configured. Fetching projects…');
|
|
41
|
+
const selectedProject = await promptForProject();
|
|
42
|
+
if (!selectedProject) {
|
|
43
|
+
await exit(1);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
projectId = selectedProject.id;
|
|
47
|
+
writeProjectConfig({
|
|
48
|
+
org_id: selectedProject.org_id || undefined,
|
|
49
|
+
org_title: selectedProject.org_title || undefined,
|
|
50
|
+
project_id: projectId,
|
|
51
|
+
project_name: selectedProject.title || undefined,
|
|
52
|
+
});
|
|
53
|
+
stdout.success('Saved project to embeddables.json');
|
|
54
|
+
stdout.gap();
|
|
55
|
+
}
|
|
56
|
+
// 4. Get embeddable ID (from option, cwd inference, or interactive prompt)
|
|
57
|
+
const inferred = inferEmbeddableFromCwd();
|
|
58
|
+
let embeddableId = opts.id ?? inferred?.embeddableId;
|
|
59
|
+
if (inferred && !opts.id && embeddableId) {
|
|
60
|
+
process.chdir(inferred.projectRoot);
|
|
61
|
+
}
|
|
62
|
+
setSentryContext(getSentryContextFromProjectConfig());
|
|
63
|
+
if (!embeddableId) {
|
|
64
|
+
const selected = await promptForLocalEmbeddable({
|
|
65
|
+
message: 'Select an embeddable to connect the experiment to:',
|
|
66
|
+
});
|
|
67
|
+
if (!selected) {
|
|
68
|
+
await exit(1);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
embeddableId = selected;
|
|
72
|
+
stdout.gap();
|
|
73
|
+
}
|
|
74
|
+
if (embeddableId) {
|
|
75
|
+
setSentryContext({
|
|
76
|
+
embeddable: { id: embeddableId },
|
|
77
|
+
...getSentryContextFromEmbeddableConfig(embeddableId),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// 5. Get experiment_id and experiment_key (from opts or interactive prompt)
|
|
81
|
+
let experimentId = opts.experimentId;
|
|
82
|
+
let experimentKey = opts.experimentKey;
|
|
83
|
+
if (experimentId && !experimentKey) {
|
|
84
|
+
stdout.error('When using --experiment-id, --experiment-key is also required.');
|
|
85
|
+
logger.error('missing experiment-key flag');
|
|
86
|
+
await exit(1);
|
|
87
|
+
}
|
|
88
|
+
if (experimentKey && !experimentId) {
|
|
89
|
+
stdout.error('When using --experiment-key, --experiment-id is also required.');
|
|
90
|
+
logger.error('missing experiment-id flag');
|
|
91
|
+
await exit(1);
|
|
92
|
+
}
|
|
93
|
+
if (!experimentId || !experimentKey) {
|
|
94
|
+
const selected = await stdout.withSpinner('Fetching experiments…', async () => {
|
|
95
|
+
return promptForExperiment(projectId, {
|
|
96
|
+
message: 'Select an experiment to connect:',
|
|
97
|
+
excludeConnectedTo: embeddableId,
|
|
98
|
+
});
|
|
99
|
+
}, { successText: 'Experiments loaded' });
|
|
100
|
+
if (!selected) {
|
|
101
|
+
await exit(1);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
experimentId = selected.experiment_id;
|
|
105
|
+
experimentKey = selected.experiment_key;
|
|
106
|
+
stdout.gap();
|
|
107
|
+
}
|
|
108
|
+
// 6. Read config.json
|
|
109
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
110
|
+
if (!fs.existsSync(configPath)) {
|
|
111
|
+
stdout.error(`No config.json found at ${configPath}`);
|
|
112
|
+
stdout.dim('Run "embeddables pull" or "embeddables init" first.');
|
|
113
|
+
logger.error('config not found', { configPath });
|
|
114
|
+
await exit(1);
|
|
115
|
+
}
|
|
116
|
+
let config;
|
|
117
|
+
try {
|
|
118
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
119
|
+
config = JSON.parse(content);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
stdout.error('Failed to parse config.json.');
|
|
123
|
+
logger.error('failed to parse config');
|
|
124
|
+
await exit(1);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// 7. Append to connected_experiments
|
|
128
|
+
const connectedExperiments = Array.isArray(config.connected_experiments) ? [...config.connected_experiments] : [];
|
|
129
|
+
const alreadyConnected = connectedExperiments.some((e) => e.experiment_id === experimentId && e.experiment_key === experimentKey);
|
|
130
|
+
if (alreadyConnected) {
|
|
131
|
+
stdout.warn(`Experiment "${experimentKey}" is already connected to this embeddable.`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
connectedExperiments.push({ experiment_id: experimentId, experiment_key: experimentKey });
|
|
135
|
+
config.connected_experiments = connectedExperiments;
|
|
136
|
+
// 8. Write the modified config back
|
|
137
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
138
|
+
stdout.success(`Connected experiment "${experimentKey}" to embeddable`);
|
|
139
|
+
stdout.dim('Run "embeddables save" to persist to the cloud.');
|
|
140
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type FeedbackCategory = 'cli' | 'ai' | 'compiler' | 'other';
|
|
2
|
+
export interface RunFeedbackOptions {
|
|
3
|
+
message?: string;
|
|
4
|
+
positive?: boolean;
|
|
5
|
+
negative?: boolean;
|
|
6
|
+
category?: FeedbackCategory;
|
|
7
|
+
}
|
|
8
|
+
export declare function runFeedback(opts: RunFeedbackOptions): Promise<void>;
|
|
9
|
+
export interface FeedbackContext {
|
|
10
|
+
userEmail?: string;
|
|
11
|
+
userName?: string;
|
|
12
|
+
cliVersion?: string;
|
|
13
|
+
nodeVersion?: string;
|
|
14
|
+
platform?: string;
|
|
15
|
+
osRelease?: string;
|
|
16
|
+
arch?: string;
|
|
17
|
+
projectId?: string;
|
|
18
|
+
projectName?: string;
|
|
19
|
+
orgId?: string;
|
|
20
|
+
orgName?: string;
|
|
21
|
+
embeddableId?: string;
|
|
22
|
+
lastCommand?: Record<string, unknown>;
|
|
23
|
+
gitBranch?: string;
|
|
24
|
+
gitDirty?: boolean;
|
|
25
|
+
aiTool?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function collectFeedbackContext(): FeedbackContext;
|
|
28
|
+
export declare function detectAiTool(): string | undefined;
|
|
29
|
+
//# sourceMappingURL=feedback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/commands/feedback.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,IAAI,GAAG,UAAU,GAAG,OAAO,CAAA;AAElE,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC5B;AAID,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsIzE;AAID,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,sBAAsB,IAAI,eAAe,CA+FxD;AAED,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CA0BjD"}
|
|
@@ -0,0 +1,267 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAoIA,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,iBAkSxE"}
|