mirror of
https://github.com/stablyai/orca.git
synced 2026-09-28 08:02:43 +00:00
fix(claude): release permission prompt abort listeners (#23195)
* fix(claude): release permission prompt abort listeners * fix(i18n): register existing diff note fallback strings --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
This commit is contained in:
@@ -41,10 +41,12 @@ function callbacksFor() {
|
||||
describe('Claude permission callbacks', () => {
|
||||
it('registers a decodable can_use_tool as a durable prompt and settles it from the registry', async () => {
|
||||
const control = callbacksFor()
|
||||
const controller = new AbortController()
|
||||
const removeListener = vi.spyOn(controller.signal, 'removeEventListener')
|
||||
const answered = control.canUseTool(
|
||||
'Bash',
|
||||
{ command: 'git status' },
|
||||
permissionOptions('perm-1', 'tool-1', new AbortController().signal, [
|
||||
permissionOptions('perm-1', 'tool-1', controller.signal, [
|
||||
{ type: 'addRules', rules: [], behavior: 'allow', destination: 'session' }
|
||||
])
|
||||
)
|
||||
@@ -63,6 +65,7 @@ describe('Claude permission callbacks', () => {
|
||||
// The prompt's settle is the SDK callback's own resolve — answering resolves this promise.
|
||||
found?.prompt.settle({ behavior: 'allow', toolUseID: 'tool-1' })
|
||||
await expect(answered).resolves.toEqual({ behavior: 'allow', toolUseID: 'tool-1' })
|
||||
expect(removeListener).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('keeps the SDK permission presentation and strips terminal escapes', async () => {
|
||||
|
||||
@@ -56,6 +56,11 @@ export function buildClaudePermissionCallbacks(deps: ClaudePermissionCallbackDep
|
||||
} {
|
||||
const canUseTool: CanUseTool = (toolName, input, options) =>
|
||||
new Promise<PermissionResult | null>((resolve) => {
|
||||
let cancel = (): void => {}
|
||||
const settle = (response: PermissionResult | null): void => {
|
||||
options.signal.removeEventListener('abort', cancel)
|
||||
resolve(response)
|
||||
}
|
||||
// Classify first so later permission-mode policy cannot swallow a plan proposal.
|
||||
const subject = claudePermissionSubject(toolName, input)
|
||||
const prompt = deps.prompts.register({
|
||||
@@ -66,14 +71,14 @@ export function buildClaudePermissionCallbacks(deps: ClaudePermissionCallbackDep
|
||||
toolUseId: options.toolUseID,
|
||||
input,
|
||||
suggestions: options.suggestions ?? [],
|
||||
settle: resolve,
|
||||
settle,
|
||||
turnId: deps.currentTurnId?.() ?? null
|
||||
})
|
||||
if (!prompt) {
|
||||
resolve(denySafeResult(options.toolUseID))
|
||||
settle(denySafeResult(options.toolUseID))
|
||||
return
|
||||
}
|
||||
const cancel = (): void => {
|
||||
cancel = (): void => {
|
||||
if (deps.prompts.forgetIfPending(prompt)) {
|
||||
deps.emit({
|
||||
type: 'prompt-cancelled',
|
||||
@@ -82,7 +87,7 @@ export function buildClaudePermissionCallbacks(deps: ClaudePermissionCallbackDep
|
||||
})
|
||||
// Null is the SDK's "no response written" sentinel: a cancelled request must not
|
||||
// be answered, only forgotten.
|
||||
resolve(null)
|
||||
settle(null)
|
||||
}
|
||||
}
|
||||
if (options.signal.aborted) {
|
||||
|
||||
Reference in New Issue
Block a user