thinkpool-pair 0.7.151 → 0.7.152
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 +21 -2
- package/package.json +1 -1
- package/sdk-smoke.mjs +1 -0
package/bridge.mjs
CHANGED
|
@@ -988,11 +988,25 @@ const mockupSeen = new Map() // `${term}/${slug}` → mtimeMs of the last mani
|
|
|
988
988
|
// in the Map" guess meant closing the generating terminal moved the cards to
|
|
989
989
|
// whatever terminal was now first — they leaked into Terminal 1.)
|
|
990
990
|
const handleManifest = async (box, file, term) => {
|
|
991
|
-
|
|
991
|
+
// Ignore our own delivery receipts — writing <slug>.receipt.json into the
|
|
992
|
+
// watched outbox re-fires fs.watch; without this guard it would re-trigger
|
|
993
|
+
// handleManifest in a loop (it still ends in .json). Must come first.
|
|
994
|
+
if (!file || file.endsWith('.receipt.json') || !file.endsWith('.json')) return
|
|
992
995
|
const full = path.join(box, file)
|
|
993
996
|
let stat
|
|
994
997
|
try { stat = fs.statSync(full) } catch { return } // tmp/removed mid-write
|
|
995
998
|
const slug = file.replace(/\.json$/, '')
|
|
999
|
+
// Delivery receipt (atomic tmp+mv) so render.sh can confirm the card actually
|
|
1000
|
+
// reached the room — written on success AND failure. Best-effort: a receipt
|
|
1001
|
+
// that can't be written just leaves render.sh at "delivery unconfirmed".
|
|
1002
|
+
const writeReceipt = (ok, status) => {
|
|
1003
|
+
try {
|
|
1004
|
+
const rc = path.join(box, `${slug}.receipt.json`)
|
|
1005
|
+
const tmp = `${rc}.tmp`
|
|
1006
|
+
fs.writeFileSync(tmp, JSON.stringify({ ok, status, ts: Date.now() }))
|
|
1007
|
+
fs.renameSync(tmp, rc)
|
|
1008
|
+
} catch { /* receipts are best-effort */ }
|
|
1009
|
+
}
|
|
996
1010
|
const seenKey = `${term}/${slug}`
|
|
997
1011
|
if (mockupSeen.get(seenKey) === stat.mtimeMs) return // already handled
|
|
998
1012
|
mockupSeen.set(seenKey, stat.mtimeMs)
|
|
@@ -1017,11 +1031,16 @@ const handleManifest = async (box, file, term) => {
|
|
|
1017
1031
|
desktopPng: readB64(m.desktop), mobilePng: readB64(m.mobile), html: readTxt(m.html),
|
|
1018
1032
|
}),
|
|
1019
1033
|
})
|
|
1020
|
-
if (!res.ok) {
|
|
1034
|
+
if (!res.ok) {
|
|
1035
|
+
writeReceipt(false, res.status)
|
|
1036
|
+
process.stderr.write(`\n ◇ mockup "${m.slug}" upload failed (${res.status}).\n`); return
|
|
1037
|
+
}
|
|
1021
1038
|
const { paths } = await res.json()
|
|
1022
1039
|
bcast('code-event', { term, evt: { kind: 'mockup', __struct: true, cid, term, slug: m.slug, title: m.title || m.slug, ts: m.ts, paths } })
|
|
1040
|
+
writeReceipt(true, 200)
|
|
1023
1041
|
process.stderr.write(`\n ◆ mockup "${m.title || m.slug}" pushed to the room.\n`)
|
|
1024
1042
|
} catch (e) {
|
|
1043
|
+
writeReceipt(false, 'error')
|
|
1025
1044
|
process.stderr.write(`\n ◇ mockup "${m.slug}" send failed: ${e?.message || e}\n`)
|
|
1026
1045
|
}
|
|
1027
1046
|
}
|
package/package.json
CHANGED
package/sdk-smoke.mjs
CHANGED
|
@@ -46,6 +46,7 @@ const version = ver()
|
|
|
46
46
|
try {
|
|
47
47
|
const sdk = await import('@anthropic-ai/claude-agent-sdk')
|
|
48
48
|
if (typeof sdk.query !== 'function') { emit('FAIL', version, 'query is not a function'); clearTimeout(guard); process.exit(1) }
|
|
49
|
+
// eslint-disable-next-line require-yield -- deliberately empty: an async generator that ends immediately (the SDK's "no input" stream), never yields.
|
|
49
50
|
async function* noInput() { return } // ends immediately — never blocks the construct
|
|
50
51
|
const q = sdk.query({ prompt: noInput(), options: { permissionMode: 'default' } })
|
|
51
52
|
const need = ['interrupt', 'setModel', 'setPermissionMode', 'supportedModels']
|