thinkpool-pair 0.7.158 → 0.7.159
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/account.mjs +19 -12
- package/package.json +1 -1
- package/serve-consent.mjs +12 -0
package/account.mjs
CHANGED
|
@@ -16,6 +16,7 @@ import os from 'node:os'
|
|
|
16
16
|
import { saveAuth, loadAuth, loadDirs, bindDir, loadServed, rememberServed, loadDefaultDir, saveDefaultDir, claudeRecentProjectDir } from './auth-store.mjs'
|
|
17
17
|
import { isSafeToRestart } from './update-gate.mjs'
|
|
18
18
|
import { makeThrottledTrack } from './presence.mjs'
|
|
19
|
+
import { supervisorServes } from './serve-consent.mjs'
|
|
19
20
|
import { resolveServeDir } from './serve-dir.mjs'
|
|
20
21
|
import { pairKeyFor, pairTopic, CROSSROOM_BUS } from './cross-terminal.mjs'
|
|
21
22
|
|
|
@@ -529,26 +530,32 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
529
530
|
return
|
|
530
531
|
}
|
|
531
532
|
let rooms = []
|
|
533
|
+
const me = session.user.id
|
|
532
534
|
try {
|
|
533
|
-
//
|
|
534
|
-
// it
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
539
|
-
|
|
535
|
+
// Discovery (Contract C-CODE-2, evolved owner-only → owner-OR-granted): a host
|
|
536
|
+
// bridges the sessions it OWNS *plus* any it has been explicitly granted to serve
|
|
537
|
+
// (code_sessions.serve_grant_uid = me — the owner-consent grant, #206/#208). RLS
|
|
538
|
+
// returns owned OR participant rooms, and a grantee is ALWAYS a participant
|
|
539
|
+
// (set_serve_grant requires it), so a granted row is visible to this login. Without
|
|
540
|
+
// a filter the supervisor would auto-serve rooms you merely JOINED as a guest —
|
|
541
|
+
// spawning your machine into another owner's session that already runs its own
|
|
542
|
+
// bridge; the .or keeps un-granted joins out while letting a consented grant IN.
|
|
543
|
+
// The web watches tpacct:<session-owner>; a granted bridge serves on the owner's
|
|
544
|
+
// behalf (the grant IS the consent), so it is wanted duplication, not stray.
|
|
545
|
+
const { data } = await sb.from('code_sessions').select('code,name,last_active_at,owner_id,serve_grant_uid,participants').or(`owner_id.eq.${me},serve_grant_uid.eq.${me}`).order('last_active_at', { ascending: false }).limit(20)
|
|
540
546
|
rooms = data || []
|
|
541
|
-
// Prune refused entries for rooms we no longer
|
|
542
|
-
// so a transient query error never wipes the set).
|
|
543
|
-
const
|
|
544
|
-
for (const c of [...refused.keys()]) if (!
|
|
547
|
+
// Prune refused entries for rooms we can no longer serve — owned OR granted (only
|
|
548
|
+
// on a SUCCESSFUL fetch, so a transient query error never wipes the set).
|
|
549
|
+
const servableCodes = new Set(rooms.map((r) => r.code))
|
|
550
|
+
for (const c of [...refused.keys()]) if (!servableCodes.has(c)) refused.delete(c)
|
|
545
551
|
} catch { /* transient — keep existing children, retry next tick */ }
|
|
546
552
|
const dirs = loadDirs()
|
|
547
553
|
const served = loadServed()
|
|
548
554
|
for (const r of rooms) {
|
|
549
555
|
const room = r.code
|
|
550
556
|
if (!room || children.has(room)) { if (room) refused.delete(room); continue } // served → not refused
|
|
551
|
-
|
|
557
|
+
// Defense-in-depth behind the .or above: serve iff we OWN the room or hold its grant.
|
|
558
|
+
if (!supervisorServes({ ownerId: r.owner_id, grantUid: r.serve_grant_uid, myUid: me })) continue
|
|
552
559
|
// Resolve the serve dir: explicit bind > last-served memory > launch dir. REFUSE
|
|
553
560
|
// to auto-serve an unbound room from $HOME — that strips the agent's resume context
|
|
554
561
|
// (cwd-keyed SDK sessions) and shows your home folder as the repo (FVIHV1DE).
|
package/package.json
CHANGED
package/serve-consent.mjs
CHANGED
|
@@ -35,6 +35,18 @@ export function serveDecision ({ ownerId, grantUid, myUid }) {
|
|
|
35
35
|
return { serve: false, reason: 'not-granted' }
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// supervisorServes — the account supervisor's per-row discovery decision: may this
|
|
39
|
+
// login auto-serve THIS discovered room? True iff the login OWNS the room or HOLDS its
|
|
40
|
+
// serve grant. This is the defense-in-depth per-row check behind the supervisor's
|
|
41
|
+
// `.or(owner_id.eq.me,serve_grant_uid.eq.me)` query — a broad RLS row (owned OR merely
|
|
42
|
+
// participant) must still resolve to owned-or-granted before a child is spawned. Mirrors
|
|
43
|
+
// serveDecision's owner|grant serve set, evaluated against a discovery row rather than a
|
|
44
|
+
// gate fetch (Contract C-CODE-2, evolved owner-only → owner-or-granted).
|
|
45
|
+
export function supervisorServes ({ ownerId, grantUid, myUid }) {
|
|
46
|
+
if (!myUid) return false
|
|
47
|
+
return ownerId === myUid || grantUid === myUid
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
// amGrantee — this bridge serves by grant (not as owner). Grantees are the only
|
|
39
51
|
// bridges that ever stand down; the owner's bridge never yields.
|
|
40
52
|
export function amGrantee ({ ownerId, grantUid, myUid }) {
|