thinkpool-pair 0.6.3 → 0.6.4
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 -2
- package/claude-session.mjs +18 -0
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -327,7 +327,7 @@ function openStructured({ id, model, resume }) {
|
|
|
327
327
|
},
|
|
328
328
|
requestPermission: (req) => new Promise((resolve) => {
|
|
329
329
|
entry.pending.set(req.id, resolve)
|
|
330
|
-
bcast('code-perm-req', { term: id, id: req.id, toolName: req.toolName, input: req.input, risk: req.risk })
|
|
330
|
+
bcast('code-perm-req', { term: id, id: req.id, toolName: req.toolName, input: req.input, risk: req.risk, plan: req.plan })
|
|
331
331
|
}),
|
|
332
332
|
})
|
|
333
333
|
announce()
|
|
@@ -459,7 +459,9 @@ channel
|
|
|
459
459
|
.on('broadcast', { event: 'code-perm' }, ({ payload }) => {
|
|
460
460
|
const s = payload?.term && sessions.get(payload.term)
|
|
461
461
|
const resolve = s && payload.id && s.pending.get(payload.id)
|
|
462
|
-
|
|
462
|
+
// Pass the raw decision through — normal tools use allow/deny, plan cards
|
|
463
|
+
// use run/accept/keep (claude-session interprets). Default deny on missing.
|
|
464
|
+
if (resolve) { s.pending.delete(payload.id); resolve(payload.decision || 'deny') }
|
|
463
465
|
})
|
|
464
466
|
.on('broadcast', { event: 'code-abort' }, ({ payload }) => {
|
|
465
467
|
const s = payload?.term && sessions.get(payload.term)
|
package/claude-session.mjs
CHANGED
|
@@ -101,6 +101,24 @@ export function startClaudeSession({ cwd, model, resume, onEvent, requestPermiss
|
|
|
101
101
|
const preTool = async (hookInput) => {
|
|
102
102
|
const toolName = hookInput.tool_name
|
|
103
103
|
const toolInput = hookInput.tool_input
|
|
104
|
+
// ── Plan approval — ExitPlanMode is how the agent presents its plan in
|
|
105
|
+
// plan mode. Render a dedicated plan card (not the generic perm card) with
|
|
106
|
+
// three outcomes: run (exit → default), accept (exit → acceptEdits), keep
|
|
107
|
+
// (deny → stay planning). On approval we flip the SDK permission mode so
|
|
108
|
+
// subsequent tools actually execute.
|
|
109
|
+
if (toolName === 'ExitPlanMode') {
|
|
110
|
+
let choice = 'keep'
|
|
111
|
+
try { choice = await requestPermission?.({ id: randomUUID(), toolName, input: toolInput, risk: 'plan', plan: toolInput?.plan || '' }) ?? 'keep' }
|
|
112
|
+
catch { choice = 'keep' }
|
|
113
|
+
if (choice === 'run' || choice === 'accept') {
|
|
114
|
+
const next = choice === 'accept' ? 'acceptEdits' : 'default'
|
|
115
|
+
mode = next
|
|
116
|
+
try { await q?.setPermissionMode?.(next) } catch { /* only valid mid-stream */ }
|
|
117
|
+
emit({ kind: 'mode', mode: next })
|
|
118
|
+
return { continue: true, hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow', permissionDecisionReason: `Plan approved in the ThinkPool room — proceed (${next} mode).` } }
|
|
119
|
+
}
|
|
120
|
+
return { continue: true, hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: 'The user chose "keep planning" in the ThinkPool room. Do not exit plan mode — keep refining the plan, then call ExitPlanMode again when ready.' } }
|
|
121
|
+
}
|
|
104
122
|
const risk = classifyRisk(toolName, toolInput)
|
|
105
123
|
const auto =
|
|
106
124
|
risk === 'low' ||
|