vesper-wizard 2.0.4 → 2.0.5

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/wizard.js +49 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vesper-wizard",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "Zero-friction setup wizard for Vesper — local MCP server, unified dataset API, and agent auto-config in 60 seconds",
5
5
  "bin": {
6
6
  "vesper-wizard": "wizard.js"
package/wizard.js CHANGED
@@ -91,12 +91,34 @@ function httpJson(method, url, body) {
91
91
  });
92
92
  }
93
93
 
94
- async function canReachDeviceAuth(baseUrl) {
94
+ async function probeDeviceAuth(baseUrl) {
95
95
  try {
96
96
  const res = await httpJson('POST', `${baseUrl}/api/auth/device/start`);
97
- return res.status === 201 && !!res.body && !!res.body.code;
98
- } catch {
99
- return false;
97
+ if (res.status === 201 && !!res.body && !!res.body.code) {
98
+ return { baseUrl, status: 'ready', response: res.body };
99
+ }
100
+
101
+ if (res.status === 503 && res.body && res.body.requiresSetup) {
102
+ return {
103
+ baseUrl,
104
+ status: 'setup-required',
105
+ response: res.body,
106
+ message: res.body.error || 'Auth storage is not initialized.',
107
+ };
108
+ }
109
+
110
+ return {
111
+ baseUrl,
112
+ status: 'unreachable',
113
+ response: res.body,
114
+ message: typeof res.body === 'string' ? res.body : JSON.stringify(res.body),
115
+ };
116
+ } catch (error) {
117
+ return {
118
+ baseUrl,
119
+ status: 'unreachable',
120
+ message: error && error.message ? error.message : 'Request failed',
121
+ };
100
122
  }
101
123
  }
102
124
 
@@ -105,13 +127,20 @@ async function resolveVesperApiBaseUrl() {
105
127
  ? [VESPER_API_URL]
106
128
  : DEFAULT_VESPER_API_CANDIDATES;
107
129
 
130
+ let setupRequiredProbe = null;
131
+
108
132
  for (const candidate of candidates) {
109
- if (await canReachDeviceAuth(candidate)) {
110
- return candidate;
133
+ const probe = await probeDeviceAuth(candidate);
134
+ if (probe.status === 'ready') {
135
+ return probe;
136
+ }
137
+
138
+ if (!setupRequiredProbe && probe.status === 'setup-required') {
139
+ setupRequiredProbe = probe;
111
140
  }
112
141
  }
113
142
 
114
- return null;
143
+ return setupRequiredProbe;
115
144
  }
116
145
 
117
146
  function openBrowser(url) {
@@ -149,16 +178,25 @@ async function deviceAuthFlow() {
149
178
  return null;
150
179
  }
151
180
 
152
- console.log(` ${dim('Auth endpoint:')} ${dim(resolvedApiBaseUrl)}\n`);
181
+ if (resolvedApiBaseUrl.status === 'setup-required') {
182
+ console.log(` ${yellow('!')} ${yellow('Reached Vesper auth endpoint, but local auth storage is not initialized.')}`);
183
+ console.log(` ${dim('Endpoint:')} ${dim(resolvedApiBaseUrl.baseUrl)}`);
184
+ console.log(` ${dim('Reason:')} ${dim(resolvedApiBaseUrl.message || 'Apply Supabase migrations first.')}`);
185
+ console.log(` ${dim('Run the SQL in supabase/migrations/001_device_auth.sql and 002_rate_limits.sql, then retry.')}`);
186
+ console.log(` ${dim('Falling back to local-only mode.\n')}`);
187
+ return null;
188
+ }
189
+
190
+ console.log(` ${dim('Auth endpoint:')} ${dim(resolvedApiBaseUrl.baseUrl)}\n`);
153
191
 
154
192
  // Step 1: Call /api/auth/device/start
155
193
  process.stdout.write(` ${dim('Requesting device code...')}`);
156
194
  let startRes;
157
195
  try {
158
- startRes = await httpJson('POST', `${resolvedApiBaseUrl}/api/auth/device/start`);
196
+ startRes = await httpJson('POST', `${resolvedApiBaseUrl.baseUrl}/api/auth/device/start`);
159
197
  } catch (err) {
160
198
  console.log(` ${red('✗')}`);
161
- console.log(` ${red('Could not reach Vesper API at')} ${dim(resolvedApiBaseUrl)}`);
199
+ console.log(` ${red('Could not reach Vesper API at')} ${dim(resolvedApiBaseUrl.baseUrl)}`);
162
200
  console.log(` ${dim('Falling back to local-only mode.\n')}`);
163
201
  return null;
164
202
  }
@@ -198,7 +236,7 @@ async function deviceAuthFlow() {
198
236
  process.stdout.write(`\r ${cyan(frame)} Polling... (${polls})`);
199
237
 
200
238
  try {
201
- const pollRes = await httpJson('GET', `${resolvedApiBaseUrl}/api/auth/device/poll?code=${code}`);
239
+ const pollRes = await httpJson('GET', `${resolvedApiBaseUrl.baseUrl}/api/auth/device/poll?code=${code}`);
202
240
 
203
241
  if (pollRes.body.status === 'confirmed' && pollRes.body.apiKey) {
204
242
  process.stdout.write(`\r ${green('✓')} Device authenticated! \n`);