thinkpool-pair 0.7.242 → 0.7.243
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 +12 -4
- package/cross-terminal.mjs +12 -2
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -105,7 +105,7 @@ const flowRedispatch = new Map()
|
|
|
105
105
|
// wave BEFORE overrun. Lives bridge-side because waves dispatch across separate
|
|
106
106
|
// broadcasts; without persistent state the cap can never bite.
|
|
107
107
|
const flowBudgets = new Map()
|
|
108
|
-
import { formatPeek, PEEK, siblingsOf, resolveSibling, crossPostDecision, CROSSPOST, spawnDecision, SPAWN, CROSSROOM, formatPairRoster, crossRoomPostDecision, formatRoomNow, formatClosableHint, laneStatusOf, nativeClaudeFallbackHint } from './cross-terminal.mjs'
|
|
108
|
+
import { formatPeek, PEEK, siblingsOf, resolveSibling, crossPostDecision, CROSSPOST, spawnDecision, SPAWN, CROSSROOM, formatPairRoster, crossRoomPostDecision, formatRoomNow, formatClosableHint, closeLaneDecision, laneStatusOf, nativeClaudeFallbackHint } from './cross-terminal.mjs'
|
|
109
109
|
import { dispatchPendingRecap, recoverInterruptedTurn, recoverMissingResumeOnce, sendInterruptedContinue, shouldAttemptNativeResume, supersedeInterruptedResume } from './interrupted-resume.mjs'
|
|
110
110
|
import { turnInFlight } from './update-gate.mjs'
|
|
111
111
|
import { saveSession, flushSession, deleteSession, loadAll, canResume, loadPtyId, savePtyId, loadNames, saveNames, appendDurableEvents, seedDurableEvents, readDurablePage, readDurableOldestSeq, hasDurableArchive, servesHistoryPage } from './session-store.mjs'
|
|
@@ -2296,7 +2296,7 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2296
2296
|
ref: String(sid).slice(0, 8),
|
|
2297
2297
|
name: termNames[sid] || undefined,
|
|
2298
2298
|
spawnedBy: s.spawnedBy,
|
|
2299
|
-
busy: s.session?.turnActive ?? false,
|
|
2299
|
+
busy: (s.session?.turnActive ?? false) || (s.pending?.size ?? 0) > 0,
|
|
2300
2300
|
}))))
|
|
2301
2301
|
// Record this spawn, pruning timestamps that have already left the window
|
|
2302
2302
|
// (identical predicate to recentSpawnCount) so the array can't grow unbounded.
|
|
@@ -2376,7 +2376,7 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2376
2376
|
// the web's code-close), which no-ops if the id isn't a live session.
|
|
2377
2377
|
...(!entry.flowRole ? [tool(
|
|
2378
2378
|
'close_terminal',
|
|
2379
|
-
'Close an agent lane that YOU opened with spawn_terminal (identified by ref/id/name). You can only close lanes you spawned yourself — never a sibling someone else is working in, and never the main terminal.
|
|
2379
|
+
'Close an IDLE agent lane that YOU opened with spawn_terminal (identified by ref/id/name). Active turns and permission waits are protected: collect the completed result with read_terminal before closing. You can only close lanes you spawned yourself — never a sibling someone else is working in, and never the main terminal.',
|
|
2380
2380
|
{
|
|
2381
2381
|
terminal: z.string().describe('ref, id, or name of the lane you spawned (from read_terminal)'),
|
|
2382
2382
|
},
|
|
@@ -2387,7 +2387,15 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
|
|
|
2387
2387
|
if (!target) return okText(`No terminal matches "${args?.terminal}". Call read_terminal with no argument to list the open terminals.`)
|
|
2388
2388
|
const te = sessions.get(target.id)
|
|
2389
2389
|
if (!te) return okText(`Terminal ${target.ref} is not an agent lane (or already closed) — only spawned agent lanes can be closed this way.`)
|
|
2390
|
-
|
|
2390
|
+
const close = closeLaneDecision({
|
|
2391
|
+
callerId: id,
|
|
2392
|
+
spawnedBy: te.spawnedBy,
|
|
2393
|
+
busy: (te.session?.turnActive ?? false) || (te.pending?.size ?? 0) > 0,
|
|
2394
|
+
})
|
|
2395
|
+
if (!close.ok && close.reason === 'not-owner') return okText(`Terminal ${target.ref} was not opened by you — you can only close lanes you spawned yourself. Leave it to the person running it.`)
|
|
2396
|
+
if (!close.ok && close.reason === 'busy') {
|
|
2397
|
+
return okText(`Terminal ${target.ref} is still working or waiting for a permission decision. close_terminal will not kill an active turn. Wait until read_terminal reports it idle/completed, collect its result, then close it. If it is genuinely stuck, ask a person to press Stop.`)
|
|
2398
|
+
}
|
|
2391
2399
|
endStructured(target.id)
|
|
2392
2400
|
return okText(`Closed agent lane ${target.ref}${target.name ? ` ("${target.name}")` : ''}.`)
|
|
2393
2401
|
},
|
package/cross-terminal.mjs
CHANGED
|
@@ -220,7 +220,7 @@ export const formatPeek = ({ selfId, sessions, terms, names = {}, terminal, line
|
|
|
220
220
|
} else {
|
|
221
221
|
body = cleanPtyTail(hit.buf, n).join('\n') || '(no output yet)'
|
|
222
222
|
}
|
|
223
|
-
return `Terminal ${label(hit)} (${hit.kind} · ${hit.cmd}) — last ${n} lines:\n${body}`
|
|
223
|
+
return `Terminal ${label(hit)} (${hit.kind} · ${hit.cmd}) · ${laneStatusText(hit)} — last ${n} lines:\n${body}`
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// A native Claude Code account failure is provider-wide, not model-specific. Retrying
|
|
@@ -417,8 +417,18 @@ export const spawnDecision = ({ hop = 0, spawnTimes = [], now = 0, spawnedLive =
|
|
|
417
417
|
// Only lanes this caller spawned are suggested: close_terminal refuses the others, and
|
|
418
418
|
// suggesting a sibling's lane is how you get an agent killing someone else's work.
|
|
419
419
|
export const CLOSABLE_HINT_MAX = 6
|
|
420
|
+
export const closeLaneDecision = ({ callerId, spawnedBy, busy } = {}) => {
|
|
421
|
+
if (!callerId || spawnedBy !== callerId) return { ok: false, reason: 'not-owner' }
|
|
422
|
+
if (busy) return { ok: false, reason: 'busy' }
|
|
423
|
+
return { ok: true }
|
|
424
|
+
}
|
|
425
|
+
|
|
420
426
|
export const closableLanes = (callerId, lanes = []) =>
|
|
421
|
-
(Array.isArray(lanes) ? lanes : []).filter((l) => l &&
|
|
427
|
+
(Array.isArray(lanes) ? lanes : []).filter((l) => l && closeLaneDecision({
|
|
428
|
+
callerId,
|
|
429
|
+
spawnedBy: l.spawnedBy,
|
|
430
|
+
busy: l.busy,
|
|
431
|
+
}).ok)
|
|
422
432
|
|
|
423
433
|
export const formatClosableHint = (callerId, lanes = [], max = CLOSABLE_HINT_MAX) => {
|
|
424
434
|
const idle = closableLanes(callerId, lanes)
|