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 +1 -0
- package/dist/index.js +1 -1
- package/dist/supabase.d.ts +3 -1
- package/dist/supabase.js +51 -12
- package/package.json +1 -1
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 = {
|
package/dist/supabase.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 (
|
|
180
|
-
|
|
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.
|
|
244
|
-
throw new Error('
|
|
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.
|
|
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: `
|
|
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: `
|
|
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.
|
|
416
|
+
if (!this.userId)
|
|
378
417
|
return [];
|
|
379
418
|
const { data, error } = await this.client
|
|
380
419
|
.from('messages')
|
|
381
420
|
.select('*')
|
|
382
|
-
.eq('
|
|
421
|
+
.eq('user_id', this.userId)
|
|
383
422
|
.eq('role', 'user')
|
|
384
423
|
.eq('status', 'pending')
|
|
385
424
|
.order('created_at', { ascending: true });
|