@hasna/hooks 0.1.0 → 0.1.1

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.
Files changed (3) hide show
  1. package/bin/index.js +84 -41
  2. package/dist/index.js +72 -29
  3. package/package.json +2 -2
package/bin/index.js CHANGED
@@ -3842,11 +3842,17 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3842
3842
  import { join, dirname } from "path";
3843
3843
  import { homedir } from "os";
3844
3844
  import { fileURLToPath } from "url";
3845
- function getSettingsPath(scope = "global") {
3845
+ function getTargetSettingsDir(target) {
3846
+ if (target === "gemini")
3847
+ return ".gemini";
3848
+ return ".claude";
3849
+ }
3850
+ function getSettingsPath(scope = "global", target = "claude") {
3851
+ const dir = getTargetSettingsDir(target);
3846
3852
  if (scope === "project") {
3847
- return join(process.cwd(), ".claude", "settings.json");
3853
+ return join(process.cwd(), dir, "settings.json");
3848
3854
  }
3849
- return join(homedir(), ".claude", "settings.json");
3855
+ return join(homedir(), dir, "settings.json");
3850
3856
  }
3851
3857
  function getHookPath(name) {
3852
3858
  const hookName = name.startsWith("hook-") ? name : `hook-${name}`;
@@ -3855,8 +3861,8 @@ function getHookPath(name) {
3855
3861
  function hookExists(name) {
3856
3862
  return existsSync(getHookPath(name));
3857
3863
  }
3858
- function readSettings(scope = "global") {
3859
- const path = getSettingsPath(scope);
3864
+ function readSettings(scope = "global", target = "claude") {
3865
+ const path = getSettingsPath(scope, target);
3860
3866
  try {
3861
3867
  if (existsSync(path)) {
3862
3868
  return JSON.parse(readFileSync(path, "utf-8"));
@@ -3864,8 +3870,8 @@ function readSettings(scope = "global") {
3864
3870
  } catch {}
3865
3871
  return {};
3866
3872
  }
3867
- function writeSettings(settings, scope = "global") {
3868
- const path = getSettingsPath(scope);
3873
+ function writeSettings(settings, scope = "global", target = "claude") {
3874
+ const path = getSettingsPath(scope, target);
3869
3875
  const dir = dirname(path);
3870
3876
  if (!existsSync(dir)) {
3871
3877
  mkdirSync(dir, { recursive: true });
@@ -3873,36 +3879,48 @@ function writeSettings(settings, scope = "global") {
3873
3879
  writeFileSync(path, JSON.stringify(settings, null, 2) + `
3874
3880
  `);
3875
3881
  }
3876
- function installHook(name, options = {}) {
3877
- const { scope = "global", overwrite = false } = options;
3882
+ function getTargetEventName(internalEvent, target) {
3883
+ return EVENT_MAP[target]?.[internalEvent] || internalEvent;
3884
+ }
3885
+ function installForTarget(name, scope, overwrite, target) {
3878
3886
  const hookName = name.startsWith("hook-") ? name : `hook-${name}`;
3879
3887
  const shortName = hookName.replace("hook-", "");
3880
3888
  if (!hookExists(shortName)) {
3881
- return { hook: shortName, success: false, error: `Hook '${shortName}' not found` };
3889
+ return { hook: shortName, success: false, error: `Hook '${shortName}' not found`, target };
3882
3890
  }
3883
- const registered = getRegisteredHooks(scope);
3891
+ const registered = getRegisteredHooksForTarget(scope, target);
3884
3892
  if (registered.includes(shortName) && !overwrite) {
3885
- return { hook: shortName, success: false, error: "Already installed. Use --overwrite to replace.", scope };
3893
+ return { hook: shortName, success: false, error: "Already installed. Use --overwrite to replace.", scope, target };
3886
3894
  }
3887
3895
  try {
3888
- registerHook(shortName, scope);
3889
- return { hook: shortName, success: true, scope };
3896
+ registerHook(shortName, scope, target);
3897
+ return { hook: shortName, success: true, scope, target };
3890
3898
  } catch (error) {
3891
3899
  return {
3892
3900
  hook: shortName,
3893
3901
  success: false,
3894
- error: error instanceof Error ? error.message : "Unknown error"
3902
+ error: error instanceof Error ? error.message : "Unknown error",
3903
+ target
3895
3904
  };
3896
3905
  }
3897
3906
  }
3898
- function registerHook(name, scope = "global") {
3907
+ function installHook(name, options = {}) {
3908
+ const { scope = "global", overwrite = false, target = "claude" } = options;
3909
+ if (target === "all") {
3910
+ const claudeResult = installForTarget(name, scope, overwrite, "claude");
3911
+ installForTarget(name, scope, overwrite, "gemini");
3912
+ return { ...claudeResult, target: "all" };
3913
+ }
3914
+ return installForTarget(name, scope, overwrite, target);
3915
+ }
3916
+ function registerHook(name, scope = "global", target = "claude") {
3899
3917
  const meta = getHook(name);
3900
3918
  if (!meta)
3901
3919
  return;
3902
- const settings = readSettings(scope);
3920
+ const settings = readSettings(scope, target);
3903
3921
  if (!settings.hooks)
3904
3922
  settings.hooks = {};
3905
- const eventKey = meta.event;
3923
+ const eventKey = getTargetEventName(meta.event, target);
3906
3924
  if (!settings.hooks[eventKey])
3907
3925
  settings.hooks[eventKey] = [];
3908
3926
  const hookCommand = `hooks run ${name}`;
@@ -3914,16 +3932,16 @@ function registerHook(name, scope = "global") {
3914
3932
  entry.matcher = meta.matcher;
3915
3933
  }
3916
3934
  settings.hooks[eventKey].push(entry);
3917
- writeSettings(settings, scope);
3935
+ writeSettings(settings, scope, target);
3918
3936
  }
3919
- function unregisterHook(name, scope = "global") {
3937
+ function unregisterHook(name, scope = "global", target = "claude") {
3920
3938
  const meta = getHook(name);
3921
3939
  if (!meta)
3922
3940
  return;
3923
- const settings = readSettings(scope);
3941
+ const settings = readSettings(scope, target);
3924
3942
  if (!settings.hooks)
3925
3943
  return;
3926
- const eventKey = meta.event;
3944
+ const eventKey = getTargetEventName(meta.event, target);
3927
3945
  if (!settings.hooks[eventKey])
3928
3946
  return;
3929
3947
  const hookCommand = `hooks run ${name}`;
@@ -3934,10 +3952,10 @@ function unregisterHook(name, scope = "global") {
3934
3952
  if (Object.keys(settings.hooks).length === 0) {
3935
3953
  delete settings.hooks;
3936
3954
  }
3937
- writeSettings(settings, scope);
3955
+ writeSettings(settings, scope, target);
3938
3956
  }
3939
- function getRegisteredHooks(scope = "global") {
3940
- const settings = readSettings(scope);
3957
+ function getRegisteredHooksForTarget(scope = "global", target = "claude") {
3958
+ const settings = readSettings(scope, target);
3941
3959
  if (!settings.hooks)
3942
3960
  return [];
3943
3961
  const registered = [];
@@ -3955,24 +3973,49 @@ function getRegisteredHooks(scope = "global") {
3955
3973
  }
3956
3974
  return [...new Set(registered)];
3957
3975
  }
3976
+ function getRegisteredHooks(scope = "global") {
3977
+ return getRegisteredHooksForTarget(scope, "claude");
3978
+ }
3958
3979
  function getInstalledHooks(scope = "global") {
3959
3980
  return getRegisteredHooks(scope);
3960
3981
  }
3961
- function removeHook(name, scope = "global") {
3982
+ function removeHook(name, scope = "global", target = "claude") {
3962
3983
  const hookName = name.startsWith("hook-") ? name : `hook-${name}`;
3963
3984
  const shortName = hookName.replace("hook-", "");
3964
- const registered = getRegisteredHooks(scope);
3965
- if (!registered.includes(shortName)) {
3985
+ if (target === "all") {
3986
+ const claudeRemoved = removeHookForTarget(shortName, scope, "claude");
3987
+ const geminiRemoved = removeHookForTarget(shortName, scope, "gemini");
3988
+ return claudeRemoved || geminiRemoved;
3989
+ }
3990
+ return removeHookForTarget(shortName, scope, target);
3991
+ }
3992
+ function removeHookForTarget(name, scope, target) {
3993
+ const registered = getRegisteredHooksForTarget(scope, target);
3994
+ if (!registered.includes(name)) {
3966
3995
  return false;
3967
3996
  }
3968
- unregisterHook(shortName, scope);
3997
+ unregisterHook(name, scope, target);
3969
3998
  return true;
3970
3999
  }
3971
- var __dirname2, HOOKS_DIR;
4000
+ var __dirname2, HOOKS_DIR, EVENT_MAP;
3972
4001
  var init_installer = __esm(() => {
3973
4002
  init_registry();
3974
4003
  __dirname2 = dirname(fileURLToPath(import.meta.url));
3975
4004
  HOOKS_DIR = existsSync(join(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join(__dirname2, "..", "..", "hooks") : join(__dirname2, "..", "hooks");
4005
+ EVENT_MAP = {
4006
+ claude: {
4007
+ PreToolUse: "PreToolUse",
4008
+ PostToolUse: "PostToolUse",
4009
+ Stop: "Stop",
4010
+ Notification: "Notification"
4011
+ },
4012
+ gemini: {
4013
+ PreToolUse: "BeforeTool",
4014
+ PostToolUse: "AfterTool",
4015
+ Stop: "AfterAgent",
4016
+ Notification: "Notification"
4017
+ }
4018
+ };
3976
4019
  });
3977
4020
 
3978
4021
  // src/mcp/server.ts
@@ -3995,7 +4038,7 @@ function createHooksServer() {
3995
4038
  name: "@hasna/hooks",
3996
4039
  version: "0.0.7"
3997
4040
  });
3998
- server.tool("hooks_list", "List all available Claude Code hooks, optionally filtered by category", { category: z.string().optional().describe("Filter by category name (e.g. 'Git Safety', 'Code Quality', 'Security', 'Notifications', 'Context Management')") }, async ({ category }) => {
4041
+ server.tool("hooks_list", "List all available hooks, optionally filtered by category", { category: z.string().optional().describe("Filter by category name (e.g. 'Git Safety', 'Code Quality', 'Security', 'Notifications', 'Context Management')") }, async ({ category }) => {
3999
4042
  if (category) {
4000
4043
  const cat = CATEGORIES.find((c) => c.toLowerCase() === category.toLowerCase());
4001
4044
  if (!cat) {
@@ -4022,7 +4065,7 @@ function createHooksServer() {
4022
4065
  const projectInstalled = getRegisteredHooks("project").includes(meta.name);
4023
4066
  return { content: [{ type: "text", text: JSON.stringify({ ...meta, global: globalInstalled, project: projectInstalled }) }] };
4024
4067
  });
4025
- server.tool("hooks_install", "Install one or more hooks by registering them in Claude settings. Use scope 'global' for ~/.claude/settings.json or 'project' for .claude/settings.json", {
4068
+ server.tool("hooks_install", "Install one or more hooks by registering them in agent settings", {
4026
4069
  hooks: z.array(z.string()).describe("Hook names to install"),
4027
4070
  scope: z.enum(["global", "project"]).default("global").describe("Install scope"),
4028
4071
  overwrite: z.boolean().default(false).describe("Overwrite if already installed")
@@ -4082,7 +4125,7 @@ function createHooksServer() {
4082
4125
  }]
4083
4126
  };
4084
4127
  });
4085
- server.tool("hooks_remove", "Remove (unregister) a hook from Claude settings", {
4128
+ server.tool("hooks_remove", "Remove (unregister) a hook from agent settings", {
4086
4129
  name: z.string().describe("Hook name to remove"),
4087
4130
  scope: z.enum(["global", "project"]).default("global").describe("Scope to remove from")
4088
4131
  }, async ({ name, scope }) => {
@@ -4153,7 +4196,7 @@ function createHooksServer() {
4153
4196
  content: [{
4154
4197
  type: "text",
4155
4198
  text: JSON.stringify({
4156
- overview: "Claude Code hooks are scripts that run at specific points in a Claude Code session. Install @hasna/hooks globally, then register hooks \u2014 no files are copied to your project.",
4199
+ overview: "Hooks are scripts that run at specific points in an AI coding agent session. Install @hasna/hooks globally, then register hooks \u2014 no files are copied to your project.",
4157
4200
  events: {
4158
4201
  PreToolUse: "Fires before a tool executes. Can block the operation.",
4159
4202
  PostToolUse: "Fires after a tool executes. Runs asynchronously.",
@@ -5425,11 +5468,11 @@ function resolveScope(options) {
5425
5468
  return "project";
5426
5469
  return "global";
5427
5470
  }
5428
- program2.name("hooks").description("Install Claude Code hooks for your project").version("0.1.0");
5471
+ program2.name("hooks").description("Install hooks for AI coding agents").version("0.1.1");
5429
5472
  program2.command("interactive", { isDefault: true }).alias("i").description("Interactive hook browser").action(() => {
5430
5473
  render(/* @__PURE__ */ jsxDEV8(App, {}, undefined, false, undefined, this));
5431
5474
  });
5432
- program2.command("run").argument("<hook>", "Hook to run").description("Execute a hook (called by Claude Code)").action(async (hook) => {
5475
+ program2.command("run").argument("<hook>", "Hook to run").description("Execute a hook (called by AI coding agents)").action(async (hook) => {
5433
5476
  const meta = getHook(hook);
5434
5477
  if (!meta) {
5435
5478
  console.error(JSON.stringify({ error: `Hook '${hook}' not found` }));
@@ -5512,7 +5555,7 @@ Installing hooks (${scope})...
5512
5555
  console.log(chalk2.dim(`
5513
5556
  Registered in ${settingsFile}`));
5514
5557
  });
5515
- program2.command("list").alias("ls").option("-c, --category <category>", "Filter by category").option("-a, --all", "Show all available hooks", false).option("-i, --installed", "Show only installed hooks", false).option("-r, --registered", "Show hooks registered in Claude settings", false).option("-g, --global", "Check global settings", false).option("-p, --project", "Check project settings", false).option("-j, --json", "Output as JSON", false).description("List available or installed hooks").action((options) => {
5558
+ program2.command("list").alias("ls").option("-c, --category <category>", "Filter by category").option("-a, --all", "Show all available hooks", false).option("-i, --installed", "Show only installed hooks", false).option("-r, --registered", "Show registered hooks", false).option("-g, --global", "Check global settings", false).option("-p, --project", "Check project settings", false).option("-j, --json", "Output as JSON", false).description("List available or installed hooks").action((options) => {
5516
5559
  const scope = resolveScope(options);
5517
5560
  if (options.registered || options.installed) {
5518
5561
  const registered = getRegisteredHooks(scope);
@@ -5822,11 +5865,11 @@ ${meta.displayName} v${meta.version}
5822
5865
  return;
5823
5866
  }
5824
5867
  const generalDocs = {
5825
- overview: "Claude Code hooks are scripts that run at specific points in a Claude Code session. Install @hasna/hooks globally, then register hooks \u2014 no files are copied to your project.",
5868
+ overview: "Hooks are scripts that run at specific points in an AI coding agent session. Install @hasna/hooks globally, then register hooks \u2014 no files are copied to your project.",
5826
5869
  events: {
5827
5870
  PreToolUse: 'Fires before a tool executes. Can block the operation by returning { "decision": "block" }.',
5828
5871
  PostToolUse: "Fires after a tool executes. Runs asynchronously, cannot block.",
5829
- Stop: "Fires when a Claude Code session ends. Useful for notifications and cleanup.",
5872
+ Stop: "Fires when a session ends. Useful for notifications and cleanup.",
5830
5873
  Notification: "Fires on notification events like context compaction."
5831
5874
  },
5832
5875
  installation: {
@@ -5848,7 +5891,7 @@ ${meta.displayName} v${meta.version}
5848
5891
  howItWorks: {
5849
5892
  install: "bun install -g @hasna/hooks",
5850
5893
  register: "hooks install gitguard \u2192 writes to ~/.claude/settings.json",
5851
- execution: "Claude Code runs 'hooks run gitguard' \u2192 executes hook from global package",
5894
+ execution: "Agent runs 'hooks run gitguard' \u2192 executes hook from global package",
5852
5895
  noFileCopy: "No files are copied to your project. Hooks run from the global @hasna/hooks package."
5853
5896
  }
5854
5897
  };
@@ -5894,7 +5937,7 @@ ${meta.displayName} v${meta.version}
5894
5937
  console.log(` hooks docs --json Machine-readable documentation`);
5895
5938
  console.log();
5896
5939
  });
5897
- program2.command("mcp").option("-s, --stdio", "Use stdio transport (for Claude Code integration)", false).option("-p, --port <port>", "Port for SSE transport", "39427").description("Start MCP server for AI agent integration").action(async (options) => {
5940
+ program2.command("mcp").option("-s, --stdio", "Use stdio transport (for agent MCP integration)", false).option("-p, --port <port>", "Port for SSE transport", "39427").description("Start MCP server for AI agent integration").action(async (options) => {
5898
5941
  if (options.stdio) {
5899
5942
  const { startStdioServer: startStdioServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
5900
5943
  await startStdioServer2();
package/dist/index.js CHANGED
@@ -331,11 +331,31 @@ import { homedir } from "os";
331
331
  import { fileURLToPath } from "url";
332
332
  var __dirname2 = dirname(fileURLToPath(import.meta.url));
333
333
  var HOOKS_DIR = existsSync(join(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join(__dirname2, "..", "..", "hooks") : join(__dirname2, "..", "hooks");
334
- function getSettingsPath(scope = "global") {
334
+ var EVENT_MAP = {
335
+ claude: {
336
+ PreToolUse: "PreToolUse",
337
+ PostToolUse: "PostToolUse",
338
+ Stop: "Stop",
339
+ Notification: "Notification"
340
+ },
341
+ gemini: {
342
+ PreToolUse: "BeforeTool",
343
+ PostToolUse: "AfterTool",
344
+ Stop: "AfterAgent",
345
+ Notification: "Notification"
346
+ }
347
+ };
348
+ function getTargetSettingsDir(target) {
349
+ if (target === "gemini")
350
+ return ".gemini";
351
+ return ".claude";
352
+ }
353
+ function getSettingsPath(scope = "global", target = "claude") {
354
+ const dir = getTargetSettingsDir(target);
335
355
  if (scope === "project") {
336
- return join(process.cwd(), ".claude", "settings.json");
356
+ return join(process.cwd(), dir, "settings.json");
337
357
  }
338
- return join(homedir(), ".claude", "settings.json");
358
+ return join(homedir(), dir, "settings.json");
339
359
  }
340
360
  function getHookPath(name) {
341
361
  const hookName = name.startsWith("hook-") ? name : `hook-${name}`;
@@ -344,8 +364,8 @@ function getHookPath(name) {
344
364
  function hookExists(name) {
345
365
  return existsSync(getHookPath(name));
346
366
  }
347
- function readSettings(scope = "global") {
348
- const path = getSettingsPath(scope);
367
+ function readSettings(scope = "global", target = "claude") {
368
+ const path = getSettingsPath(scope, target);
349
369
  try {
350
370
  if (existsSync(path)) {
351
371
  return JSON.parse(readFileSync(path, "utf-8"));
@@ -353,8 +373,8 @@ function readSettings(scope = "global") {
353
373
  } catch {}
354
374
  return {};
355
375
  }
356
- function writeSettings(settings, scope = "global") {
357
- const path = getSettingsPath(scope);
376
+ function writeSettings(settings, scope = "global", target = "claude") {
377
+ const path = getSettingsPath(scope, target);
358
378
  const dir = dirname(path);
359
379
  if (!existsSync(dir)) {
360
380
  mkdirSync(dir, { recursive: true });
@@ -362,36 +382,48 @@ function writeSettings(settings, scope = "global") {
362
382
  writeFileSync(path, JSON.stringify(settings, null, 2) + `
363
383
  `);
364
384
  }
365
- function installHook(name, options = {}) {
366
- const { scope = "global", overwrite = false } = options;
385
+ function getTargetEventName(internalEvent, target) {
386
+ return EVENT_MAP[target]?.[internalEvent] || internalEvent;
387
+ }
388
+ function installForTarget(name, scope, overwrite, target) {
367
389
  const hookName = name.startsWith("hook-") ? name : `hook-${name}`;
368
390
  const shortName = hookName.replace("hook-", "");
369
391
  if (!hookExists(shortName)) {
370
- return { hook: shortName, success: false, error: `Hook '${shortName}' not found` };
392
+ return { hook: shortName, success: false, error: `Hook '${shortName}' not found`, target };
371
393
  }
372
- const registered = getRegisteredHooks(scope);
394
+ const registered = getRegisteredHooksForTarget(scope, target);
373
395
  if (registered.includes(shortName) && !overwrite) {
374
- return { hook: shortName, success: false, error: "Already installed. Use --overwrite to replace.", scope };
396
+ return { hook: shortName, success: false, error: "Already installed. Use --overwrite to replace.", scope, target };
375
397
  }
376
398
  try {
377
- registerHook(shortName, scope);
378
- return { hook: shortName, success: true, scope };
399
+ registerHook(shortName, scope, target);
400
+ return { hook: shortName, success: true, scope, target };
379
401
  } catch (error) {
380
402
  return {
381
403
  hook: shortName,
382
404
  success: false,
383
- error: error instanceof Error ? error.message : "Unknown error"
405
+ error: error instanceof Error ? error.message : "Unknown error",
406
+ target
384
407
  };
385
408
  }
386
409
  }
387
- function registerHook(name, scope = "global") {
410
+ function installHook(name, options = {}) {
411
+ const { scope = "global", overwrite = false, target = "claude" } = options;
412
+ if (target === "all") {
413
+ const claudeResult = installForTarget(name, scope, overwrite, "claude");
414
+ installForTarget(name, scope, overwrite, "gemini");
415
+ return { ...claudeResult, target: "all" };
416
+ }
417
+ return installForTarget(name, scope, overwrite, target);
418
+ }
419
+ function registerHook(name, scope = "global", target = "claude") {
388
420
  const meta = getHook(name);
389
421
  if (!meta)
390
422
  return;
391
- const settings = readSettings(scope);
423
+ const settings = readSettings(scope, target);
392
424
  if (!settings.hooks)
393
425
  settings.hooks = {};
394
- const eventKey = meta.event;
426
+ const eventKey = getTargetEventName(meta.event, target);
395
427
  if (!settings.hooks[eventKey])
396
428
  settings.hooks[eventKey] = [];
397
429
  const hookCommand = `hooks run ${name}`;
@@ -403,16 +435,16 @@ function registerHook(name, scope = "global") {
403
435
  entry.matcher = meta.matcher;
404
436
  }
405
437
  settings.hooks[eventKey].push(entry);
406
- writeSettings(settings, scope);
438
+ writeSettings(settings, scope, target);
407
439
  }
408
- function unregisterHook(name, scope = "global") {
440
+ function unregisterHook(name, scope = "global", target = "claude") {
409
441
  const meta = getHook(name);
410
442
  if (!meta)
411
443
  return;
412
- const settings = readSettings(scope);
444
+ const settings = readSettings(scope, target);
413
445
  if (!settings.hooks)
414
446
  return;
415
- const eventKey = meta.event;
447
+ const eventKey = getTargetEventName(meta.event, target);
416
448
  if (!settings.hooks[eventKey])
417
449
  return;
418
450
  const hookCommand = `hooks run ${name}`;
@@ -423,13 +455,13 @@ function unregisterHook(name, scope = "global") {
423
455
  if (Object.keys(settings.hooks).length === 0) {
424
456
  delete settings.hooks;
425
457
  }
426
- writeSettings(settings, scope);
458
+ writeSettings(settings, scope, target);
427
459
  }
428
460
  function installHooks(names, options = {}) {
429
461
  return names.map((name) => installHook(name, options));
430
462
  }
431
- function getRegisteredHooks(scope = "global") {
432
- const settings = readSettings(scope);
463
+ function getRegisteredHooksForTarget(scope = "global", target = "claude") {
464
+ const settings = readSettings(scope, target);
433
465
  if (!settings.hooks)
434
466
  return [];
435
467
  const registered = [];
@@ -447,17 +479,28 @@ function getRegisteredHooks(scope = "global") {
447
479
  }
448
480
  return [...new Set(registered)];
449
481
  }
482
+ function getRegisteredHooks(scope = "global") {
483
+ return getRegisteredHooksForTarget(scope, "claude");
484
+ }
450
485
  function getInstalledHooks(scope = "global") {
451
486
  return getRegisteredHooks(scope);
452
487
  }
453
- function removeHook(name, scope = "global") {
488
+ function removeHook(name, scope = "global", target = "claude") {
454
489
  const hookName = name.startsWith("hook-") ? name : `hook-${name}`;
455
490
  const shortName = hookName.replace("hook-", "");
456
- const registered = getRegisteredHooks(scope);
457
- if (!registered.includes(shortName)) {
491
+ if (target === "all") {
492
+ const claudeRemoved = removeHookForTarget(shortName, scope, "claude");
493
+ const geminiRemoved = removeHookForTarget(shortName, scope, "gemini");
494
+ return claudeRemoved || geminiRemoved;
495
+ }
496
+ return removeHookForTarget(shortName, scope, target);
497
+ }
498
+ function removeHookForTarget(name, scope, target) {
499
+ const registered = getRegisteredHooksForTarget(scope, target);
500
+ if (!registered.includes(name)) {
458
501
  return false;
459
502
  }
460
- unregisterHook(shortName, scope);
503
+ unregisterHook(name, scope, target);
461
504
  return true;
462
505
  }
463
506
  export {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hasna/hooks",
3
- "version": "0.1.0",
4
- "description": "Open source Claude Code hooks library - Install hooks with a single command",
3
+ "version": "0.1.1",
4
+ "description": "Open source hooks library for AI coding agents - Install safety, quality, and automation hooks with a single command",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "hooks": "bin/index.js"