thinkpool-pair 0.7.210 → 0.7.211

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.
@@ -21,6 +21,7 @@ import { sanitizeSession } from './transcript-sanitize.mjs'
21
21
  import { reviewGatePreToolDecision } from './flow-review-gate.mjs'
22
22
  import { crossPostNeedsCard } from './cross-terminal.mjs'
23
23
  import { correctContext } from './context-windows.mjs'
24
+ import { THINKPOOL_REMOTE_DELIVERY_RULES } from './thinkpool-room-prompt.mjs'
24
25
  import { stallDecision, stallEvent, isCompactTurn } from './turn-stall.mjs'
25
26
 
26
27
  // The caret-pulled SDK's real version (^0.3.x auto-upgrades on restart). Resolved
@@ -700,13 +701,7 @@ export function startClaudeSession({ cwd, model, effort: initialEffort = 'high',
700
701
  // never plan-mode's approval card. Trivial asks stay single-lane with zero ceremony.
701
702
  'DEFAULT BUILD WORKFLOW (this IS your standard behaviour — no keyword and no "flow" word is ever required to trigger it; you infer it from the request itself). RIGHT-SIZE to the task, always: a TRIVIAL ask — a one-line fix, a small tweak, a question — you just do it directly, with no plan and no extra lanes (never tax small work with ceremony). A NON-TRIVIAL build that genuinely decomposes — you FIRST write a short plan as a normal chat message (the approach, the concrete slices, and what you will verify), THEN fan the independent slices out into their own visible lanes with spawn_terminal, build, and self-verify each slice before calling it done.',
702
703
  'CRUCIAL RECONCILIATION for that workflow: it is NOT plan mode. Never call ExitPlanMode and never make the room wait behind a "plan ready — approve to start" card — your plan lives in the CHAT as a message, and your lanes live in the room\'s EXISTING terminal/lane list. Reuse only those two surfaces; there is no new Flow panel or mode to switch into, and you must not ask for one. Keep the plan and the lanes VISIBLE — that shared visibility is the whole point (it is the pair differentiator, and it catches bugs a single silent lane would hide); never collapse a decomposable build into one hidden lane just to look tidy.',
703
- 'LINKS & ARTIFACTS (hard rule for ThinkPool Code rooms): the room is driven from a phone or browser, and the bridge runs on the host machine — so a local filesystem path, a file:// URL, or a localhost address only opens on the host and is useless to the room (a partner literally cannot open it).',
704
- 'Whenever you produce an HTML artifact (a demo, mockup, preview, report, or page) or surface ANY link meant to be opened or shared, NEVER hand the room a local path, a file:// URL, or a localhost/127.0.0.1 address. Publish it to a GitHub-shareable URL that renders in a browser — push the HTML to a GitHub repo and give its GitHub Pages URL (or an equivalent raw-HTML URL that actually renders, not raw.githubusercontent.com which serves HTML as plain text) — so anyone in the room can open it. The same applies to any other link you surface: it must be one the room can reach, not a host-only path.',
705
- 'If you cannot publish a shareable link, say so and ask how to proceed — do not fall back to handing over a local path.',
706
- 'SHOW YOUR WORK, do not just describe it: the room is watched live from a phone, where a wall of text is painful to read. Whenever you build, change, or fix anything visual — a UI, a page, an HTML artifact, a chart, a diagram, a rendered result — capture a screenshot and surface the PNG (for example, read the image file into your turn) so it appears inline in the room. The room auto-uploads any image you surface. Default to showing a picture of the result over narrating it; err toward more screenshots, not fewer.',
707
- 'BRIDGE VIEWPORTS: for a built web UI, use preview_start (default root: dist), then preview_capture for exact desktop 1440×900 + mobile 390×844 screenshots, and preview_inspect when DOM text or selector geometry helps. These tools run in the bridge, so they work even when your lane sandbox cannot bind localhost or launch Chrome. They only serve built files inside your own lane workspace; run the project build first. Stop the server with preview_stop when you are done.',
708
- 'HTML PREVIEWS: for any HTML you produce, give the room something it can actually open, by whichever path is available. (a) IN-ROOM PREVIEW: if a mockup render helper is present — one that writes a manifest into the directory named by $TP_MOCKUP_OUTBOX, such as the mockup-iterate render.sh script when the bridge was launched from the thinkpool repo — use it; it surfaces an inline card with desktop and mobile views that the room can expand. (b) SHAREABLE LINK: additionally or otherwise, publish the HTML to a GitHub Pages URL per the LINKS & ARTIFACTS rule above and post the link. Never leave an HTML artifact viewable only as a local path.',
709
- 'RUN IT, DO NOT ASK: verify your own work before calling it done. Actually run or serve what you changed, observe that it behaves correctly, and show the evidence in the room — a screenshot of the running result, the passing test output, or the real response — rather than telling the user "this should work, go test it." If you could not verify something, say exactly what is unverified. This room follows verify-before-claiming: runtime evidence you produced, not assertion.',
704
+ ...THINKPOOL_REMOTE_DELIVERY_RULES,
710
705
  'CROSS-TERMINAL AWARENESS: this room may have other terminals open alongside yours — other agents working, or shells the people are driving. You have a READ-ONLY tool, read_terminal: call it with no arguments to list the other open terminals, or with a terminal ref/id/command to read that terminal\'s recent activity. Reach for it when your work depends on what another terminal is doing (e.g. someone says "see what the other terminal hit", or you need to coordinate with a sibling agent before acting). It only ever reads — it never changes another terminal. Identify a terminal by its NAME or its ref/id from the roster, never by an on-screen number like "Terminal 2" — those positional labels renumber when a terminal is closed, so they do not reliably point at a lane.',
711
706
  'CROSS-TERMINAL HAND-OFF: you also have post_to_terminal(terminal, text) to send a message or task to ANOTHER AGENT terminal in this room (not a plain shell). Use it sparingly and only when the people clearly want the lanes to coordinate — e.g. "tell the backend terminal the API is ready", or to hand a sibling agent a concrete task. Every post requires a person in the room to approve a card before it is delivered, and an agent that was itself reached via a cross-post cannot post onward — so do not rely on it for chit-chat or loops. Prefer read_terminal to understand a sibling before you ever post to it.',
712
707
  'CROSS-TERMINAL SPAWN: when a person asks you to fan work out across multiple agents — research lanes, parallel sub-tasks, a swarm — open YOUR OWN fresh lanes with spawn_terminal(name?, task?, model?); do NOT dump the work into siblings that are already busy (a sibling is mid-task unless read_terminal shows it idle, and hijacking it derails their work). spawn_terminal opens a brand-new Claude lane and, if you pass `task`, hands it that task immediately; it appears as a new terminal in the room. A spawned lane INHERITS your current permission mode by default — so if you are in bypass, your lanes run autonomously with no per-action clicking; pass `mode` only to override. Raising a lane to bypass from a non-bypass lane asks the room to confirm once (everything else spawns without a prompt). Collect each lane\'s result later with read_terminal (a spawned lane cannot post back to you). CLOSING IS PART OF THE JOB, not housekeeping you get to skip: the moment you have read a lane\'s result and acted on it, close_terminal it. A finished lane left open holds a slot against the room\'s machine cap and against your dispatch ceiling, so the NEXT fan-out — yours, or a person\'s — gets refused; rooms silt up with dead lanes exactly this way. Before each new wave of spawns, list your open lanes (read_terminal with no argument) and close the finished ones first. If a spawn is refused for capacity, the refusal names your own idle lanes so you do not have to hunt. You may only close lanes you spawned yourself — never close a sibling\'s, and never close one that is mid-turn. You are bounded: a sliding spawn-burst window, a per-plan dispatch ceiling on concurrent spawned lanes (Free 3 / Plus 6) that is separate from the human terminals so it never blocks them, an overall machine cap on live lanes, and a DEPTH bound — a lane opened by a person may spawn workers, and those workers may spawn one further level (a conductor dispatching its crew), but that second level can never spawn onward (so no runaway). This is how you "open the terminals yourself" instead of asking a person to.',
@@ -716,7 +711,6 @@ export function startClaudeSession({ cwd, model, effort: initialEffort = 'high',
716
711
  'RESEARCH LANE: you have a `research` tool that runs a REAL multi-source web search + adversarial verification and returns each claim marked HELD or REJECTED with citations. Reach for it when the people would genuinely benefit from looking something external up or settling a question of current fact — pricing, "is X still maintained / deprecated", "is that benchmark real", a debate over facts you are not sure of. Do NOT run it unprompted or for things you already know: first OFFER in plain language ("want me to spawn a research lane on that and check it?"), and only call `research(question)` once they agree — it spends real budget (plan-gated Free 5 / Plus 100 runs a month) and takes ~a minute. When it returns, present the held/rejected findings clearly and invite both people to weigh the sources, flagging any held claim that rests on a source they might not trust — that shared scrutiny is the point.',
717
712
  'PEER FIRST: other lanes may be working in the same repo as you, right now. Before starting substantive work — and before any code edit that could overlap another lane — check what the room is doing: the ROOM NOW snapshot appended to your latest turn, or read_terminal for detail; list_sessions/read_session when the question spans your other rooms. If a sibling is touching the same files or branch, coordinate (read its lane, or raise it in chat) instead of colliding.',
718
713
  'WORKTREES: parallel lanes share one machine and usually one repo. Run `git worktree list` before your first code edit; if linked worktrees exist, the shared main checkout is contended (and may be guard-blocked) — do your work in your OWN worktree on your OWN branch (`git worktree add <dir> -b <branch>`), and never edit a checkout or ride a branch another lane is using.',
719
- 'REMOTE USER: the people driving this room may be on a phone, with NO terminal and no access to this host. Never ask them to run a local command, open a local file, or "go check" something on the machine — anything that must run on the host, you run yourself and show the output in the room. Only suggest actions they can actually do from the room UI or a browser.',
720
714
  'WRITE PLANS INTO THE CHAT: whenever you form or revise a plan — because the room is in Plan mode, or because someone asked you to plan, design, or think it through first — write the actual plan out as a normal message in the room as you develop it: the approach, the concrete steps, the files you will touch, the open questions. The room does NOT surface plan files at all, and the plan-approval card does not reliably carry the plan text, so a plan that lives only in a plan file or only inside ExitPlanMode is INVISIBLE to the people you are working with — they just see "plan ready" with no content. The chat is the canonical place your plan lives; put it there so the room can read and react to it before you proceed.',
721
715
  ].join(' '),
722
716
  // Needed for live thinking-token progress (SDKThinkingTokensMessage) to
package/codex-session.mjs CHANGED
@@ -29,6 +29,7 @@ import path from 'node:path'
29
29
  import readline from 'node:readline'
30
30
  import { CodexEventMapper } from './codex-event-mapper.mjs'
31
31
  import { startCodexMcpHttp } from './codex-mcp-http.mjs'
32
+ import { CODEX_THINKPOOL_FIRST_TURN_PREAMBLE } from './thinkpool-room-prompt.mjs'
32
33
 
33
34
  const DEFAULT_SANDBOX = 'workspace-write'
34
35
  const SAFE_SANDBOXES = new Set(['read-only', 'workspace-write', 'danger-full-access'])
@@ -169,9 +170,13 @@ export function codexPublishAccess({ cwd, env = process.env, tmpdir = os.tmpdir(
169
170
  }
170
171
  }
171
172
 
172
- export function buildCodexPrompt({ text, rolePrompt, roomContext }) {
173
+ export function buildCodexPrompt({ text, rolePrompt, roomContext, firstTurn = false }) {
173
174
  const context = typeof roomContext === 'function' ? roomContext() : roomContext
174
- const additions = [rolePrompt, context].map((v) => String(v || '').trim()).filter(Boolean)
175
+ const additions = [
176
+ firstTurn ? CODEX_THINKPOOL_FIRST_TURN_PREAMBLE : '',
177
+ rolePrompt,
178
+ context,
179
+ ].map((v) => String(v || '').trim()).filter(Boolean)
175
180
  if (!additions.length) return String(text ?? '')
176
181
  return `<thinkpool-context>\n${additions.join('\n\n')}\n</thinkpool-context>\n\n${String(text ?? '')}`
177
182
  }
@@ -342,7 +347,7 @@ export function startCodexSession({ cwd, model, effort: initialEffort = 'high',
342
347
  // Claude receives these through the Agent SDK's system-reminder path.
343
348
  // Codex is one-shot per turn, so give it the same lane identity and live
344
349
  // room awareness in a compact envelope before the person's text.
345
- await runExec(buildCodexPrompt({ text: next, rolePrompt, roomContext }))
350
+ await runExec(buildCodexPrompt({ text: next, rolePrompt, roomContext, firstTurn: turnNo === 0 }))
346
351
  turnNo++
347
352
  pump()
348
353
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.210",
3
+ "version": "0.7.211",
4
4
  "description": "Share a local coding-agent CLI (Claude Code, Codex, Gemini, Aider, …) into a ThinkPool Code room, live.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "context-windows.mjs",
15
15
  "claude-session.mjs",
16
16
  "codex-session.mjs",
17
+ "thinkpool-room-prompt.mjs",
17
18
  "codex-mcp-http.mjs",
18
19
  "lane-worktree.mjs",
19
20
  "codex-event-mapper.mjs",
@@ -0,0 +1,19 @@
1
+ // Shared delivery contract for structured agents running inside ThinkPool Code.
2
+ // Claude receives this as part of its system prompt; Codex receives it ahead of
3
+ // the first human turn in each fresh native thread. Keep the runtime-specific
4
+ // orchestration rules in their own drivers — these are the cross-runtime truths
5
+ // about where the people are and how finished work must reach them.
6
+ export const THINKPOOL_REMOTE_DELIVERY_RULES = Object.freeze([
7
+ 'REMOTE USER (authoritative default for ThinkPool Code rooms): unless a person explicitly says they are at the host machine, assume everyone driving this room is remote — possibly on a phone — with no terminal and no access to the host filesystem. Never ask them to run a local command, open a local file, or "go check" something on the machine. Anything host-side, you run yourself and show the result in the room. Only suggest actions they can actually do from the room UI or a browser.',
8
+ 'LINKS & ARTIFACTS: a local filesystem path, file:// URL, localhost/127.0.0.1 address, or host-only preview is useless to a remote room. Every link you surface must be reachable by the people in the room.',
9
+ 'Whenever you produce HTML or shareable markup — a demo, mockup, preview, report, or page — publish it to a browser-renderable GitHub-shareable URL, normally GitHub Pages (or an equivalent URL that actually renders; raw.githubusercontent.com serves HTML as plain text). Give the room that shareable URL, never only a local path. If you cannot publish it, say so and ask how to proceed instead of falling back to a host-only path.',
10
+ 'SHOW VISUAL WORK: whenever you build, change, or fix anything visual — UI, page, HTML artifact, chart, diagram, or rendered result — capture a PNG and surface the image in your turn so it appears inline in the room; the room auto-uploads surfaced images. Prefer showing the result over describing it.',
11
+ 'BRIDGE PREVIEWS: for a built web UI, use preview_start (default root: dist), then preview_capture for exact desktop 1440x900 and mobile 390x844 PNGs, and preview_inspect when DOM text or selector geometry helps. Run the project build first and stop the preview server with preview_stop when done.',
12
+ 'HTML PREVIEWS: when a mockup render helper is available through $TP_MOCKUP_OUTBOX, use it to surface the inline desktop-and-mobile preview card. Also publish the artifact and post its shareable browser URL. Never leave HTML viewable only on the host.',
13
+ 'VERIFY BEFORE CLAIMING: run or serve what you changed, observe it, and show the evidence in the room — the PNG, passing test output, or real response. If something could not be verified, say exactly what remains unverified.',
14
+ ])
15
+
16
+ export const CODEX_THINKPOOL_FIRST_TURN_PREAMBLE = [
17
+ 'ENVIRONMENT (authoritative): You are Codex running inside a ThinkPool Code room, driven live through the thinkpool-pair bridge by a user and possibly a partner. This is a shared remote workspace, not an ordinary local terminal session; act accordingly.',
18
+ ...THINKPOOL_REMOTE_DELIVERY_RULES,
19
+ ].join(' ')