thinkpool-pair 0.7.300 → 0.7.302
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 +22 -3
- package/codex-session.mjs +1 -2
- package/package.json +1 -1
- package/serve-consent.mjs +22 -2
package/account.mjs
CHANGED
|
@@ -17,7 +17,7 @@ import { saveAuth, loadAuth, loadDirs, bindDir, loadServed, rememberServed, load
|
|
|
17
17
|
import { isSafeToRestart } from './update-gate.mjs'
|
|
18
18
|
import { makeThrottledTrack, presenceSelfEchoVerdict } from './presence.mjs'
|
|
19
19
|
import { publicKeyB64, announceProviders, listProviders, addProvider, addProviderModel, removeProvider, unseal } from './providers.mjs'
|
|
20
|
-
import { supervisorServes } from './serve-consent.mjs'
|
|
20
|
+
import { supervisorServes, supervisorRoomsToStop } from './serve-consent.mjs'
|
|
21
21
|
import { resolveServeDir } from './serve-dir.mjs'
|
|
22
22
|
import { pairKeyFor, pairTopic, CROSSROOM_BUS } from './cross-terminal.mjs'
|
|
23
23
|
import { installedAgentCommands } from './agent-detect.mjs'
|
|
@@ -798,6 +798,7 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
798
798
|
return
|
|
799
799
|
}
|
|
800
800
|
let rooms = []
|
|
801
|
+
let discoverySucceeded = false
|
|
801
802
|
const me = session.user.id
|
|
802
803
|
try {
|
|
803
804
|
// Discovery (Contract C-CODE-2, owner-only since 2026-07-06): a host bridges ONLY
|
|
@@ -805,20 +806,38 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
805
806
|
// keeps rooms you merely JOINED as a guest out of auto-serve — your machine never
|
|
806
807
|
// spawns into another owner's session (cross-person serving removed; pairing is
|
|
807
808
|
// read-only peer peek, not hosting). The web watches tpacct:<session-owner>.
|
|
808
|
-
const { data } = await sb.from('code_sessions')
|
|
809
|
+
const { data, error } = await sb.from('code_sessions')
|
|
810
|
+
.select('code,name,last_active_at,owner_id,participants,closed_at')
|
|
811
|
+
.eq('owner_id', me)
|
|
812
|
+
.is('closed_at', null)
|
|
813
|
+
.order('last_active_at', { ascending: false })
|
|
814
|
+
.limit(20)
|
|
815
|
+
if (error) throw error
|
|
809
816
|
rooms = data || []
|
|
817
|
+
discoverySucceeded = true
|
|
810
818
|
// Prune refused entries for rooms we can no longer serve — owned OR granted (only
|
|
811
819
|
// on a SUCCESSFUL fetch, so a transient query error never wipes the set).
|
|
812
820
|
const servableCodes = new Set(rooms.map((r) => r.code))
|
|
813
821
|
for (const c of [...refused.keys()]) if (!servableCodes.has(c)) refused.delete(c)
|
|
814
822
|
} catch { /* transient — keep existing children, retry next tick */ }
|
|
823
|
+
// The realtime shutdown broadcast is an acceleration, never the lifecycle
|
|
824
|
+
// authority. Reconcile every successful discovery read so a bridge that missed
|
|
825
|
+
// `session-deleted` still stops after its room is closed, deleted, or transferred.
|
|
826
|
+
if (discoverySucceeded) {
|
|
827
|
+
for (const room of supervisorRoomsToStop({ rooms, childRooms: children.keys(), myUid: me })) {
|
|
828
|
+
const child = children.get(room)
|
|
829
|
+
if (!child) continue
|
|
830
|
+
console.log(`child_retire sup=${SUP_ID} room=${room} pid=${child.pid || '?'} reason=not-active-owned`)
|
|
831
|
+
try { child.kill('SIGTERM') } catch { /* child exit reconciliation retries next tick */ }
|
|
832
|
+
}
|
|
833
|
+
}
|
|
815
834
|
const dirs = loadDirs()
|
|
816
835
|
const served = loadServed()
|
|
817
836
|
for (const r of rooms) {
|
|
818
837
|
const room = r.code
|
|
819
838
|
if (!room || children.has(room)) { if (room) refused.delete(room); continue } // served → not refused
|
|
820
839
|
// Defense-in-depth behind the owner-only query above: serve iff we OWN the room.
|
|
821
|
-
if (!supervisorServes({ ownerId: r.owner_id, myUid: me })) continue
|
|
840
|
+
if (!supervisorServes({ ownerId: r.owner_id, myUid: me, closedAt: r.closed_at })) continue
|
|
822
841
|
// Resolve the serve dir: explicit bind > last-served memory > launch dir. REFUSE
|
|
823
842
|
// to auto-serve an unbound room from $HOME — that strips the agent's resume context
|
|
824
843
|
// (cwd-keyed SDK sessions) and shows your home folder as the repo (FVIHV1DE).
|
package/codex-session.mjs
CHANGED
|
@@ -577,14 +577,13 @@ export function startCodexSession({ cwd, model, effort: initialEffort = 'high',
|
|
|
577
577
|
appServerThreadReady = true
|
|
578
578
|
pushMappedEvent({ type: 'thread.started', thread_id: sessionId })
|
|
579
579
|
return true
|
|
580
|
-
} catch
|
|
580
|
+
} catch {
|
|
581
581
|
// Fallback is safe only here: no turn/start request has been accepted, so
|
|
582
582
|
// there is no possibility of running the same prompt twice.
|
|
583
583
|
appServerDisabled = true
|
|
584
584
|
try { appServer?.end() } catch { /* noop */ }
|
|
585
585
|
appServer = null
|
|
586
586
|
appServerThreadReady = false
|
|
587
|
-
note(`Codex App Server unavailable; using codex exec: ${error?.message || error}`)
|
|
588
587
|
return false
|
|
589
588
|
}
|
|
590
589
|
}
|
package/package.json
CHANGED
package/serve-consent.mjs
CHANGED
|
@@ -38,9 +38,29 @@ export function serveDecision ({ ownerId, myUid }) {
|
|
|
38
38
|
// defense-in-depth per-row check behind the supervisor's owner-only `.eq(owner_id, me)`
|
|
39
39
|
// query — a broad RLS row (owned OR merely participant) must still resolve to OWNED
|
|
40
40
|
// before a child is spawned. Contract C-CODE-2 (owner-only).
|
|
41
|
-
export function supervisorServes ({ ownerId, myUid }) {
|
|
41
|
+
export function supervisorServes ({ ownerId, myUid, closedAt = null }) {
|
|
42
42
|
if (!myUid) return false
|
|
43
|
-
return ownerId === myUid
|
|
43
|
+
return ownerId === myUid && !closedAt
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// supervisorRoomsToStop — reconcile the long-lived child map after a SUCCESSFUL
|
|
47
|
+
// discovery read. Closing, deleting, or transferring a room removes it from the
|
|
48
|
+
// active-owned result set; any existing child for that room must be retired even
|
|
49
|
+
// when the best-effort `session-deleted` realtime broadcast was missed.
|
|
50
|
+
//
|
|
51
|
+
// This stays pure so a transient discovery failure can be handled by the caller:
|
|
52
|
+
// account.mjs invokes it only after Supabase returned without an error. On a failed
|
|
53
|
+
// fetch the existing children stay alive and the next tick retries.
|
|
54
|
+
export function supervisorRoomsToStop ({ rooms, childRooms, myUid }) {
|
|
55
|
+
const activeOwned = new Set((rooms || [])
|
|
56
|
+
.filter((room) => supervisorServes({
|
|
57
|
+
ownerId: room?.owner_id,
|
|
58
|
+
myUid,
|
|
59
|
+
closedAt: room?.closed_at,
|
|
60
|
+
}))
|
|
61
|
+
.map((room) => room.code)
|
|
62
|
+
.filter(Boolean))
|
|
63
|
+
return [...(childRooms || [])].filter((code) => !activeOwned.has(code))
|
|
44
64
|
}
|
|
45
65
|
|
|
46
66
|
// fetchServeRow — read the room's owner with whatever identity the bridge holds
|