thinkpool-pair 0.7.208 → 0.7.210

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 CHANGED
@@ -50,7 +50,7 @@ import { validateProviderSwitch, providerSwitchPlan, BUILTIN_PROVIDER } from './
50
50
  import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'
51
51
  import { z } from 'zod'
52
52
  import { startClaudeSession } from './claude-session.mjs'
53
- import { startCodexSession, readCodexDefaultModel, readCodexModels, codexConfigForMode } from './codex-session.mjs'
53
+ import { startCodexSession, readCodexDefaultModel, readCodexModels, codexConfigForMode, defaultModeForRuntime } from './codex-session.mjs'
54
54
  import { createManagedLaneWorktree, removeManagedLaneWorktree } from './lane-worktree.mjs'
55
55
  import { commandOnPath } from './agent-detect.mjs'
56
56
 
@@ -1544,7 +1544,13 @@ function worktreeSnapshot(cwd) {
1544
1544
  function openStructured({ id, runtime = 'claude', model, effort, resume, log, commands, mode, spawnedBy, rolePrompt, flowSessionId, flowTaskKey, cwd, managedWorktree, reviewSliceRoots, openedAt, defer, provider, carryRecap, lastUsage }) {
1545
1545
  if (sessions.has(id)) return
1546
1546
  runtime = runtime === 'codex' ? 'codex' : 'claude'
1547
- mode = STRUCTURED_MODES.has(mode) ? mode : 'default'
1547
+ // No explicit mode → a sensible default per runtime (see defaultModeForRuntime):
1548
+ // codex → bypassPermissions, so a freshly-opened codex terminal can fetch /
1549
+ // advance / ship instead of hitting the no-network wall; claude → default.
1550
+ // Only fires when no mode was passed — a person's pick, a resume (persisted
1551
+ // entry.mode), a flow lane, and spawn_terminal (inherits the parent's mode +
1552
+ // its own bypass-escalation gate) all pass an explicit mode and skip this.
1553
+ mode = STRUCTURED_MODES.has(mode) ? mode : defaultModeForRuntime(runtime)
1548
1554
  // The lane's EFFECTIVE model — computed ONCE and used for BOTH the truthful display
1549
1555
  // label (entry.model) and the SDK's `model` option below. These used to be computed
1550
1556
  // separately: the label resolved the provider's configured model while the SDK got the
package/codex-session.mjs CHANGED
@@ -44,6 +44,21 @@ export function codexConfigForMode(mode) {
44
44
  return CODEX_MODE_CONFIG[mode] || CODEX_MODE_CONFIG.default
45
45
  }
46
46
 
47
+ /**
48
+ * The permission mode a FRESHLY-OPENED terminal gets when none was specified
49
+ * (the person clicked "+ New terminal" without picking a mode). Codex defaults
50
+ * to bypassPermissions: its workspace-write sandbox has NO network, so a
51
+ * default-mode codex lane can't fetch / advance git metadata / push / publish
52
+ * (the 2026-07-13 "sandbox won't let it advance Git metadata" wall) and is
53
+ * hobbled out-of-the-box. bypass gives a person-opened codex terminal parity
54
+ * with how Claude lanes run. Claude keeps 'default' — its permission modes don't
55
+ * gate network. Explicit modes (a person's pick, resume's persisted entry.mode,
56
+ * a flow lane, spawn_terminal's inherited mode) always override this.
57
+ */
58
+ export function defaultModeForRuntime(runtime) {
59
+ return runtime === 'codex' ? 'bypassPermissions' : 'default'
60
+ }
61
+
47
62
  export function readCodexDefaultModel({ home = process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), fsImpl = fs } = {}) {
48
63
  try {
49
64
  const text = fsImpl.readFileSync(path.join(home, 'config.toml'), 'utf8')
@@ -164,10 +179,18 @@ export function buildCodexPrompt({ text, rolePrompt, roomContext }) {
164
179
  export function buildCodexExecArgs({ sessionId, model, effort, sandbox, approvalPolicy = 'untrusted', providerConfig, mcpUrl, writableDirs = [], prompt }) {
165
180
  const safeSandbox = normalizeCodexSandbox(sandbox)
166
181
  const args = sessionId
167
- // `codex exec resume` deliberately has no --sandbox option. The resumed
168
- // rollout retains the sandbox selected on its fresh first turn. Passing the
169
- // fresh-only flag here makes current Codex exit 2 before doing any work.
170
- ? ['exec', 'resume', '--json', '--skip-git-repo-check']
182
+ // `codex exec resume` has no --sandbox option and does NOT retain the fresh
183
+ // exec's sandbox: without an explicit override Codex falls back to its
184
+ // workspace profile (network=false). That silently removes the loopback
185
+ // ThinkPool MCP and blocks git metadata/network on turn two. Reassert the
186
+ // selected posture on every resume. Codex exposes a dedicated resume flag
187
+ // for full access; restricted modes ride the equivalent config override.
188
+ ? [
189
+ 'exec', 'resume', '--json', '--skip-git-repo-check',
190
+ ...(safeSandbox === 'danger-full-access'
191
+ ? ['--dangerously-bypass-approvals-and-sandbox']
192
+ : ['-c', `sandbox_mode="${safeSandbox}"`]),
193
+ ]
171
194
  : ['exec', '--json', '--sandbox', safeSandbox, '--skip-git-repo-check']
172
195
  if (model) args.push('-m', model)
173
196
  args.push('-c', `approval_policy="${approvalPolicy}"`)
@@ -362,8 +385,8 @@ export function startCodexSession({ cwd, model, effort: initialEffort = 'high',
362
385
  activeMode = nextMode
363
386
  modeConfig = codexConfigForMode(activeMode)
364
387
  sandbox = modeConfig.sandbox
365
- // Resume retains the original sandbox. Start a fresh native thread on the
366
- // next turn so the selected mode is real, while ThinkPool keeps the lane log.
388
+ // A mode change deliberately starts a fresh native thread so no prior
389
+ // rollout can carry stale permission state; ThinkPool keeps the lane log.
367
390
  sessionId = null
368
391
  turnNo = 0
369
392
  latestUsageSnapshot = null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.208",
3
+ "version": "0.7.210",
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": {