thinkpool-pair 0.7.218 → 0.7.219
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 +4 -1
- package/design-edit.mjs +38 -0
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -65,7 +65,7 @@ import { writeLaneArtifact, digestSlice, appendDigest, resumeLane } from './flow
|
|
|
65
65
|
import { createFlowWorktree, worktreeSpec } from './flow-worktree.mjs'
|
|
66
66
|
import { startPreview, stopAllPreviews, previews } from './flow-preview.mjs'
|
|
67
67
|
import { ViewportManager, createViewportTools, sharedViewportBrowser } from './viewport.mjs'
|
|
68
|
-
import { designPrompt, resolveDesignSource, syncRealtimeAuth, validateDesignRequest } from './design-edit.mjs'
|
|
68
|
+
import { designPrompt, resolveDesignSource, restoreDesignSources, syncRealtimeAuth, validateDesignRequest } from './design-edit.mjs'
|
|
69
69
|
// FL-M9 — per-lane preview servers leak (one per done lane, never stopped until shutdown).
|
|
70
70
|
// Lane previews are keyed `lane:<flowId>:<laneId>`; stop a whole flow's set when it assembles
|
|
71
71
|
// (the assembled preview supersedes them) or when a lane is reverted.
|
|
@@ -1862,6 +1862,9 @@ function openStructured({ id, runtime = 'claude', model, effort, resume, log, co
|
|
|
1862
1862
|
// they land on this session even after other terminals open/close.
|
|
1863
1863
|
const mockupOutbox = ownerOutbox('sessions', id)
|
|
1864
1864
|
entry.mockupWatcher = watchOutbox(mockupOutbox, () => id, true)
|
|
1865
|
+
const restoredDesigns = restoreDesignSources(mockupOutbox, cwd || process.cwd(), id)
|
|
1866
|
+
for (const record of restoredDesigns) designArtifacts.set(record.previewId, record)
|
|
1867
|
+
if (restoredDesigns.length) process.stderr.write(`\n ◆ restored ${restoredDesigns.length} Thinkpool Design artifact${restoredDesigns.length === 1 ? '' : 's'} (${id.slice(0, 8)}).\n`)
|
|
1865
1868
|
// Visual QA runs in the bridge process, outside either agent runtime's sandbox.
|
|
1866
1869
|
// It remains scoped to this lane's cwd and private mockup outbox.
|
|
1867
1870
|
entry.viewport = new ViewportManager({ workspaceRoot: cwd || process.cwd(), ownerId: id, outbox: mockupOutbox })
|
package/design-edit.mjs
CHANGED
|
@@ -48,6 +48,44 @@ export function resolveDesignSource(file, workspaceRoot) {
|
|
|
48
48
|
return { previewId, revision, sourcePath, workspaceRoot: root, source }
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// Design provenance is intentionally host-only, but it must survive a bridge
|
|
52
|
+
// restart. Rebuild the in-memory registry from manifests already written by the
|
|
53
|
+
// trusted lane render workflow; do not re-upload or re-broadcast old cards.
|
|
54
|
+
export function restoreDesignSources(box, workspaceRoot, term, limit = 100) {
|
|
55
|
+
if (!box || !workspaceRoot || !term) return []
|
|
56
|
+
let files
|
|
57
|
+
try {
|
|
58
|
+
files = fs.readdirSync(box, { withFileTypes: true })
|
|
59
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.json') && !entry.name.endsWith('.receipt.json'))
|
|
60
|
+
.map((entry) => {
|
|
61
|
+
const file = path.join(box, entry.name)
|
|
62
|
+
return { file, mtimeMs: fs.statSync(file).mtimeMs }
|
|
63
|
+
})
|
|
64
|
+
.sort((a, b) => b.mtimeMs - a.mtimeMs)
|
|
65
|
+
.slice(0, Math.max(0, limit))
|
|
66
|
+
} catch { return [] }
|
|
67
|
+
const restored = []
|
|
68
|
+
for (const { file } of files) {
|
|
69
|
+
try {
|
|
70
|
+
const manifest = JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
71
|
+
if (!manifest?.source) continue
|
|
72
|
+
const record = resolveDesignSource(manifest.source, workspaceRoot)
|
|
73
|
+
if (!record) continue
|
|
74
|
+
Object.assign(record, {
|
|
75
|
+
term,
|
|
76
|
+
slug: String(manifest.slug || ''),
|
|
77
|
+
title: String(manifest.title || manifest.slug || ''),
|
|
78
|
+
desktop: manifest.desktop || null,
|
|
79
|
+
mobile: manifest.mobile || null,
|
|
80
|
+
})
|
|
81
|
+
const backupPath = path.join(box, '.design-revisions', `${record.revision}.html`)
|
|
82
|
+
if (fs.existsSync(backupPath)) record.backupPath = backupPath
|
|
83
|
+
restored.push(record)
|
|
84
|
+
} catch { /* stale or malformed manifests are ignored */ }
|
|
85
|
+
}
|
|
86
|
+
return restored
|
|
87
|
+
}
|
|
88
|
+
|
|
51
89
|
function safeTarget(value) {
|
|
52
90
|
if (!value || typeof value !== 'object') return null
|
|
53
91
|
const rect = value.rect && typeof value.rect === 'object' ? {
|