thinkpool-pair 0.7.354 → 0.7.356

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.
@@ -9,6 +9,7 @@
9
9
  // tells a fresh agent WHEN ThinkPool expects each capability without requiring
10
10
  // the people in the room to know a tool name or summon word.
11
11
  import { THINKPOOL_CAPABILITY_ROUTES, THINKPOOL_PROMPT_BUNDLE, thinkPoolCapabilityContract } from './thinkpool-prompt-contracts.mjs'
12
+ import { buildContextManifest, formatRoomContextProjection } from './context-contract.mjs'
12
13
 
13
14
  export { THINKPOOL_CAPABILITY_ROUTES, THINKPOOL_PROMPT_BUNDLE }
14
15
 
@@ -113,7 +114,7 @@ export function createRoomContextSelector(roomContext) {
113
114
  return ({ force = false } = {}) => {
114
115
  let context = null
115
116
  try { context = typeof roomContext === 'function' ? roomContext() : roomContext } catch { context = null }
116
- const value = String(context || '').trim()
117
+ const value = formatRoomContextProjection(context)
117
118
  if (!value) return ''
118
119
  const fingerprint = roomContextFingerprint(value)
119
120
  const changed = fingerprint !== previousFingerprint
@@ -122,6 +123,21 @@ export function createRoomContextSelector(roomContext) {
122
123
  }
123
124
  }
124
125
 
126
+ // A caller can inspect the deterministic selection without retaining its raw
127
+ // text. The manifest contains only allow-listed source kinds and safe refs.
128
+ export function buildThinkPoolContextManifest({ currentUserTurn = '', roomNow = '', flowSliceDigest = null, approvedHumanResponse = null } = {}) {
129
+ const roomProjection = formatRoomContextProjection(roomNow)
130
+ return buildContextManifest({
131
+ promptBundle: THINKPOOL_PROMPT_BUNDLE,
132
+ sources: [
133
+ { kind: 'current_user_turn', value: currentUserTurn },
134
+ { kind: 'room_now_delta', value: roomProjection },
135
+ ...(flowSliceDigest ? [{ kind: 'flow_slice_digest', value: flowSliceDigest, ref: { type: 'flow_digest', id: 'local' } }] : []),
136
+ ...(approvedHumanResponse ? [{ kind: 'approved_human_response', value: approvedHumanResponse, ref: { type: 'control_item', id: 'approved' } }] : []),
137
+ ],
138
+ })
139
+ }
140
+
125
141
  // One authoritative terminal-identity preamble for every structured runtime.
126
142
  // The bridge derives this from durable structural metadata — never from the text
127
143
  // of the task handed to the model. That distinction matters because a spawned
package/viewport.mjs CHANGED
@@ -17,6 +17,10 @@ import os from 'node:os'
17
17
  import path from 'node:path'
18
18
  import { randomUUID } from 'node:crypto'
19
19
  import { previews, startPreview } from './flow-preview.mjs'
20
+ import {
21
+ DESIGN_SOURCE_MAP_RELATIVE,
22
+ MAX_DESIGN_SOURCE_MAP_BYTES,
23
+ } from './design-source-contract.mjs'
20
24
 
21
25
  export const DEFAULT_VIEWPORTS = Object.freeze({
22
26
  desktop: Object.freeze({ width: 1440, height: 900 }),
@@ -51,6 +55,18 @@ export async function resolveContainedRoot(workspaceRoot, requested = 'dist') {
51
55
  return resolved
52
56
  }
53
57
 
58
+ export async function resolvePreviewSourceMap(previewRoot) {
59
+ if (!previewRoot) return null
60
+ let root, sourceMap
61
+ try {
62
+ root = await fsp.realpath(previewRoot)
63
+ sourceMap = await fsp.realpath(path.join(root, DESIGN_SOURCE_MAP_RELATIVE))
64
+ const stat = await fsp.stat(sourceMap)
65
+ if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_DESIGN_SOURCE_MAP_BYTES) return null
66
+ } catch { return null }
67
+ return isInside(root, sourceMap) ? sourceMap : null
68
+ }
69
+
54
70
  export function normalizeRoute(value = '/') {
55
71
  const route = String(value || '/').trim()
56
72
  if (!route.startsWith('/') || route.startsWith('//')) throw new Error('Preview path must start with one "/" and cannot be a URL.')
@@ -674,11 +690,13 @@ export class ViewportManager {
674
690
  if (snapshotPath) await fsp.writeFile(snapshotPath, snapshot)
675
691
  let manifestPath = null
676
692
  if (cardReady) {
693
+ const sourceMap = await resolvePreviewSourceMap(this.root)
677
694
  const manifest = {
678
695
  slug, title: String(title || 'Viewport capture').slice(0, 120),
679
696
  desktop: captures.desktop.file, mobile: captures.mobile.file, ts: Date.now(),
680
697
  sourceKind: 'preview', deliveryIntent: 'card', readinessValidated: true,
681
698
  snapshot: snapshotPath, previewRoot, route: normalizedRoute, captureKey,
699
+ ...(sourceMap ? { sourceMap } : {}),
682
700
  ...correlation,
683
701
  }
684
702
  manifestPath = path.join(this.outbox, `${slug}.json`)