mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
feat(core): Ensure all properties in hooks object are event names. (#16870)
This commit is contained in:
@@ -122,10 +122,10 @@ they appear in the UI.
|
|||||||
| Enable CLI Help Agent | `experimental.cliHelpAgentSettings.enabled` | Enable the CLI Help Agent. | `true` |
|
| Enable CLI Help Agent | `experimental.cliHelpAgentSettings.enabled` | Enable the CLI Help Agent. | `true` |
|
||||||
| Plan | `experimental.plan` | Enable planning features (Plan Mode and tools). | `false` |
|
| Plan | `experimental.plan` | Enable planning features (Plan Mode and tools). | `false` |
|
||||||
|
|
||||||
### Hooks
|
### HooksConfig
|
||||||
|
|
||||||
| UI Label | Setting | Description | Default |
|
| UI Label | Setting | Description | Default |
|
||||||
| ------------------ | --------------------- | ------------------------------------------------ | ------- |
|
| ------------------ | --------------------------- | ------------------------------------------------ | ------- |
|
||||||
| Hook Notifications | `hooks.notifications` | Show visual indicators when hooks are executing. | `true` |
|
| Hook Notifications | `hooksConfig.notifications` | Show visual indicators when hooks are executing. | `true` |
|
||||||
|
|
||||||
<!-- SETTINGS-AUTOGEN:END -->
|
<!-- SETTINGS-AUTOGEN:END -->
|
||||||
|
|||||||
@@ -904,22 +904,24 @@ their corresponding top-level category object in your `settings.json` file.
|
|||||||
- **Default:** `[]`
|
- **Default:** `[]`
|
||||||
- **Requires restart:** Yes
|
- **Requires restart:** Yes
|
||||||
|
|
||||||
#### `hooks`
|
#### `hooksConfig`
|
||||||
|
|
||||||
- **`hooks.enabled`** (boolean):
|
- **`hooksConfig.enabled`** (boolean):
|
||||||
- **Description:** Canonical toggle for the hooks system. When disabled, no
|
- **Description:** Canonical toggle for the hooks system. When disabled, no
|
||||||
hooks will be executed.
|
hooks will be executed.
|
||||||
- **Default:** `false`
|
- **Default:** `false`
|
||||||
|
|
||||||
- **`hooks.disabled`** (array):
|
- **`hooksConfig.disabled`** (array):
|
||||||
- **Description:** List of hook names (commands) that should be disabled.
|
- **Description:** List of hook names (commands) that should be disabled.
|
||||||
Hooks in this list will not execute even if configured.
|
Hooks in this list will not execute even if configured.
|
||||||
- **Default:** `[]`
|
- **Default:** `[]`
|
||||||
|
|
||||||
- **`hooks.notifications`** (boolean):
|
- **`hooksConfig.notifications`** (boolean):
|
||||||
- **Description:** Show visual indicators when hooks are executing.
|
- **Description:** Show visual indicators when hooks are executing.
|
||||||
- **Default:** `true`
|
- **Default:** `true`
|
||||||
|
|
||||||
|
#### `hooks`
|
||||||
|
|
||||||
- **`hooks.BeforeTool`** (array):
|
- **`hooks.BeforeTool`** (array):
|
||||||
- **Description:** Hooks that execute before tool execution. Can intercept,
|
- **Description:** Hooks that execute before tool execution. Can intercept,
|
||||||
validate, or modify tool calls.
|
validate, or modify tool calls.
|
||||||
|
|||||||
@@ -53,8 +53,10 @@ describe('Hooks Agent Flow', () => {
|
|||||||
|
|
||||||
await rig.setup('should inject additional context via BeforeAgent hook', {
|
await rig.setup('should inject additional context via BeforeAgent hook', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeAgent: [
|
BeforeAgent: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -116,8 +118,10 @@ describe('Hooks Agent Flow', () => {
|
|||||||
|
|
||||||
await rig.setup('should receive prompt and response in AfterAgent hook', {
|
await rig.setup('should receive prompt and response in AfterAgent hook', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
AfterAgent: [
|
AfterAgent: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -163,8 +167,10 @@ describe('Hooks Agent Flow', () => {
|
|||||||
'hooks-agent-flow-multistep.responses',
|
'hooks-agent-flow-multistep.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeAgent: [
|
BeforeAgent: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ describe('Hooks System Integration', () => {
|
|||||||
'hooks-system.block-tool.responses',
|
'hooks-system.block-tool.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
matcher: 'write_file',
|
matcher: 'write_file',
|
||||||
@@ -84,8 +86,10 @@ describe('Hooks System Integration', () => {
|
|||||||
'hooks-system.block-tool.responses',
|
'hooks-system.block-tool.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
matcher: 'write_file',
|
matcher: 'write_file',
|
||||||
@@ -141,8 +145,10 @@ describe('Hooks System Integration', () => {
|
|||||||
'hooks-system.allow-tool.responses',
|
'hooks-system.allow-tool.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
matcher: 'write_file',
|
matcher: 'write_file',
|
||||||
@@ -189,8 +195,10 @@ describe('Hooks System Integration', () => {
|
|||||||
'hooks-system.after-tool-context.responses',
|
'hooks-system.after-tool-context.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
AfterTool: [
|
AfterTool: [
|
||||||
{
|
{
|
||||||
matcher: 'read_file',
|
matcher: 'read_file',
|
||||||
@@ -262,8 +270,10 @@ console.log(JSON.stringify({
|
|||||||
|
|
||||||
rig.setup('should modify LLM requests with BeforeModel hooks', {
|
rig.setup('should modify LLM requests with BeforeModel hooks', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeModel: [
|
BeforeModel: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -321,8 +331,10 @@ console.log(JSON.stringify({
|
|||||||
'should block model execution when BeforeModel hook returns deny decision',
|
'should block model execution when BeforeModel hook returns deny decision',
|
||||||
{
|
{
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeModel: [
|
BeforeModel: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -364,8 +376,10 @@ console.log(JSON.stringify({
|
|||||||
'should block model execution when BeforeModel hook returns block decision',
|
'should block model execution when BeforeModel hook returns block decision',
|
||||||
{
|
{
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeModel: [
|
BeforeModel: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -429,8 +443,10 @@ console.log(JSON.stringify({
|
|||||||
|
|
||||||
rig.setup('should modify LLM responses with AfterModel hooks', {
|
rig.setup('should modify LLM responses with AfterModel hooks', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
AfterModel: [
|
AfterModel: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -475,8 +491,10 @@ console.log(JSON.stringify({
|
|||||||
rig.setup('should modify tool selection with BeforeToolSelection hooks', {
|
rig.setup('should modify tool selection with BeforeToolSelection hooks', {
|
||||||
settings: {
|
settings: {
|
||||||
debugMode: true,
|
debugMode: true,
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeToolSelection: [
|
BeforeToolSelection: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -540,8 +558,10 @@ console.log(JSON.stringify({
|
|||||||
|
|
||||||
rig.setup('should augment prompts with BeforeAgent hooks', {
|
rig.setup('should augment prompts with BeforeAgent hooks', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeAgent: [
|
BeforeAgent: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -586,8 +606,10 @@ console.log(JSON.stringify({
|
|||||||
approval: 'ASK', // Disable YOLO mode to show permission prompts
|
approval: 'ASK', // Disable YOLO mode to show permission prompts
|
||||||
confirmationRequired: ['run_shell_command'],
|
confirmationRequired: ['run_shell_command'],
|
||||||
},
|
},
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
Notification: [
|
Notification: [
|
||||||
{
|
{
|
||||||
matcher: 'ToolPermission',
|
matcher: 'ToolPermission',
|
||||||
@@ -677,8 +699,10 @@ console.log(JSON.stringify({
|
|||||||
'hooks-system.sequential-execution.responses',
|
'hooks-system.sequential-execution.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeAgent: [
|
BeforeAgent: [
|
||||||
{
|
{
|
||||||
sequential: true,
|
sequential: true,
|
||||||
@@ -757,8 +781,10 @@ try {
|
|||||||
|
|
||||||
rig.setup('should provide correct input format to hooks', {
|
rig.setup('should provide correct input format to hooks', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -800,8 +826,10 @@ try {
|
|||||||
'hooks-system.allow-tool.responses',
|
'hooks-system.allow-tool.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
matcher: 'write_file',
|
matcher: 'write_file',
|
||||||
@@ -852,8 +880,10 @@ try {
|
|||||||
'hooks-system.multiple-events.responses',
|
'hooks-system.multiple-events.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeAgent: [
|
BeforeAgent: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -965,8 +995,10 @@ try {
|
|||||||
|
|
||||||
rig.setup('should handle hook failures gracefully', {
|
rig.setup('should handle hook failures gracefully', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -1017,8 +1049,10 @@ try {
|
|||||||
'hooks-system.telemetry.responses',
|
'hooks-system.telemetry.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -1058,8 +1092,10 @@ try {
|
|||||||
'hooks-system.session-startup.responses',
|
'hooks-system.session-startup.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
SessionStart: [
|
SessionStart: [
|
||||||
{
|
{
|
||||||
matcher: 'startup',
|
matcher: 'startup',
|
||||||
@@ -1129,8 +1165,10 @@ console.log(JSON.stringify({
|
|||||||
|
|
||||||
rig.setup('should fire SessionStart hook and inject context', {
|
rig.setup('should fire SessionStart hook and inject context', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
SessionStart: [
|
SessionStart: [
|
||||||
{
|
{
|
||||||
matcher: 'startup',
|
matcher: 'startup',
|
||||||
@@ -1212,8 +1250,10 @@ console.log(JSON.stringify({
|
|||||||
'should fire SessionStart hook and display systemMessage in interactive mode',
|
'should fire SessionStart hook and display systemMessage in interactive mode',
|
||||||
{
|
{
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
SessionStart: [
|
SessionStart: [
|
||||||
{
|
{
|
||||||
matcher: 'startup',
|
matcher: 'startup',
|
||||||
@@ -1280,8 +1320,10 @@ console.log(JSON.stringify({
|
|||||||
'hooks-system.session-clear.responses',
|
'hooks-system.session-clear.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
SessionEnd: [
|
SessionEnd: [
|
||||||
{
|
{
|
||||||
matcher: '*',
|
matcher: '*',
|
||||||
@@ -1452,8 +1494,10 @@ console.log(JSON.stringify({
|
|||||||
'hooks-system.compress-auto.responses',
|
'hooks-system.compress-auto.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
PreCompress: [
|
PreCompress: [
|
||||||
{
|
{
|
||||||
matcher: 'auto',
|
matcher: 'auto',
|
||||||
@@ -1517,8 +1561,10 @@ console.log(JSON.stringify({
|
|||||||
'hooks-system.session-startup.responses',
|
'hooks-system.session-startup.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
SessionEnd: [
|
SessionEnd: [
|
||||||
{
|
{
|
||||||
matcher: 'exit',
|
matcher: 'exit',
|
||||||
@@ -1615,8 +1661,11 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho
|
|||||||
|
|
||||||
rig.setup('should not execute hooks disabled in settings file', {
|
rig.setup('should not execute hooks disabled in settings file', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
disabled: [`node "${disabledPath}"`], // Disable the second hook
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -1633,7 +1682,6 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
disabled: [`node "${disabledPath}"`], // Disable the second hook
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1690,8 +1738,11 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho
|
|||||||
|
|
||||||
rig.setup('should respect disabled hooks across multiple operations', {
|
rig.setup('should respect disabled hooks across multiple operations', {
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
disabled: [`node "${disabledPath}"`], // Disable the second hook,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
hooks: [
|
hooks: [
|
||||||
@@ -1708,7 +1759,6 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
disabled: [`node "${disabledPath}"`], // Disable the second hook
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1795,8 +1845,10 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho
|
|||||||
'hooks-system.input-modification.responses',
|
'hooks-system.input-modification.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
matcher: 'write_file',
|
matcher: 'write_file',
|
||||||
@@ -1879,8 +1931,10 @@ console.log(JSON.stringify({decision: "block", systemMessage: "Disabled hook sho
|
|||||||
'hooks-system.before-tool-stop.responses',
|
'hooks-system.before-tool-stop.responses',
|
||||||
),
|
),
|
||||||
settings: {
|
settings: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
matcher: 'write_file',
|
matcher: 'write_file',
|
||||||
|
|||||||
@@ -512,7 +512,7 @@ describe('migrate command', () => {
|
|||||||
'\nMigration complete! Please review the migrated hooks in .gemini/settings.json',
|
'\nMigration complete! Please review the migrated hooks in .gemini/settings.json',
|
||||||
);
|
);
|
||||||
expect(debugLoggerLogSpy).toHaveBeenCalledWith(
|
expect(debugLoggerLogSpy).toHaveBeenCalledWith(
|
||||||
'Note: Set hooks.enabled to true in your settings to enable the hook system.',
|
'Note: Set hooksConfig.enabled to true in your settings to enable the hook system.',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -230,7 +230,10 @@ export async function handleMigrateFromClaude() {
|
|||||||
const settings = loadSettings(workingDir);
|
const settings = loadSettings(workingDir);
|
||||||
|
|
||||||
// Merge migrated hooks with existing hooks
|
// Merge migrated hooks with existing hooks
|
||||||
const existingHooks = settings.merged.hooks as Record<string, unknown>;
|
const existingHooks = (settings.merged?.hooks || {}) as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>;
|
||||||
const mergedHooks = { ...existingHooks, ...migratedHooks };
|
const mergedHooks = { ...existingHooks, ...migratedHooks };
|
||||||
|
|
||||||
// Update settings (setValue automatically saves)
|
// Update settings (setValue automatically saves)
|
||||||
@@ -242,7 +245,7 @@ export async function handleMigrateFromClaude() {
|
|||||||
'\nMigration complete! Please review the migrated hooks in .gemini/settings.json',
|
'\nMigration complete! Please review the migrated hooks in .gemini/settings.json',
|
||||||
);
|
);
|
||||||
debugLogger.log(
|
debugLogger.log(
|
||||||
'Note: Set hooks.enabled to true in your settings to enable the hook system.',
|
'Note: Set hooksConfig.enabled to true in your settings to enable the hook system.',
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
debugLogger.error(`Error saving migrated hooks: ${getErrorMessage(error)}`);
|
debugLogger.error(`Error saving migrated hooks: ${getErrorMessage(error)}`);
|
||||||
|
|||||||
@@ -763,9 +763,10 @@ export async function loadCliConfig(
|
|||||||
// TODO: loading of hooks based on workspace trust
|
// TODO: loading of hooks based on workspace trust
|
||||||
enableHooks:
|
enableHooks:
|
||||||
(settings.tools?.enableHooks ?? true) &&
|
(settings.tools?.enableHooks ?? true) &&
|
||||||
(settings.hooks?.enabled ?? false),
|
(settings.hooksConfig?.enabled ?? false),
|
||||||
enableHooksUI: settings.tools?.enableHooks ?? true,
|
enableHooksUI: settings.tools?.enableHooks ?? true,
|
||||||
hooks: settings.hooks || {},
|
hooks: settings.hooks || {},
|
||||||
|
disabledHooks: settings.hooksConfig?.disabled || [],
|
||||||
projectHooks: projectHooks || {},
|
projectHooks: projectHooks || {},
|
||||||
onModelChange: (model: string) => saveModelChange(loadedSettings, model),
|
onModelChange: (model: string) => saveModelChange(loadedSettings, model),
|
||||||
onReload: async () => {
|
onReload: async () => {
|
||||||
|
|||||||
@@ -613,7 +613,10 @@ Would you like to attempt to install via "git clone" instead?`,
|
|||||||
.filter((contextFilePath) => fs.existsSync(contextFilePath));
|
.filter((contextFilePath) => fs.existsSync(contextFilePath));
|
||||||
|
|
||||||
let hooks: { [K in HookEventName]?: HookDefinition[] } | undefined;
|
let hooks: { [K in HookEventName]?: HookDefinition[] } | undefined;
|
||||||
if (this.settings.tools.enableHooks && this.settings.hooks.enabled) {
|
if (
|
||||||
|
this.settings.tools.enableHooks &&
|
||||||
|
this.settings.hooksConfig.enabled
|
||||||
|
) {
|
||||||
hooks = await this.loadExtensionHooks(effectiveExtensionPath, {
|
hooks = await this.loadExtensionHooks(effectiveExtensionPath, {
|
||||||
extensionPath: effectiveExtensionPath,
|
extensionPath: effectiveExtensionPath,
|
||||||
workspacePath: this.workspaceDir,
|
workspacePath: this.workspaceDir,
|
||||||
|
|||||||
@@ -815,6 +815,7 @@ describe('extension tests', () => {
|
|||||||
fs.mkdirSync(hooksDir);
|
fs.mkdirSync(hooksDir);
|
||||||
|
|
||||||
const hooksConfig = {
|
const hooksConfig = {
|
||||||
|
enabled: false,
|
||||||
hooks: {
|
hooks: {
|
||||||
BeforeTool: [
|
BeforeTool: [
|
||||||
{
|
{
|
||||||
@@ -836,7 +837,7 @@ describe('extension tests', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const settings = loadSettings(tempWorkspaceDir).merged;
|
const settings = loadSettings(tempWorkspaceDir).merged;
|
||||||
settings.hooks.enabled = true;
|
settings.hooksConfig.enabled = true;
|
||||||
|
|
||||||
extensionManager = new ExtensionManager({
|
extensionManager = new ExtensionManager({
|
||||||
workspaceDir: tempWorkspaceDir,
|
workspaceDir: tempWorkspaceDir,
|
||||||
@@ -867,11 +868,10 @@ describe('extension tests', () => {
|
|||||||
fs.mkdirSync(hooksDir);
|
fs.mkdirSync(hooksDir);
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(hooksDir, 'hooks.json'),
|
path.join(hooksDir, 'hooks.json'),
|
||||||
JSON.stringify({ hooks: { BeforeTool: [] } }),
|
JSON.stringify({ hooks: { BeforeTool: [] }, enabled: false }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const settings = loadSettings(tempWorkspaceDir).merged;
|
const settings = loadSettings(tempWorkspaceDir).merged;
|
||||||
settings.hooks.enabled = false;
|
|
||||||
|
|
||||||
extensionManager = new ExtensionManager({
|
extensionManager = new ExtensionManager({
|
||||||
workspaceDir: tempWorkspaceDir,
|
workspaceDir: tempWorkspaceDir,
|
||||||
|
|||||||
@@ -395,8 +395,8 @@ describe('SettingsSchema', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have hooks.notifications setting in schema', () => {
|
it('should have hooksConfig.notifications setting in schema', () => {
|
||||||
const setting = getSettingsSchema().hooks.properties.notifications;
|
const setting = getSettingsSchema().hooksConfig?.properties.notifications;
|
||||||
expect(setting).toBeDefined();
|
expect(setting).toBeDefined();
|
||||||
expect(setting.type).toBe('boolean');
|
expect(setting.type).toBe('boolean');
|
||||||
expect(setting.category).toBe('Advanced');
|
expect(setting.category).toBe('Advanced');
|
||||||
|
|||||||
@@ -1631,9 +1631,9 @@ const SETTINGS_SCHEMA = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
label: 'Hooks',
|
label: 'HooksConfig',
|
||||||
category: 'Advanced',
|
category: 'Advanced',
|
||||||
requiresRestart: false,
|
requiresRestart: false,
|
||||||
default: {},
|
default: {},
|
||||||
@@ -1675,6 +1675,18 @@ const SETTINGS_SCHEMA = {
|
|||||||
description: 'Show visual indicators when hooks are executing.',
|
description: 'Show visual indicators when hooks are executing.',
|
||||||
showInDialog: true,
|
showInDialog: true,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
hooks: {
|
||||||
|
type: 'object',
|
||||||
|
label: 'Hook Events',
|
||||||
|
category: 'Advanced',
|
||||||
|
requiresRestart: false,
|
||||||
|
default: {},
|
||||||
|
description: 'Event-specific hook configurations.',
|
||||||
|
showInDialog: false,
|
||||||
|
properties: {
|
||||||
BeforeTool: {
|
BeforeTool: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
label: 'Before Tool Hooks',
|
label: 'Before Tool Hooks',
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe('hooksCommand', () => {
|
|||||||
};
|
};
|
||||||
let mockSettings: {
|
let mockSettings: {
|
||||||
merged: {
|
merged: {
|
||||||
hooks?: {
|
hooksConfig?: {
|
||||||
disabled?: string[];
|
disabled?: string[];
|
||||||
};
|
};
|
||||||
tools?: {
|
tools?: {
|
||||||
@@ -58,7 +58,7 @@ describe('hooksCommand', () => {
|
|||||||
// Create mock settings
|
// Create mock settings
|
||||||
mockSettings = {
|
mockSettings = {
|
||||||
merged: {
|
merged: {
|
||||||
hooks: {
|
hooksConfig: {
|
||||||
disabled: [],
|
disabled: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -273,7 +273,7 @@ describe('hooksCommand', () => {
|
|||||||
|
|
||||||
it('should enable a hook and update settings', async () => {
|
it('should enable a hook and update settings', async () => {
|
||||||
// Update the context's settings with disabled hooks
|
// Update the context's settings with disabled hooks
|
||||||
mockContext.services.settings.merged.hooks.disabled = [
|
mockContext.services.settings.merged.hooksConfig.disabled = [
|
||||||
'test-hook',
|
'test-hook',
|
||||||
'other-hook',
|
'other-hook',
|
||||||
];
|
];
|
||||||
@@ -289,7 +289,7 @@ describe('hooksCommand', () => {
|
|||||||
|
|
||||||
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
'hooks.disabled',
|
'hooksConfig.disabled',
|
||||||
['other-hook'],
|
['other-hook'],
|
||||||
);
|
);
|
||||||
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
||||||
@@ -404,7 +404,7 @@ describe('hooksCommand', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should disable a hook and update settings', async () => {
|
it('should disable a hook and update settings', async () => {
|
||||||
mockContext.services.settings.merged.hooks.disabled = [];
|
mockContext.services.settings.merged.hooksConfig.disabled = [];
|
||||||
|
|
||||||
const disableCmd = hooksCommand.subCommands!.find(
|
const disableCmd = hooksCommand.subCommands!.find(
|
||||||
(cmd) => cmd.name === 'disable',
|
(cmd) => cmd.name === 'disable',
|
||||||
@@ -417,7 +417,7 @@ describe('hooksCommand', () => {
|
|||||||
|
|
||||||
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
'hooks.disabled',
|
'hooksConfig.disabled',
|
||||||
['test-hook'],
|
['test-hook'],
|
||||||
);
|
);
|
||||||
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
||||||
@@ -433,7 +433,7 @@ describe('hooksCommand', () => {
|
|||||||
|
|
||||||
it('should synchronize with hook system even if hook is already in disabled list', async () => {
|
it('should synchronize with hook system even if hook is already in disabled list', async () => {
|
||||||
// Update the context's settings with the hook already disabled
|
// Update the context's settings with the hook already disabled
|
||||||
mockContext.services.settings.merged.hooks.disabled = ['test-hook'];
|
mockContext.services.settings.merged.hooksConfig.disabled = ['test-hook'];
|
||||||
|
|
||||||
const disableCmd = hooksCommand.subCommands!.find(
|
const disableCmd = hooksCommand.subCommands!.find(
|
||||||
(cmd) => cmd.name === 'disable',
|
(cmd) => cmd.name === 'disable',
|
||||||
@@ -458,7 +458,7 @@ describe('hooksCommand', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle error when disabling hook fails', async () => {
|
it('should handle error when disabling hook fails', async () => {
|
||||||
mockContext.services.settings.merged.hooks.disabled = [];
|
mockContext.services.settings.merged.hooksConfig.disabled = [];
|
||||||
mockSettings.setValue.mockImplementationOnce(() => {
|
mockSettings.setValue.mockImplementationOnce(() => {
|
||||||
throw new Error('Failed to save settings');
|
throw new Error('Failed to save settings');
|
||||||
});
|
});
|
||||||
@@ -637,7 +637,7 @@ describe('hooksCommand', () => {
|
|||||||
|
|
||||||
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
'hooks.disabled',
|
'hooksConfig.disabled',
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
||||||
@@ -761,7 +761,7 @@ describe('hooksCommand', () => {
|
|||||||
|
|
||||||
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
expect(mockContext.services.settings.setValue).toHaveBeenCalledWith(
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
'hooks.disabled',
|
'hooksConfig.disabled',
|
||||||
['hook-1', 'hook-2', 'hook-3'],
|
['hook-1', 'hook-2', 'hook-3'],
|
||||||
);
|
);
|
||||||
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
expect(mockHookSystem.setHookEnabled).toHaveBeenCalledWith(
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ async function enableAction(
|
|||||||
|
|
||||||
// Get current disabled hooks from settings
|
// Get current disabled hooks from settings
|
||||||
const settings = context.services.settings;
|
const settings = context.services.settings;
|
||||||
const disabledHooks = settings.merged.hooks.disabled;
|
const disabledHooks = settings.merged.hooksConfig.disabled;
|
||||||
// Remove from disabled list if present
|
// Remove from disabled list if present
|
||||||
const newDisabledHooks = disabledHooks.filter(
|
const newDisabledHooks = disabledHooks.filter(
|
||||||
(name: string) => name !== hookName,
|
(name: string) => name !== hookName,
|
||||||
@@ -87,10 +87,10 @@ async function enableAction(
|
|||||||
const scope = settings.workspace
|
const scope = settings.workspace
|
||||||
? SettingScope.Workspace
|
? SettingScope.Workspace
|
||||||
: SettingScope.User;
|
: SettingScope.User;
|
||||||
settings.setValue(scope, 'hooks.disabled', newDisabledHooks);
|
settings.setValue(scope, 'hooksConfig.disabled', newDisabledHooks);
|
||||||
|
|
||||||
// Update core config so re-initialization (e.g. extension reload) respects the change
|
// Update core config so re-initialization (e.g. extension reload) respects the change
|
||||||
config.updateDisabledHooks(settings.merged.hooks.disabled);
|
config.updateDisabledHooks(settings.merged.hooksConfig.disabled);
|
||||||
|
|
||||||
// Enable in hook system
|
// Enable in hook system
|
||||||
hookSystem.setHookEnabled(hookName, true);
|
hookSystem.setHookEnabled(hookName, true);
|
||||||
@@ -145,7 +145,7 @@ async function disableAction(
|
|||||||
|
|
||||||
// Get current disabled hooks from settings
|
// Get current disabled hooks from settings
|
||||||
const settings = context.services.settings;
|
const settings = context.services.settings;
|
||||||
const disabledHooks = settings.merged.hooks.disabled;
|
const disabledHooks = settings.merged.hooksConfig.disabled;
|
||||||
// Add to disabled list if not already present
|
// Add to disabled list if not already present
|
||||||
try {
|
try {
|
||||||
if (!disabledHooks.includes(hookName)) {
|
if (!disabledHooks.includes(hookName)) {
|
||||||
@@ -154,11 +154,11 @@ async function disableAction(
|
|||||||
const scope = settings.workspace
|
const scope = settings.workspace
|
||||||
? SettingScope.Workspace
|
? SettingScope.Workspace
|
||||||
: SettingScope.User;
|
: SettingScope.User;
|
||||||
settings.setValue(scope, 'hooks.disabled', newDisabledHooks);
|
settings.setValue(scope, 'hooksConfig.disabled', newDisabledHooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update core config so re-initialization (e.g. extension reload) respects the change
|
// Update core config so re-initialization (e.g. extension reload) respects the change
|
||||||
config.updateDisabledHooks(settings.merged.hooks.disabled);
|
config.updateDisabledHooks(settings.merged.hooksConfig.disabled);
|
||||||
|
|
||||||
// Always disable in hook system to ensure in-memory state matches settings
|
// Always disable in hook system to ensure in-memory state matches settings
|
||||||
hookSystem.setHookEnabled(hookName, false);
|
hookSystem.setHookEnabled(hookName, false);
|
||||||
@@ -250,10 +250,10 @@ async function enableAllAction(
|
|||||||
const scope = settings.workspace
|
const scope = settings.workspace
|
||||||
? SettingScope.Workspace
|
? SettingScope.Workspace
|
||||||
: SettingScope.User;
|
: SettingScope.User;
|
||||||
settings.setValue(scope, 'hooks.disabled', []);
|
settings.setValue(scope, 'hooksConfig.disabled', []);
|
||||||
|
|
||||||
// Update core config so re-initialization (e.g. extension reload) respects the change
|
// Update core config so re-initialization (e.g. extension reload) respects the change
|
||||||
config.updateDisabledHooks(settings.merged.hooks.disabled);
|
config.updateDisabledHooks(settings.merged.hooksConfig.disabled);
|
||||||
|
|
||||||
for (const hook of disabledHooks) {
|
for (const hook of disabledHooks) {
|
||||||
const hookName = getHookDisplayName(hook);
|
const hookName = getHookDisplayName(hook);
|
||||||
@@ -323,10 +323,10 @@ async function disableAllAction(
|
|||||||
const scope = settings.workspace
|
const scope = settings.workspace
|
||||||
? SettingScope.Workspace
|
? SettingScope.Workspace
|
||||||
: SettingScope.User;
|
: SettingScope.User;
|
||||||
settings.setValue(scope, 'hooks.disabled', allHookNames);
|
settings.setValue(scope, 'hooksConfig.disabled', allHookNames);
|
||||||
|
|
||||||
// Update core config so re-initialization (e.g. extension reload) respects the change
|
// Update core config so re-initialization (e.g. extension reload) respects the change
|
||||||
config.updateDisabledHooks(settings.merged.hooks.disabled);
|
config.updateDisabledHooks(settings.merged.hooksConfig.disabled);
|
||||||
|
|
||||||
for (const hook of enabledHooks) {
|
for (const hook of enabledHooks) {
|
||||||
const hookName = getHookDisplayName(hook);
|
const hookName = getHookDisplayName(hook);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const createMockConfig = (overrides = {}) => ({
|
|||||||
|
|
||||||
const createMockSettings = (merged = {}) => ({
|
const createMockSettings = (merged = {}) => ({
|
||||||
merged: {
|
merged: {
|
||||||
hooks: { notifications: true },
|
hooksConfig: { notifications: true },
|
||||||
ui: { hideContextSummary: false },
|
ui: { hideContextSummary: false },
|
||||||
...merged,
|
...merged,
|
||||||
},
|
},
|
||||||
@@ -185,7 +185,7 @@ describe('StatusDisplay', () => {
|
|||||||
activeHooks: [{ name: 'hook', eventName: 'event' }],
|
activeHooks: [{ name: 'hook', eventName: 'event' }],
|
||||||
});
|
});
|
||||||
const settings = createMockSettings({
|
const settings = createMockSettings({
|
||||||
hooks: { notifications: false },
|
hooksConfig: { notifications: false },
|
||||||
});
|
});
|
||||||
const { lastFrame } = renderStatusDisplay(
|
const { lastFrame } = renderStatusDisplay(
|
||||||
{ hideContextSummary: false },
|
{ hideContextSummary: false },
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ export const StatusDisplay: React.FC<StatusDisplayProps> = ({
|
|||||||
return <Text color={theme.status.error}>{uiState.queueErrorMessage}</Text>;
|
return <Text color={theme.status.error}>{uiState.queueErrorMessage}</Text>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uiState.activeHooks.length > 0 && settings.merged.hooks.notifications) {
|
if (
|
||||||
|
uiState.activeHooks.length > 0 &&
|
||||||
|
settings.merged.hooksConfig.notifications
|
||||||
|
) {
|
||||||
return <HookStatusDisplay activeHooks={uiState.activeHooks} />;
|
return <HookStatusDisplay activeHooks={uiState.activeHooks} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1841,7 +1841,7 @@ describe('Hooks configuration', () => {
|
|||||||
debugMode: false,
|
debugMode: false,
|
||||||
model: 'test-model',
|
model: 'test-model',
|
||||||
cwd: '.',
|
cwd: '.',
|
||||||
hooks: { disabled: ['initial-hook'] },
|
disabledHooks: ['initial-hook'],
|
||||||
};
|
};
|
||||||
|
|
||||||
it('updateDisabledHooks should update the disabled list', () => {
|
it('updateDisabledHooks should update the disabled list', () => {
|
||||||
|
|||||||
@@ -379,10 +379,9 @@ export interface ConfigParameters {
|
|||||||
enableHooks?: boolean;
|
enableHooks?: boolean;
|
||||||
enableHooksUI?: boolean;
|
enableHooksUI?: boolean;
|
||||||
experiments?: Experiments;
|
experiments?: Experiments;
|
||||||
hooks?: { [K in HookEventName]?: HookDefinition[] } & { disabled?: string[] };
|
hooks?: { [K in HookEventName]?: HookDefinition[] };
|
||||||
projectHooks?: { [K in HookEventName]?: HookDefinition[] } & {
|
disabledHooks?: string[];
|
||||||
disabled?: string[];
|
projectHooks?: { [K in HookEventName]?: HookDefinition[] };
|
||||||
};
|
|
||||||
previewFeatures?: boolean;
|
previewFeatures?: boolean;
|
||||||
enableAgents?: boolean;
|
enableAgents?: boolean;
|
||||||
enableEventDrivenScheduler?: boolean;
|
enableEventDrivenScheduler?: boolean;
|
||||||
@@ -680,10 +679,7 @@ export class Config {
|
|||||||
: (params.useWriteTodos ?? true);
|
: (params.useWriteTodos ?? true);
|
||||||
this.enableHooksUI = params.enableHooksUI ?? true;
|
this.enableHooksUI = params.enableHooksUI ?? true;
|
||||||
this.enableHooks = params.enableHooks ?? false;
|
this.enableHooks = params.enableHooks ?? false;
|
||||||
this.disabledHooks =
|
this.disabledHooks = params.disabledHooks ?? [];
|
||||||
(params.hooks && 'disabled' in params.hooks
|
|
||||||
? params.hooks.disabled
|
|
||||||
: undefined) ?? [];
|
|
||||||
|
|
||||||
this.codebaseInvestigatorSettings = {
|
this.codebaseInvestigatorSettings = {
|
||||||
enabled: params.codebaseInvestigatorSettings?.enabled ?? true,
|
enabled: params.codebaseInvestigatorSettings?.enabled ?? true,
|
||||||
@@ -724,8 +720,7 @@ export class Config {
|
|||||||
this.disableYoloMode = params.disableYoloMode ?? false;
|
this.disableYoloMode = params.disableYoloMode ?? false;
|
||||||
|
|
||||||
if (params.hooks) {
|
if (params.hooks) {
|
||||||
const { disabled: _, ...restOfHooks } = params.hooks;
|
this.hooks = params.hooks;
|
||||||
this.hooks = restOfHooks;
|
|
||||||
}
|
}
|
||||||
if (params.projectHooks) {
|
if (params.projectHooks) {
|
||||||
this.projectHooks = params.projectHooks;
|
this.projectHooks = params.projectHooks;
|
||||||
@@ -1993,9 +1988,7 @@ export class Config {
|
|||||||
/**
|
/**
|
||||||
* Get project-specific hooks configuration
|
* Get project-specific hooks configuration
|
||||||
*/
|
*/
|
||||||
getProjectHooks():
|
getProjectHooks(): { [K in HookEventName]?: HookDefinition[] } | undefined {
|
||||||
| ({ [K in HookEventName]?: HookDefinition[] } & { disabled?: string[] })
|
|
||||||
| undefined {
|
|
||||||
return this.projectHooks;
|
return this.projectHooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -279,8 +279,8 @@ describe('HookSystem Integration', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
disabled: ['echo "disabled-hook"'], // Disable the second hook
|
|
||||||
},
|
},
|
||||||
|
disabledHooks: ['echo "disabled-hook"'], // Disable the second hook
|
||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -1564,8 +1564,8 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"hooks": {
|
"hooksConfig": {
|
||||||
"title": "Hooks",
|
"title": "HooksConfig",
|
||||||
"description": "Hook configurations for intercepting and customizing agent behavior.",
|
"description": "Hook configurations for intercepting and customizing agent behavior.",
|
||||||
"markdownDescription": "Hook configurations for intercepting and customizing agent behavior.\n\n- Category: `Advanced`\n- Requires restart: `no`\n- Default: `{}`",
|
"markdownDescription": "Hook configurations for intercepting and customizing agent behavior.\n\n- Category: `Advanced`\n- Requires restart: `no`\n- Default: `{}`",
|
||||||
"default": {},
|
"default": {},
|
||||||
@@ -1594,7 +1594,17 @@
|
|||||||
"markdownDescription": "Show visual indicators when hooks are executing.\n\n- Category: `Advanced`\n- Requires restart: `no`\n- Default: `true`",
|
"markdownDescription": "Show visual indicators when hooks are executing.\n\n- Category: `Advanced`\n- Requires restart: `no`\n- Default: `true`",
|
||||||
"default": true,
|
"default": true,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"title": "Hook Events",
|
||||||
|
"description": "Event-specific hook configurations.",
|
||||||
|
"markdownDescription": "Event-specific hook configurations.\n\n- Category: `Advanced`\n- Requires restart: `no`\n- Default: `{}`",
|
||||||
|
"default": {},
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
"BeforeTool": {
|
"BeforeTool": {
|
||||||
"title": "Before Tool Hooks",
|
"title": "Before Tool Hooks",
|
||||||
"description": "Hooks that execute before tool execution. Can intercept, validate, or modify tool calls.",
|
"description": "Hooks that execute before tool execution. Can intercept, validate, or modify tool calls.",
|
||||||
|
|||||||
Reference in New Issue
Block a user