spudmobile-bridge 1.0.1 → 1.0.3

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/codex.js CHANGED
@@ -61,6 +61,7 @@ export function runCodex(prompt, cliPath, options = {}, onChunk) {
61
61
  cwd: options.cwd || process.cwd(),
62
62
  env: { ...process.env },
63
63
  stdio: ['pipe', 'pipe', 'pipe'],
64
+ shell: true,
64
65
  });
65
66
  // Close stdin immediately — exec mode doesn't need it
66
67
  if (proc.stdin) {
package/dist/index.js CHANGED
@@ -233,7 +233,7 @@ function handleCancellation(messageId) {
233
233
  }
234
234
  // ─── Model Mapping ────────────────────────────────────────
235
235
  function mapModel(model) {
236
- if (!model || model.toLowerCase() === 'default')
236
+ if (!model || model.toLowerCase() === 'default' || model.toLowerCase() === 'unknown')
237
237
  return undefined;
238
238
  // Map iOS model names to Codex CLI model flags
239
239
  const mapping = {
@@ -59,7 +59,9 @@ export declare class SupabaseBridge {
59
59
  */
60
60
  isPairActive(pairId: string): Promise<boolean>;
61
61
  /**
62
- * Activate a device pair using the pair code from callback
62
+ * Activate a device pair using the pair code from callback.
63
+ * For SpudMobile, the token is the iOS device UUID and no device_pairs row
64
+ * exists yet — the bridge creates one.
63
65
  */
64
66
  activatePair(pairCode: string): Promise<string>;
65
67
  /**
package/dist/supabase.js CHANGED
@@ -168,16 +168,55 @@ export class SupabaseBridge {
168
168
  }
169
169
  }
170
170
  /**
171
- * Activate a device pair using the pair code from callback
171
+ * Activate a device pair using the pair code from callback.
172
+ * For SpudMobile, the token is the iOS device UUID and no device_pairs row
173
+ * exists yet — the bridge creates one.
172
174
  */
173
175
  async activatePair(pairCode) {
174
- const { data: pair, error: findError } = await this.client
176
+ // Try finding by pair_code first (8-char hex codes from other IDEs)
177
+ let pair = null;
178
+ const { data: byCode } = await this.client
175
179
  .from('device_pairs')
176
180
  .select('id')
177
181
  .eq('pair_code', pairCode)
178
182
  .single();
179
- if (findError || !pair) {
180
- throw new Error(`Pair not found for code: ${pairCode}`);
183
+ if (byCode) {
184
+ pair = byCode;
185
+ }
186
+ else {
187
+ // Fallback: the token might be ios_device_id (UUID from connect edge function)
188
+ const { data: byDevice } = await this.client
189
+ .from('device_pairs')
190
+ .select('id')
191
+ .ilike('ios_device_id', pairCode)
192
+ .eq('is_active', true)
193
+ .order('created_at', { ascending: false })
194
+ .limit(1)
195
+ .single();
196
+ pair = byDevice;
197
+ }
198
+ // If no pair exists, create one (SpudMobile flow: iOS sends userId directly)
199
+ if (!pair) {
200
+ const shortCode = pairCode.slice(0, 8);
201
+ const { data: newPair, error: insertError } = await this.client
202
+ .from('device_pairs')
203
+ .insert({
204
+ pair_code: shortCode,
205
+ ios_device_id: pairCode.toUpperCase(),
206
+ mac_device_id: this.deviceId,
207
+ paired_at: new Date().toISOString(),
208
+ is_active: true,
209
+ })
210
+ .select('id')
211
+ .single();
212
+ if (insertError || !newPair) {
213
+ throw new Error(`Failed to create pair: ${insertError?.message}`);
214
+ }
215
+ this.pairId = newPair.id;
216
+ this.userId = pairCode.toLowerCase();
217
+ saveConfig({ pairId: newPair.id, pairCode: shortCode });
218
+ console.log(`👤 iOS user_id: ${this.userId.slice(0, 8)}…`);
219
+ return newPair.id;
181
220
  }
182
221
  const { error: updateError } = await this.client
183
222
  .from('device_pairs')
@@ -240,16 +279,16 @@ export class SupabaseBridge {
240
279
  * Subscribe to new user messages for processing
241
280
  */
242
281
  subscribeToMessages(onNewMessage, onCancellation) {
243
- if (!this.pairId)
244
- throw new Error('Not paired');
282
+ if (!this.userId)
283
+ throw new Error('No user_id resolved');
245
284
  // Realtime subscription
246
285
  this.messageChannel = this.client
247
- .channel(`bridge-messages-${this.pairId}`)
286
+ .channel(`bridge-messages-${this.userId}`)
248
287
  .on('postgres_changes', {
249
288
  event: 'INSERT',
250
289
  schema: 'public',
251
290
  table: 'messages',
252
- filter: `pair_id=eq.${this.pairId}`,
291
+ filter: `user_id=eq.${this.userId}`,
253
292
  }, (payload) => {
254
293
  const msg = payload.new;
255
294
  if (msg.role === 'user' && msg.status === 'pending' && !this.processedMessageIds.has(msg.id)) {
@@ -261,7 +300,7 @@ export class SupabaseBridge {
261
300
  event: 'UPDATE',
262
301
  schema: 'public',
263
302
  table: 'messages',
264
- filter: `pair_id=eq.${this.pairId}`,
303
+ filter: `user_id=eq.${this.userId}`,
265
304
  }, (payload) => {
266
305
  const msg = payload.new;
267
306
  if (msg.is_cancelled) {
@@ -358,7 +397,7 @@ export class SupabaseBridge {
358
397
  */
359
398
  startPresenceHeartbeat() {
360
399
  const upsertPresence = async () => {
361
- const userId = this.pairId || this.deviceId;
400
+ const userId = this.userId || this.pairId || this.deviceId;
362
401
  await this.client
363
402
  .from('ide_presence')
364
403
  .upsert({
@@ -374,12 +413,12 @@ export class SupabaseBridge {
374
413
  * Check if there are pending messages to process (on startup or polling)
375
414
  */
376
415
  async getPendingMessages() {
377
- if (!this.pairId)
416
+ if (!this.userId)
378
417
  return [];
379
418
  const { data, error } = await this.client
380
419
  .from('messages')
381
420
  .select('*')
382
- .eq('pair_id', this.pairId)
421
+ .eq('user_id', this.userId)
383
422
  .eq('role', 'user')
384
423
  .eq('status', 'pending')
385
424
  .order('created_at', { ascending: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spudmobile-bridge",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Bridge between OpenAI Codex CLI and SpudMobile iOS app via Supabase",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",