spudmobile-bridge 1.0.2 → 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,10 +168,12 @@ 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
- // Try finding by pair_code first (8-char hex codes)
176
+ // Try finding by pair_code first (8-char hex codes from other IDEs)
175
177
  let pair = null;
176
178
  const { data: byCode } = await this.client
177
179
  .from('device_pairs')
@@ -182,7 +184,7 @@ export class SupabaseBridge {
182
184
  pair = byCode;
183
185
  }
184
186
  else {
185
- // Fallback: the token might be ios_device_id (UUID from the connect edge function)
187
+ // Fallback: the token might be ios_device_id (UUID from connect edge function)
186
188
  const { data: byDevice } = await this.client
187
189
  .from('device_pairs')
188
190
  .select('id')
@@ -193,8 +195,28 @@ export class SupabaseBridge {
193
195
  .single();
194
196
  pair = byDevice;
195
197
  }
198
+ // If no pair exists, create one (SpudMobile flow: iOS sends userId directly)
196
199
  if (!pair) {
197
- throw new Error(`Pair not found for code: ${pairCode}`);
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;
198
220
  }
199
221
  const { error: updateError } = await this.client
200
222
  .from('device_pairs')
@@ -257,16 +279,16 @@ export class SupabaseBridge {
257
279
  * Subscribe to new user messages for processing
258
280
  */
259
281
  subscribeToMessages(onNewMessage, onCancellation) {
260
- if (!this.pairId)
261
- throw new Error('Not paired');
282
+ if (!this.userId)
283
+ throw new Error('No user_id resolved');
262
284
  // Realtime subscription
263
285
  this.messageChannel = this.client
264
- .channel(`bridge-messages-${this.pairId}`)
286
+ .channel(`bridge-messages-${this.userId}`)
265
287
  .on('postgres_changes', {
266
288
  event: 'INSERT',
267
289
  schema: 'public',
268
290
  table: 'messages',
269
- filter: `pair_id=eq.${this.pairId}`,
291
+ filter: `user_id=eq.${this.userId}`,
270
292
  }, (payload) => {
271
293
  const msg = payload.new;
272
294
  if (msg.role === 'user' && msg.status === 'pending' && !this.processedMessageIds.has(msg.id)) {
@@ -278,7 +300,7 @@ export class SupabaseBridge {
278
300
  event: 'UPDATE',
279
301
  schema: 'public',
280
302
  table: 'messages',
281
- filter: `pair_id=eq.${this.pairId}`,
303
+ filter: `user_id=eq.${this.userId}`,
282
304
  }, (payload) => {
283
305
  const msg = payload.new;
284
306
  if (msg.is_cancelled) {
@@ -375,7 +397,7 @@ export class SupabaseBridge {
375
397
  */
376
398
  startPresenceHeartbeat() {
377
399
  const upsertPresence = async () => {
378
- const userId = this.pairId || this.deviceId;
400
+ const userId = this.userId || this.pairId || this.deviceId;
379
401
  await this.client
380
402
  .from('ide_presence')
381
403
  .upsert({
@@ -391,12 +413,12 @@ export class SupabaseBridge {
391
413
  * Check if there are pending messages to process (on startup or polling)
392
414
  */
393
415
  async getPendingMessages() {
394
- if (!this.pairId)
416
+ if (!this.userId)
395
417
  return [];
396
418
  const { data, error } = await this.client
397
419
  .from('messages')
398
420
  .select('*')
399
- .eq('pair_id', this.pairId)
421
+ .eq('user_id', this.userId)
400
422
  .eq('role', 'user')
401
423
  .eq('status', 'pending')
402
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.2",
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",