@amplitude/wizard 1.0.0-beta.0 → 1.0.0-beta.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/bin.js +191 -47
- package/dist/src/lib/agent-interface.js +10 -22
- package/dist/src/lib/agent-runner.js +4 -6
- package/dist/src/lib/commandments.js +1 -1
- package/dist/src/lib/constants.d.ts +1 -4
- package/dist/src/lib/constants.js +9 -8
- package/dist/src/lib/feature-flags.d.ts +37 -0
- package/dist/src/lib/feature-flags.js +119 -0
- package/dist/src/lib/wizard-session.d.ts +16 -0
- package/dist/src/lib/wizard-session.js +2 -0
- package/dist/src/run.js +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.js +3 -3
- package/dist/src/steps/add-or-update-environment-variables.js +5 -17
- package/dist/src/steps/run-prettier.js +1 -1
- package/dist/src/steps/upload-environment-variables/index.js +2 -2
- package/dist/src/ui/tui/App.js +1 -1
- package/dist/src/ui/tui/components/ConsoleView.js +17 -6
- package/dist/src/ui/tui/components/TitleBar.d.ts +3 -1
- package/dist/src/ui/tui/components/TitleBar.js +17 -6
- package/dist/src/ui/tui/console-commands.d.ts +5 -2
- package/dist/src/ui/tui/console-commands.js +14 -5
- package/dist/src/ui/tui/screens/AuthScreen.d.ts +2 -1
- package/dist/src/ui/tui/screens/AuthScreen.js +166 -26
- package/dist/src/ui/tui/screens/ChecklistScreen.js +1 -1
- package/dist/src/ui/tui/screens/DataIngestionCheckScreen.js +13 -2
- package/dist/src/ui/tui/screens/IntroScreen.js +2 -2
- package/dist/src/ui/tui/screens/McpScreen.js +42 -27
- package/dist/src/ui/tui/screens/OutroScreen.js +1 -2
- package/dist/src/ui/tui/screens/SlackScreen.d.ts +0 -5
- package/dist/src/ui/tui/screens/SlackScreen.js +1 -11
- package/dist/src/ui/tui/store.d.ts +20 -0
- package/dist/src/ui/tui/store.js +68 -19
- package/dist/src/utils/analytics.d.ts +45 -3
- package/dist/src/utils/analytics.js +118 -47
- package/dist/src/utils/oauth.js +1 -1
- package/dist/src/utils/setup-utils.d.ts +11 -0
- package/dist/src/utils/setup-utils.js +81 -4
- package/dist/src/utils/shell-completions.d.ts +2 -2
- package/dist/src/utils/shell-completions.js +8 -1
- package/dist/src/utils/track-wizard-feedback.d.ts +5 -0
- package/dist/src/utils/track-wizard-feedback.js +25 -0
- package/package.json +13 -13
- package/dist/package.json +0 -144
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Feature flags powered by Amplitude Experiment (server-side local evaluation).
|
|
4
|
+
*
|
|
5
|
+
* Flags are fetched once at startup via `initFeatureFlags()` and evaluated
|
|
6
|
+
* synchronously thereafter — no per-check network calls.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.FLAG_AGENT_ANALYTICS = exports.FLAG_LLM_ANALYTICS = void 0;
|
|
10
|
+
exports.initFeatureFlags = initFeatureFlags;
|
|
11
|
+
exports.getFlag = getFlag;
|
|
12
|
+
exports.isFlagEnabled = isFlagEnabled;
|
|
13
|
+
exports.getAllFlags = getAllFlags;
|
|
14
|
+
exports.refreshFlags = refreshFlags;
|
|
15
|
+
const experiment_node_server_1 = require("@amplitude/experiment-node-server");
|
|
16
|
+
const debug_1 = require("../utils/debug");
|
|
17
|
+
// ── Flag keys ────────────────────────────────────────────────────────
|
|
18
|
+
/** Gate for the LLM analytics additional-feature flow. */
|
|
19
|
+
exports.FLAG_LLM_ANALYTICS = 'wizard-llm-analytics';
|
|
20
|
+
/** Gate for agent-level analytics / telemetry instrumented by the wizard. */
|
|
21
|
+
exports.FLAG_AGENT_ANALYTICS = 'wizard-agent-analytics';
|
|
22
|
+
// ── Deployment key ───────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Server deployment key for local evaluation.
|
|
25
|
+
* Override with `AMPLITUDE_EXPERIMENT_DEPLOYMENT_KEY` env var.
|
|
26
|
+
*/
|
|
27
|
+
const DEFAULT_DEPLOYMENT_KEY = 'server-YOTsk4MS1RWzLyIf1DmvNDUsdOGqkRdM';
|
|
28
|
+
function resolveDeploymentKey() {
|
|
29
|
+
const fromEnv = process.env.AMPLITUDE_EXPERIMENT_DEPLOYMENT_KEY;
|
|
30
|
+
return (fromEnv ?? DEFAULT_DEPLOYMENT_KEY).trim();
|
|
31
|
+
}
|
|
32
|
+
// ── Singleton client ─────────────────────────────────────────────────
|
|
33
|
+
let client = null;
|
|
34
|
+
let cachedFlags = {};
|
|
35
|
+
/**
|
|
36
|
+
* Initialize the Experiment local-evaluation client and pre-fetch flag configs.
|
|
37
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
38
|
+
*
|
|
39
|
+
* @param userId Optional user ID for targeted flag evaluation.
|
|
40
|
+
* @param deviceId Optional device ID for targeted flag evaluation.
|
|
41
|
+
*/
|
|
42
|
+
async function initFeatureFlags(userId, deviceId) {
|
|
43
|
+
if (client)
|
|
44
|
+
return; // already initialized
|
|
45
|
+
const deploymentKey = resolveDeploymentKey();
|
|
46
|
+
if (!deploymentKey) {
|
|
47
|
+
(0, debug_1.debug)('feature-flags: no deployment key — all flags default to off');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
client = experiment_node_server_1.Experiment.initializeLocal(deploymentKey);
|
|
52
|
+
await client.start();
|
|
53
|
+
const user = {};
|
|
54
|
+
if (userId)
|
|
55
|
+
user.user_id = userId;
|
|
56
|
+
if (deviceId)
|
|
57
|
+
user.device_id = deviceId;
|
|
58
|
+
const variants = client.evaluateV2(user);
|
|
59
|
+
for (const [key, variant] of Object.entries(variants)) {
|
|
60
|
+
if (variant.value !== undefined && variant.value !== null) {
|
|
61
|
+
cachedFlags[key] = String(variant.value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
(0, debug_1.debug)('feature-flags: initialized with flags', cachedFlags);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
(0, debug_1.debug)('feature-flags: initialization failed, defaulting all flags off', err);
|
|
68
|
+
client = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Evaluate a single feature flag. Returns the string variant value,
|
|
73
|
+
* or `undefined` if the flag is not set / client not initialized.
|
|
74
|
+
*/
|
|
75
|
+
function getFlag(flagKey) {
|
|
76
|
+
return cachedFlags[flagKey];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check whether a flag is enabled (variant is `'on'` or `'true'`).
|
|
80
|
+
* Returns `false` when the flag is absent or the client is not initialized.
|
|
81
|
+
*/
|
|
82
|
+
function isFlagEnabled(flagKey) {
|
|
83
|
+
const value = cachedFlags[flagKey];
|
|
84
|
+
return value === 'on' || value === 'true';
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Return a snapshot of all evaluated flags (key -> string value).
|
|
88
|
+
*/
|
|
89
|
+
function getAllFlags() {
|
|
90
|
+
return { ...cachedFlags };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Re-evaluate flags for a specific user (e.g. after login).
|
|
94
|
+
* Updates the cached flags in place.
|
|
95
|
+
*/
|
|
96
|
+
async function refreshFlags(userId, deviceId) {
|
|
97
|
+
if (!client)
|
|
98
|
+
return;
|
|
99
|
+
try {
|
|
100
|
+
// Re-fetch flag configs in case they changed
|
|
101
|
+
await client.start();
|
|
102
|
+
const user = {};
|
|
103
|
+
if (userId)
|
|
104
|
+
user.user_id = userId;
|
|
105
|
+
if (deviceId)
|
|
106
|
+
user.device_id = deviceId;
|
|
107
|
+
const variants = client.evaluateV2(user);
|
|
108
|
+
cachedFlags = {};
|
|
109
|
+
for (const [key, variant] of Object.entries(variants)) {
|
|
110
|
+
if (variant.value !== undefined && variant.value !== null) {
|
|
111
|
+
cachedFlags[key] = String(variant.value);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
(0, debug_1.debug)('feature-flags: refreshed flags', cachedFlags);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
(0, debug_1.debug)('feature-flags: refresh failed', err);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -132,6 +132,14 @@ export interface WizardSession {
|
|
|
132
132
|
workspaces: Array<{
|
|
133
133
|
id: string;
|
|
134
134
|
name: string;
|
|
135
|
+
environments?: Array<{
|
|
136
|
+
name: string;
|
|
137
|
+
rank: number;
|
|
138
|
+
app: {
|
|
139
|
+
id: string;
|
|
140
|
+
apiKey?: string | null;
|
|
141
|
+
} | null;
|
|
142
|
+
}> | null;
|
|
135
143
|
}>;
|
|
136
144
|
}> | null;
|
|
137
145
|
/** OAuth id_token held during SUSI account-setup steps. */
|
|
@@ -146,6 +154,8 @@ export interface WizardSession {
|
|
|
146
154
|
/** Workspace selected during SUSI (written to ampli.json). */
|
|
147
155
|
selectedWorkspaceId: string | null;
|
|
148
156
|
selectedWorkspaceName: string | null;
|
|
157
|
+
/** Project/environment selected during SUSI (displayed in TitleBar). */
|
|
158
|
+
selectedProjectName: string | null;
|
|
149
159
|
/**
|
|
150
160
|
* Notice shown on the API key entry step of AuthScreen.
|
|
151
161
|
* Set when auto-fetch fails (e.g. user is not an org admin) so the user
|
|
@@ -185,6 +195,12 @@ export interface WizardSession {
|
|
|
185
195
|
* runPhase is set to Completed.
|
|
186
196
|
*/
|
|
187
197
|
amplitudePreDetected: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* While true, McpScreen shows a prompt: skip the agent (default) or run
|
|
200
|
+
* the setup wizard anyway. Cleared when the user chooses or when resetting
|
|
201
|
+
* for a forced wizard run.
|
|
202
|
+
*/
|
|
203
|
+
amplitudePreDetectedChoicePending: boolean;
|
|
188
204
|
/**
|
|
189
205
|
* True once the activation check confirms events are flowing into the project.
|
|
190
206
|
* Set immediately if activationLevel is already 'full', otherwise set after
|
|
@@ -109,6 +109,7 @@ function buildSession(args) {
|
|
|
109
109
|
selectedOrgName: null,
|
|
110
110
|
selectedWorkspaceId: null,
|
|
111
111
|
selectedWorkspaceName: null,
|
|
112
|
+
selectedProjectName: null,
|
|
112
113
|
loginUrl: null,
|
|
113
114
|
credentials: null,
|
|
114
115
|
apiKeyNotice: null,
|
|
@@ -119,6 +120,7 @@ function buildSession(args) {
|
|
|
119
120
|
additionalFeatureQueue: [],
|
|
120
121
|
frameworkConfig: null,
|
|
121
122
|
amplitudePreDetected: false,
|
|
123
|
+
amplitudePreDetectedChoicePending: false,
|
|
122
124
|
dataIngestionConfirmed: false,
|
|
123
125
|
checklistChartComplete: false,
|
|
124
126
|
checklistDashboardComplete: false,
|
package/dist/src/run.js
CHANGED
|
@@ -59,7 +59,7 @@ async function runWizard(argv, session) {
|
|
|
59
59
|
const integration = session.integration ?? (await detectAndResolveIntegration(session));
|
|
60
60
|
session.integration = integration;
|
|
61
61
|
analytics_1.analytics.setTag('integration', integration);
|
|
62
|
-
analytics_1.analytics.wizardCapture('
|
|
62
|
+
analytics_1.analytics.wizardCapture('Session Started', {
|
|
63
63
|
integration,
|
|
64
64
|
ci: session.ci ?? false,
|
|
65
65
|
});
|
|
@@ -58,7 +58,7 @@ const addMCPServerToClientsStep = async ({ integration, local = false, ci = fals
|
|
|
58
58
|
});
|
|
59
59
|
ui.log.success(`Added the MCP server to:
|
|
60
60
|
${supportedClients.map((c) => `- ${c.name}`).join('\n ')} `);
|
|
61
|
-
analytics_1.analytics.wizardCapture('
|
|
61
|
+
analytics_1.analytics.wizardCapture('MCP Servers Added', {
|
|
62
62
|
clients: supportedClients.map((c) => c.name),
|
|
63
63
|
integration,
|
|
64
64
|
});
|
|
@@ -68,7 +68,7 @@ exports.addMCPServerToClientsStep = addMCPServerToClientsStep;
|
|
|
68
68
|
const removeMCPServerFromClientsStep = async ({ integration, local = false, }) => {
|
|
69
69
|
const installedClients = await (0, exports.getInstalledClients)(local);
|
|
70
70
|
if (installedClients.length === 0) {
|
|
71
|
-
analytics_1.analytics.wizardCapture('
|
|
71
|
+
analytics_1.analytics.wizardCapture('MCP No Servers To Remove', {
|
|
72
72
|
integration,
|
|
73
73
|
});
|
|
74
74
|
return [];
|
|
@@ -78,7 +78,7 @@ const removeMCPServerFromClientsStep = async ({ integration, local = false, }) =
|
|
|
78
78
|
await (0, exports.removeMCPServer)(installedClients, local);
|
|
79
79
|
return installedClients.map((c) => c.name);
|
|
80
80
|
});
|
|
81
|
-
analytics_1.analytics.wizardCapture('
|
|
81
|
+
analytics_1.analytics.wizardCapture('MCP Servers Removed', {
|
|
82
82
|
clients: results,
|
|
83
83
|
integration,
|
|
84
84
|
});
|
|
@@ -90,10 +90,7 @@ async function addOrUpdateEnvironmentVariablesStep({ installDir, variables, inte
|
|
|
90
90
|
}
|
|
91
91
|
catch (error) {
|
|
92
92
|
(0, ui_1.getUI)().log.warn(`Failed to update environment variables in ${chalk_1.default.bold.cyan(relativeEnvFilePath)}. Please update them manually.`);
|
|
93
|
-
analytics_1.
|
|
94
|
-
integration,
|
|
95
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
96
|
-
});
|
|
93
|
+
(0, analytics_1.captureWizardError)('Environment Variables', error instanceof Error ? error.message : 'Unknown error', 'add-or-update-env:update-existing', { integration });
|
|
97
94
|
return {
|
|
98
95
|
relativeEnvFilePath,
|
|
99
96
|
addedEnvVariables,
|
|
@@ -112,10 +109,7 @@ async function addOrUpdateEnvironmentVariablesStep({ installDir, variables, inte
|
|
|
112
109
|
}
|
|
113
110
|
catch (error) {
|
|
114
111
|
(0, ui_1.getUI)().log.warn(`Failed to create ${chalk_1.default.bold.cyan(relativeEnvFilePath)} with environment variables. Please add them manually.`);
|
|
115
|
-
analytics_1.
|
|
116
|
-
integration,
|
|
117
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
118
|
-
});
|
|
112
|
+
(0, analytics_1.captureWizardError)('Environment Variables', error instanceof Error ? error.message : 'Unknown error', 'add-or-update-env:create-new', { integration });
|
|
119
113
|
return {
|
|
120
114
|
relativeEnvFilePath,
|
|
121
115
|
addedEnvVariables,
|
|
@@ -141,10 +135,7 @@ async function addOrUpdateEnvironmentVariablesStep({ installDir, variables, inte
|
|
|
141
135
|
}
|
|
142
136
|
catch (error) {
|
|
143
137
|
(0, ui_1.getUI)().log.warn(`Failed to update ${chalk_1.default.bold.cyan('.gitignore')} to include ${chalk_1.default.bold.cyan(envFileName)}.`);
|
|
144
|
-
analytics_1.
|
|
145
|
-
integration,
|
|
146
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
147
|
-
});
|
|
138
|
+
(0, analytics_1.captureWizardError)('Environment Variables', error instanceof Error ? error.message : 'Unknown error', 'add-or-update-env:gitignore-update', { integration });
|
|
148
139
|
return {
|
|
149
140
|
relativeEnvFilePath,
|
|
150
141
|
addedEnvVariables,
|
|
@@ -165,10 +156,7 @@ async function addOrUpdateEnvironmentVariablesStep({ installDir, variables, inte
|
|
|
165
156
|
}
|
|
166
157
|
catch (error) {
|
|
167
158
|
(0, ui_1.getUI)().log.warn(`Failed to create ${chalk_1.default.bold.cyan('.gitignore')} with environment files.`);
|
|
168
|
-
analytics_1.
|
|
169
|
-
integration,
|
|
170
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
171
|
-
});
|
|
159
|
+
(0, analytics_1.captureWizardError)('Environment Variables', error instanceof Error ? error.message : 'Unknown error', 'add-or-update-env:gitignore-create', { integration });
|
|
172
160
|
return {
|
|
173
161
|
relativeEnvFilePath,
|
|
174
162
|
addedEnvVariables,
|
|
@@ -176,7 +164,7 @@ async function addOrUpdateEnvironmentVariablesStep({ installDir, variables, inte
|
|
|
176
164
|
};
|
|
177
165
|
}
|
|
178
166
|
}
|
|
179
|
-
analytics_1.analytics.wizardCapture('
|
|
167
|
+
analytics_1.analytics.wizardCapture('Environment Variables Added', {
|
|
180
168
|
integration,
|
|
181
169
|
});
|
|
182
170
|
return {
|
|
@@ -83,7 +83,7 @@ async function runPrettierStep({ installDir, integration, }) {
|
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
prettierSpinner.stop('Prettier has formatted your files.');
|
|
86
|
-
analytics_1.analytics.wizardCapture('
|
|
86
|
+
analytics_1.analytics.wizardCapture('Prettier Ran', {
|
|
87
87
|
integration,
|
|
88
88
|
});
|
|
89
89
|
});
|
|
@@ -17,7 +17,7 @@ const uploadEnvironmentVariablesStep = async (envVars, { integration, session, }
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
if (!provider) {
|
|
20
|
-
analytics_1.analytics.wizardCapture('
|
|
20
|
+
analytics_1.analytics.wizardCapture('Env Upload Skipped', {
|
|
21
21
|
reason: 'no environment provider found',
|
|
22
22
|
integration,
|
|
23
23
|
});
|
|
@@ -28,7 +28,7 @@ const uploadEnvironmentVariablesStep = async (envVars, { integration, session, }
|
|
|
28
28
|
const results = await (0, telemetry_1.traceStep)('uploading environment variables', async () => {
|
|
29
29
|
return await provider.uploadEnvVars(envVars);
|
|
30
30
|
});
|
|
31
|
-
analytics_1.analytics.wizardCapture('
|
|
31
|
+
analytics_1.analytics.wizardCapture('Env Uploaded', {
|
|
32
32
|
provider: provider.name,
|
|
33
33
|
integration,
|
|
34
34
|
});
|
package/dist/src/ui/tui/App.js
CHANGED
|
@@ -30,5 +30,5 @@ export const App = ({ store }) => {
|
|
|
30
30
|
const contentAreaWidth = Math.max(10, innerWidth - 2);
|
|
31
31
|
const direction = store.lastNavDirection === 'pop' ? 'right' : 'left';
|
|
32
32
|
const activeScreen = screens[store.currentScreen] ?? null;
|
|
33
|
-
return (_jsx(CommandModeContext.Provider, { value: store.commandMode, children: _jsx(Box, { flexDirection: "column", height: rows, width: columns, alignItems: "center", justifyContent: "flex-start", children: _jsxs(ConsoleView, { store: store, width: width, height: rows, children: [_jsx(TitleBar, { version: store.version, width: innerWidth }), _jsx(Box, { height: 1 }), _jsx(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, overflow: "hidden", children: _jsx(DissolveTransition, { transitionKey: store.currentScreen, width: contentAreaWidth, height: contentHeight, direction: direction, children: _jsx(ScreenErrorBoundary, { store: store, retryToken: store.screenErrorRetry, children: activeScreen }) }) })] }) }) }));
|
|
33
|
+
return (_jsx(CommandModeContext.Provider, { value: store.commandMode, children: _jsx(Box, { flexDirection: "column", height: rows, width: columns, alignItems: "center", justifyContent: "flex-start", children: _jsxs(ConsoleView, { store: store, width: width, height: rows, children: [_jsx(TitleBar, { version: store.version, width: innerWidth, orgName: store.session.selectedOrgName, projectName: store.session.selectedProjectName }), _jsx(Box, { height: 1 }), _jsx(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, overflow: "hidden", children: _jsx(DissolveTransition, { transitionKey: store.currentScreen, width: contentAreaWidth, height: contentHeight, direction: direction, children: _jsx(ScreenErrorBoundary, { store: store, retryToken: store.screenErrorRetry, children: activeScreen }) }) })] }) }) }));
|
|
34
34
|
};
|
|
@@ -21,8 +21,9 @@ import { PickerMenu } from '../primitives/PickerMenu.js';
|
|
|
21
21
|
import { Colors, Icons } from '../styles.js';
|
|
22
22
|
import { Overlay } from '../router.js';
|
|
23
23
|
import { queryConsole, resolveConsoleCredentials, buildSessionContext, } from '../../../lib/console-query.js';
|
|
24
|
-
import { COMMANDS, getWhoamiText,
|
|
24
|
+
import { COMMANDS, getWhoamiText, parseFeedbackSlashInput, TEST_PROMPT, } from '../console-commands.js';
|
|
25
25
|
import { analytics } from '../../../utils/analytics.js';
|
|
26
|
+
import { trackWizardFeedback } from '../../../utils/track-wizard-feedback.js';
|
|
26
27
|
function executeCommand(raw, store) {
|
|
27
28
|
const [cmd] = raw.trim().split(/\s+/);
|
|
28
29
|
switch (cmd) {
|
|
@@ -41,6 +42,19 @@ function executeCommand(raw, store) {
|
|
|
41
42
|
case '/slack':
|
|
42
43
|
store.showSlackOverlay();
|
|
43
44
|
break;
|
|
45
|
+
case '/feedback': {
|
|
46
|
+
const message = parseFeedbackSlashInput(raw);
|
|
47
|
+
if (!message) {
|
|
48
|
+
store.setCommandFeedback('Usage: /feedback <your message>');
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
void trackWizardFeedback(message)
|
|
52
|
+
.then(() => store.setCommandFeedback('Thanks — your feedback was sent.'))
|
|
53
|
+
.catch((err) => {
|
|
54
|
+
store.setCommandFeedback(`Could not send feedback: ${err instanceof Error ? err.message : String(err)}`);
|
|
55
|
+
});
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
44
58
|
case '/test':
|
|
45
59
|
return TEST_PROMPT;
|
|
46
60
|
case '/mcp':
|
|
@@ -52,12 +66,9 @@ function executeCommand(raw, store) {
|
|
|
52
66
|
case '/exit':
|
|
53
67
|
store.setOutroData({ kind: OutroKind.Cancel, message: 'Exited.' });
|
|
54
68
|
break;
|
|
55
|
-
case '/help':
|
|
56
|
-
store.setCommandFeedback(getHelpText());
|
|
57
|
-
break;
|
|
58
69
|
default:
|
|
59
70
|
if (cmd)
|
|
60
|
-
store.setCommandFeedback(`Unknown command: ${cmd}. Type /
|
|
71
|
+
store.setCommandFeedback(`Unknown command: ${cmd}. Type / to see available commands.`);
|
|
61
72
|
}
|
|
62
73
|
}
|
|
63
74
|
export const ConsoleView = ({ store, width, height, children, }) => {
|
|
@@ -116,7 +127,7 @@ export const ConsoleView = ({ store, width, height, children, }) => {
|
|
|
116
127
|
}, { isActive: !inputActive });
|
|
117
128
|
const handleSubmit = (value) => {
|
|
118
129
|
const isSlashCommand = value.startsWith('/');
|
|
119
|
-
analytics.wizardCapture('
|
|
130
|
+
analytics.wizardCapture('Agent Message Sent', {
|
|
120
131
|
message_length: value.length,
|
|
121
132
|
is_slash_command: isSlashCommand,
|
|
122
133
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
interface TitleBarProps {
|
|
2
2
|
version: string;
|
|
3
3
|
width: number;
|
|
4
|
+
orgName?: string | null;
|
|
5
|
+
projectName?: string | null;
|
|
4
6
|
}
|
|
5
|
-
export declare const TitleBar: ({ version, width }: TitleBarProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const TitleBar: ({ version, width, orgName, projectName, }: TitleBarProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
8
|
export {};
|
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import { Colors } from '../styles.js';
|
|
4
4
|
const FEEDBACK = 'Feedback: wizard@amplitude.com ';
|
|
5
5
|
const FEEDBACK_SHORT = ' wizard@amplitude.com ';
|
|
6
|
-
export const TitleBar = ({ version, width }) => {
|
|
6
|
+
export const TitleBar = ({ version, width, orgName, projectName, }) => {
|
|
7
7
|
const fullTitle = ` Amplitude Wizard v${version}`;
|
|
8
|
-
|
|
8
|
+
// Build context string from org + project names
|
|
9
|
+
const contextParts = [];
|
|
10
|
+
if (orgName)
|
|
11
|
+
contextParts.push(orgName);
|
|
12
|
+
if (projectName)
|
|
13
|
+
contextParts.push(projectName);
|
|
14
|
+
const contextStr = contextParts.length > 0 ? ` ${contextParts.join(' / ')} ` : '';
|
|
15
|
+
const needShort = width < fullTitle.length + contextStr.length + FEEDBACK.length;
|
|
9
16
|
const feedback = needShort ? FEEDBACK_SHORT : FEEDBACK;
|
|
10
|
-
const title = needShort && fullTitle.length + feedback.length > width
|
|
17
|
+
const title = needShort && fullTitle.length + contextStr.length + feedback.length > width
|
|
11
18
|
? ` Wizard v${version}`
|
|
12
19
|
: fullTitle;
|
|
13
|
-
|
|
20
|
+
// If context doesn't fit even with the short title, drop it
|
|
21
|
+
const showContext = contextStr.length > 0 &&
|
|
22
|
+
title.length + contextStr.length + feedback.length <= width;
|
|
23
|
+
const middleText = showContext ? contextStr : '';
|
|
24
|
+
const gap = Math.max(0, width - title.length - middleText.length - feedback.length);
|
|
14
25
|
const padding = ' '.repeat(gap);
|
|
15
|
-
return (
|
|
26
|
+
return (_jsxs(Box, { width: width, overflow: "hidden", children: [_jsx(Text, { backgroundColor: Colors.accent, color: "white", bold: true, children: title }), middleText ? (_jsxs(Text, { backgroundColor: Colors.accent, color: "white", dimColor: true, children: [padding, middleText] })) : (_jsx(Text, { backgroundColor: Colors.accent, color: "white", children: padding })), _jsx(Text, { backgroundColor: Colors.accent, color: "white", bold: true, children: feedback })] }));
|
|
16
27
|
};
|
|
@@ -12,5 +12,8 @@ export declare const COMMANDS: {
|
|
|
12
12
|
export declare const TEST_PROMPT: string;
|
|
13
13
|
/** Returns the feedback text for the /whoami command. */
|
|
14
14
|
export declare function getWhoamiText(session: Pick<WizardSession, 'selectedOrgName' | 'selectedWorkspaceName' | 'region'>): string;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Parses `/feedback <message>` from a slash command line.
|
|
17
|
+
* Returns `undefined` if the line is not a feedback command or the message is empty.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseFeedbackSlashInput(raw: string): string | undefined;
|
|
@@ -11,10 +11,13 @@ export const COMMANDS = [
|
|
|
11
11
|
{ cmd: '/whoami', desc: 'Show current user, org, and project' },
|
|
12
12
|
{ cmd: '/mcp', desc: 'Install or remove the Amplitude MCP server' },
|
|
13
13
|
{ cmd: '/slack', desc: 'Set up Amplitude Slack integration' },
|
|
14
|
+
{
|
|
15
|
+
cmd: '/feedback',
|
|
16
|
+
desc: 'Send product feedback (event: wizard: feedback submitted)',
|
|
17
|
+
},
|
|
14
18
|
{ cmd: '/test', desc: 'Run a prompt-skill demo (confirm + choose)' },
|
|
15
19
|
{ cmd: '/snake', desc: 'Play Snake' },
|
|
16
20
|
{ cmd: '/exit', desc: 'Exit the wizard' },
|
|
17
|
-
{ cmd: '/help', desc: 'List available slash commands' },
|
|
18
21
|
];
|
|
19
22
|
export const TEST_PROMPT = 'Demo the wizard prompt tools. ' +
|
|
20
23
|
'First, use the wizard-tools:confirm tool to ask if I want to continue. ' +
|
|
@@ -24,8 +27,14 @@ export const TEST_PROMPT = 'Demo the wizard prompt tools. ' +
|
|
|
24
27
|
export function getWhoamiText(session) {
|
|
25
28
|
return `org: ${session.selectedOrgName ?? '(none)'} workspace: ${session.selectedWorkspaceName ?? '(none)'} region: ${session.region ?? '(none)'}`;
|
|
26
29
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Parses `/feedback <message>` from a slash command line.
|
|
32
|
+
* Returns `undefined` if the line is not a feedback command or the message is empty.
|
|
33
|
+
*/
|
|
34
|
+
export function parseFeedbackSlashInput(raw) {
|
|
35
|
+
const m = /^\s*\/feedback(?:\s+(.*))?\s*$/i.exec(raw);
|
|
36
|
+
if (!m)
|
|
37
|
+
return undefined;
|
|
38
|
+
const body = m[1]?.trim();
|
|
39
|
+
return body || undefined;
|
|
31
40
|
}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* 1. OAuth waiting — spinner + login URL while browser auth happens
|
|
6
6
|
* 2. Org selection — picker if the user belongs to multiple orgs
|
|
7
7
|
* 3. Workspace selection — picker if the org has multiple workspaces
|
|
8
|
-
* 4.
|
|
8
|
+
* 4. Project selection — picker if the workspace has multiple environments
|
|
9
|
+
* 5. API key entry — text input (only if no project key could be resolved)
|
|
9
10
|
*
|
|
10
11
|
* The screen drives itself from session.pendingOrgs + session.credentials.
|
|
11
12
|
* When credentials are set the router resolves past this screen.
|