feat: wire autoFix into PostToolUse hook flow (Task 5)
Add auto-fix lint/test check after existing PostToolUse hooks in runPostToolUseHooks. When autoFix is configured in settings, runs lint/test commands after file_edit/file_write tools and yields errors as hook_additional_context for the model to act on. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
46
src/services/autoFix/autoFixIntegration.test.ts
Normal file
46
src/services/autoFix/autoFixIntegration.test.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test'
|
||||||
|
import { getAutoFixConfig } from './autoFixConfig.js'
|
||||||
|
import { shouldRunAutoFix, buildAutoFixContext } from './autoFixHook.js'
|
||||||
|
import { runAutoFixCheck } from './autoFixRunner.js'
|
||||||
|
|
||||||
|
describe('autoFix end-to-end flow', () => {
|
||||||
|
test('full flow: config → shouldRun → check → context', async () => {
|
||||||
|
const config = getAutoFixConfig({
|
||||||
|
enabled: true,
|
||||||
|
lint: 'echo "error: unused" && exit 1',
|
||||||
|
maxRetries: 2,
|
||||||
|
timeout: 5000,
|
||||||
|
})
|
||||||
|
expect(config).not.toBeNull()
|
||||||
|
expect(shouldRunAutoFix('file_edit', config)).toBe(true)
|
||||||
|
|
||||||
|
const result = await runAutoFixCheck({
|
||||||
|
lint: config!.lint,
|
||||||
|
test: config!.test,
|
||||||
|
timeout: config!.timeout,
|
||||||
|
cwd: '/tmp',
|
||||||
|
})
|
||||||
|
expect(result.hasErrors).toBe(true)
|
||||||
|
|
||||||
|
const context = buildAutoFixContext(result)
|
||||||
|
expect(context).not.toBeNull()
|
||||||
|
expect(context).toContain('AUTO-FIX')
|
||||||
|
expect(context).toContain('unused')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('full flow: no errors = no context', async () => {
|
||||||
|
const config = getAutoFixConfig({
|
||||||
|
enabled: true,
|
||||||
|
lint: 'echo "all clean"',
|
||||||
|
timeout: 5000,
|
||||||
|
})
|
||||||
|
const result = await runAutoFixCheck({
|
||||||
|
lint: config!.lint,
|
||||||
|
timeout: config!.timeout,
|
||||||
|
cwd: '/tmp',
|
||||||
|
})
|
||||||
|
expect(result.hasErrors).toBe(false)
|
||||||
|
const context = buildAutoFixContext(result)
|
||||||
|
expect(context).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -29,6 +29,9 @@ import {
|
|||||||
} from '../../utils/permissions/PermissionResult.js'
|
} from '../../utils/permissions/PermissionResult.js'
|
||||||
import { checkRuleBasedPermissions } from '../../utils/permissions/permissions.js'
|
import { checkRuleBasedPermissions } from '../../utils/permissions/permissions.js'
|
||||||
import { formatError } from '../../utils/toolErrors.js'
|
import { formatError } from '../../utils/toolErrors.js'
|
||||||
|
import { getAutoFixConfig } from '../autoFix/autoFixConfig.js'
|
||||||
|
import { shouldRunAutoFix, buildAutoFixContext } from '../autoFix/autoFixHook.js'
|
||||||
|
import { runAutoFixCheck } from '../autoFix/autoFixRunner.js'
|
||||||
import { isMcpTool } from '../mcp/utils.js'
|
import { isMcpTool } from '../mcp/utils.js'
|
||||||
import type { McpServerType, MessageUpdateLazy } from './toolExecution.js'
|
import type { McpServerType, MessageUpdateLazy } from './toolExecution.js'
|
||||||
|
|
||||||
@@ -185,6 +188,40 @@ export async function* runPostToolUseHooks<Input extends AnyObject, Output>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-fix: run lint/test if configured for this tool
|
||||||
|
const autoFixSettings = toolUseContext.getAppState().settings
|
||||||
|
const autoFixConfig = getAutoFixConfig(
|
||||||
|
autoFixSettings && typeof autoFixSettings === 'object' && 'autoFix' in autoFixSettings
|
||||||
|
? (autoFixSettings as Record<string, unknown>).autoFix
|
||||||
|
: undefined,
|
||||||
|
)
|
||||||
|
if (shouldRunAutoFix(tool.name, autoFixConfig) && autoFixConfig) {
|
||||||
|
try {
|
||||||
|
const cwd = toolUseContext.options?.cwd ?? process.cwd()
|
||||||
|
const autoFixResult = await runAutoFixCheck({
|
||||||
|
lint: autoFixConfig.lint,
|
||||||
|
test: autoFixConfig.test,
|
||||||
|
timeout: autoFixConfig.timeout,
|
||||||
|
cwd,
|
||||||
|
signal: toolUseContext.abortController.signal,
|
||||||
|
})
|
||||||
|
const autoFixContext = buildAutoFixContext(autoFixResult)
|
||||||
|
if (autoFixContext) {
|
||||||
|
yield {
|
||||||
|
message: createAttachmentMessage({
|
||||||
|
type: 'hook_additional_context',
|
||||||
|
content: [autoFixContext],
|
||||||
|
hookName: `AutoFix:${tool.name}`,
|
||||||
|
toolUseID,
|
||||||
|
hookEvent: 'PostToolUse',
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (autoFixError) {
|
||||||
|
logError(autoFixError)
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error)
|
logError(error)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user