thinkpool-pair 0.6.7 → 0.6.8
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 +21 -0
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -384,10 +384,12 @@ function openStructured({ id, model, resume, log }) {
|
|
|
384
384
|
},
|
|
385
385
|
requestPermission: (req) => new Promise((resolve) => {
|
|
386
386
|
entry.pending.set(req.id, resolve)
|
|
387
|
-
bcast('code-perm-req', { term: id, id: req.id, toolName: req.toolName, input: req.input, risk: req.risk, plan: req.plan })
|
|
387
|
+
bcast('code-perm-req', { term: id, id: req.id, toolName: req.toolName, input: req.input, risk: req.risk, plan: req.plan, questions: req.questions })
|
|
388
388
|
process.stderr.write(req.risk === 'plan'
|
|
389
389
|
? `\n ${A.mag}◆ plan ready — approve in the room.${A.rst}\n`
|
|
390
|
-
:
|
|
390
|
+
: req.risk === 'ask'
|
|
391
|
+
? `\n ${A.cyan}● Claude is asking: ${(req.questions || []).map((q) => q.question).join(' / ').slice(0, 100)} — answer in the room.${A.rst}\n`
|
|
392
|
+
: `\n ${A.yel}● permission: ${req.toolName}${argStr(req.input)} — approve in the room.${A.rst}\n`)
|
|
391
393
|
}),
|
|
392
394
|
})
|
|
393
395
|
announce()
|
package/claude-session.mjs
CHANGED
|
@@ -120,6 +120,27 @@ export function startClaudeSession({ cwd, model, resume, onEvent, requestPermiss
|
|
|
120
120
|
}
|
|
121
121
|
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.' } }
|
|
122
122
|
}
|
|
123
|
+
// ── AskUserQuestion — the agent asks the user a multiple-choice question.
|
|
124
|
+
// It can't run its interactive dialog headless (allowing it errors), so we
|
|
125
|
+
// render the choice card in the room and feed the selection back as the tool
|
|
126
|
+
// outcome. PreToolUse can't inject a tool_result, but a deny's reason IS what
|
|
127
|
+
// the model receives — so we deny and put the answer in the reason.
|
|
128
|
+
if (toolName === 'AskUserQuestion') {
|
|
129
|
+
let decision = ''
|
|
130
|
+
try { decision = await requestPermission?.({ id: randomUUID(), toolName, input: toolInput, risk: 'ask', questions: toolInput?.questions || [] }) ?? '' }
|
|
131
|
+
catch { decision = '' }
|
|
132
|
+
const ans = (typeof decision === 'string' && decision.startsWith('answer:')) ? decision.slice(7) : ''
|
|
133
|
+
return {
|
|
134
|
+
continue: true,
|
|
135
|
+
hookSpecificOutput: {
|
|
136
|
+
hookEventName: 'PreToolUse',
|
|
137
|
+
permissionDecision: 'deny',
|
|
138
|
+
permissionDecisionReason: ans
|
|
139
|
+
? `The user answered in the ThinkPool room — ${ans}. Treat this as their selection and continue; do not call AskUserQuestion again for the same question.`
|
|
140
|
+
: 'The user dismissed the question in the ThinkPool room without selecting. Ask in plain prose, or proceed with a sensible default.',
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
}
|
|
123
144
|
const risk = classifyRisk(toolName, toolInput)
|
|
124
145
|
// "Don't ask again" is keyed by tool + risk tier, so allowing medium Bash
|
|
125
146
|
// never silently allows a future destructive one (high always re-asks).
|