thinkpool-pair 0.7.263 → 0.7.264
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/bridge.mjs +17 -20
- package/dispatch-permission-cleanup.mjs +13 -7
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -3104,23 +3104,20 @@ function cancelPendingDurablePermissions(s, permissionIds = null, reason = 'perm
|
|
|
3104
3104
|
})
|
|
3105
3105
|
}
|
|
3106
3106
|
|
|
3107
|
-
|
|
3107
|
+
let restoredPermissionCleanupPending = false
|
|
3108
3108
|
|
|
3109
|
-
async function cancelRestoredDurablePermissions(
|
|
3110
|
-
|
|
3111
|
-
const
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
}))
|
|
3122
|
-
for (const outcome of outcomes) if (outcome.ok) restoredPermissionCleanupPending.delete(outcome.terminalId)
|
|
3123
|
-
return { ok: restoredPermissionCleanupPending.size === 0, pending: [...restoredPermissionCleanupPending] }
|
|
3109
|
+
async function cancelRestoredDurablePermissions() {
|
|
3110
|
+
restoredPermissionCleanupPending = true
|
|
3111
|
+
const result = await cancelDurablePermissions({
|
|
3112
|
+
supabaseUrl: SUPABASE_URL, anonKey: SUPABASE_ANON, token: codeAuthToken, roomCode: room,
|
|
3113
|
+
// A new process gets a fresh bridge id. Every approval bound to any older
|
|
3114
|
+
// id has lost its process-local resolver, including archived terminals that
|
|
3115
|
+
// no longer have a session file and therefore never enter loadAll().
|
|
3116
|
+
currentBridgeId: BRIDGE_ID, reason: 'bridge_restarted',
|
|
3117
|
+
})
|
|
3118
|
+
if (result.ok) restoredPermissionCleanupPending = false
|
|
3119
|
+
else if (process.env.TP_DEBUG) process.stderr.write(`\n ◇ restored permission cleanup incomplete (${result.code})\n`)
|
|
3120
|
+
return result
|
|
3124
3121
|
}
|
|
3125
3122
|
|
|
3126
3123
|
function drainPending(s) {
|
|
@@ -4065,7 +4062,7 @@ channel
|
|
|
4065
4062
|
// Cancel their durable dispatch rows BEFORE opening a restored SDK
|
|
4066
4063
|
// session, so a new permission raised during resume can never be
|
|
4067
4064
|
// mistaken for a pre-restart card from the same terminal.
|
|
4068
|
-
await cancelRestoredDurablePermissions(
|
|
4065
|
+
await cancelRestoredDurablePermissions()
|
|
4069
4066
|
if (all.length) for (const rec of all) {
|
|
4070
4067
|
const wasInterrupted = restoredTurnOpen(rec.log || [])
|
|
4071
4068
|
// Codex can persist a thread id before its rollout receives the
|
|
@@ -4608,9 +4605,9 @@ if (process.env.THINKPOOL_PAIR_AUTOUPDATE === '1' && VERSION) {
|
|
|
4608
4605
|
})
|
|
4609
4606
|
refreshOwnerPlan()
|
|
4610
4607
|
// A restart sweep may have raced an expiring owner JWT. Keep failed
|
|
4611
|
-
//
|
|
4612
|
-
// retry
|
|
4613
|
-
if (restoredPermissionCleanupPending
|
|
4608
|
+
// room sweep queued until the supervisor hands us its next fresh token,
|
|
4609
|
+
// then retry without leaving archived-terminal questions behind.
|
|
4610
|
+
if (restoredPermissionCleanupPending) void cancelRestoredDurablePermissions()
|
|
4614
4611
|
}
|
|
4615
4612
|
})
|
|
4616
4613
|
setInterval(() => { try { process.send({ t: 'idle', idle: idleNow(), between: betweenTurns(), webPeer: webPeerPresent() }) } catch { /* parent gone */ } }, 5000).unref()
|
|
@@ -9,14 +9,17 @@ const SETTLED = new Set(['denied', 'idempotent_replay', 'already_resolved', 'sta
|
|
|
9
9
|
|
|
10
10
|
const safeString = (value) => typeof value === 'string' && value.length > 0
|
|
11
11
|
|
|
12
|
-
export function pendingDurablePermissionItems (items, { bridgeId = null, terminalId, permissionIds = null, actionKinds = ['approval', 'dispatch'] } = {}) {
|
|
13
|
-
if ((bridgeId != null && !safeString(bridgeId)) || !safeString(
|
|
12
|
+
export function pendingDurablePermissionItems (items, { bridgeId = null, currentBridgeId = null, terminalId = null, permissionIds = null, actionKinds = ['approval', 'dispatch'] } = {}) {
|
|
13
|
+
if ((bridgeId != null && !safeString(bridgeId)) || (currentBridgeId != null && !safeString(currentBridgeId)) ||
|
|
14
|
+
(terminalId != null && !safeString(terminalId)) || (terminalId == null && currentBridgeId == null)) return []
|
|
14
15
|
const requested = permissionIds == null ? null : new Set(permissionIds.filter(safeString))
|
|
15
16
|
const actions = new Set(actionKinds)
|
|
16
17
|
return (Array.isArray(items) ? items : []).filter((item) => {
|
|
17
18
|
const permissionId = item?.request_context?.permission_id
|
|
18
19
|
return PENDING.has(item?.status) && item?.item_kind === 'approval' && actions.has(item?.action_kind) &&
|
|
19
|
-
(!bridgeId || item?.bridge_authority_id === bridgeId) &&
|
|
20
|
+
(!bridgeId || item?.bridge_authority_id === bridgeId) &&
|
|
21
|
+
(!currentBridgeId || item?.bridge_authority_id !== currentBridgeId) &&
|
|
22
|
+
(!terminalId || item?.local_authority_id === terminalId) &&
|
|
20
23
|
safeString(permissionId) && (!requested || requested.has(permissionId))
|
|
21
24
|
})
|
|
22
25
|
}
|
|
@@ -37,10 +40,13 @@ const rpc = async ({ fetchImpl, supabaseUrl, headers, name, body }) => {
|
|
|
37
40
|
// room-member identity. Never accept an id supplied by a public broadcast.
|
|
38
41
|
export async function cancelDurablePermissions ({
|
|
39
42
|
fetchImpl = globalThis.fetch, supabaseUrl, anonKey, token, roomCode, bridgeId,
|
|
40
|
-
|
|
43
|
+
currentBridgeId = null, terminalId = null, permissionIds = null,
|
|
44
|
+
reason = 'permission_aborted', actionKinds = ['approval', 'dispatch'],
|
|
41
45
|
} = {}) {
|
|
42
46
|
if (typeof fetchImpl !== 'function' || !safeString(supabaseUrl) || !safeString(anonKey) ||
|
|
43
|
-
!safeString(token) || !safeString(roomCode) || (bridgeId != null && !safeString(bridgeId)) ||
|
|
47
|
+
!safeString(token) || !safeString(roomCode) || (bridgeId != null && !safeString(bridgeId)) ||
|
|
48
|
+
(currentBridgeId != null && !safeString(currentBridgeId)) ||
|
|
49
|
+
(terminalId != null && !safeString(terminalId)) || (terminalId == null && currentBridgeId == null)) {
|
|
44
50
|
return Object.freeze({ ok: false, code: 'cleanup_unavailable', canceled: 0 })
|
|
45
51
|
}
|
|
46
52
|
if (permissionIds != null && (!Array.isArray(permissionIds) || !permissionIds.length)) {
|
|
@@ -51,7 +57,7 @@ export async function cancelDurablePermissions ({
|
|
|
51
57
|
const listed = await rpc({ fetchImpl, supabaseUrl, headers, name: 'list_code_pair_controls', body: {
|
|
52
58
|
p_session_code: String(roomCode).toUpperCase(), p_status: null, p_limit: 100,
|
|
53
59
|
} })
|
|
54
|
-
const candidates = pendingDurablePermissionItems(listed, { bridgeId, terminalId, permissionIds, actionKinds })
|
|
60
|
+
const candidates = pendingDurablePermissionItems(listed, { bridgeId, currentBridgeId, terminalId, permissionIds, actionKinds })
|
|
55
61
|
const outcomes = await Promise.all(candidates.map(async (item) => {
|
|
56
62
|
const result = await rpc({ fetchImpl, supabaseUrl, headers, name: 'resolve_code_pair_control', body: {
|
|
57
63
|
p_item_id: item.id,
|
|
@@ -63,7 +69,7 @@ export async function cancelDurablePermissions ({
|
|
|
63
69
|
// by its immutable authority binding, so resolve it with that exact
|
|
64
70
|
// value after the owner-authenticated RLS list—not a guessed current ID.
|
|
65
71
|
p_bridge_authority_id: item.bridge_authority_id,
|
|
66
|
-
p_local_authority_id:
|
|
72
|
+
p_local_authority_id: item.local_authority_id,
|
|
67
73
|
p_idempotency_key: `cancel-permission:${item.id}:${reason}`.slice(0, 160),
|
|
68
74
|
} })
|
|
69
75
|
return { id: item.id, code: result?.code || 'invalid_response', ok: Boolean(result?.ok) && SETTLED.has(result.code) }
|