@goodfoot/claude-code-hooks 1.2.3 → 1.2.6

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/README.md CHANGED
@@ -211,8 +211,11 @@ The Logger is **silent by default** — no output to stdout, stderr, or files un
211
211
  # Option A: Environment Variable
212
212
  export CLAUDE_CODE_HOOKS_LOG_FILE=/tmp/claude-hooks.log
213
213
 
214
- # Option B: CLI Argument (during build)
214
+ # Option B: CLI Argument — hardcodes path into bundle (runtime CLAUDE_CODE_HOOKS_LOG_FILE overrides)
215
215
  npx -y @goodfoot/claude-code-hooks ... --log /tmp/claude-hooks.log
216
+
217
+ # Option C: CLI Argument — embed the env var name instead of a hardcoded path (good for worktrees)
218
+ npx -y @goodfoot/claude-code-hooks ... --log-env-var CLAUDE_CODE_HOOKS_LOG_FILE
216
219
  ```
217
220
 
218
221
  **View logs:**
@@ -231,9 +234,12 @@ import { Logger } from '@goodfoot/claude-code-hooks';
231
234
  // Silent by default — perfect for unit tests
232
235
  const logger = new Logger();
233
236
 
234
- // With file output
237
+ // With file output (hardcoded path)
235
238
  const fileLogger = new Logger({ logFilePath: '/tmp/my-hooks.log' });
236
239
 
240
+ // With dynamic path via env var
241
+ const envLogger = new Logger({ logEnvVar: 'MY_PLUGIN_LOG_FILE' });
242
+
237
243
  // Subscribe to events programmatically
238
244
  const unsubscribe = logger.on('error', (event) => {
239
245
  sendToMonitoring(event);
package/dist/cli.js CHANGED
@@ -68,11 +68,19 @@ Scaffold Mode (create new hook project):
68
68
 
69
69
  Optional Arguments:
70
70
  --log <path>
71
- Path to a log file for runtime hook logging.
72
- If provided, all context.logger calls within your hooks will write to this file.
73
- This is equivalent to setting the CLAUDE_CODE_HOOKS_LOG_FILE environment variable.
71
+ Hardcode a log file path into the compiled bundle.
72
+ All context.logger calls within your hooks will write to this file.
73
+ A runtime CLAUDE_CODE_HOOKS_LOG_FILE env var overrides this hardcoded path.
74
+ Cannot be combined with --log-env-var.
74
75
  Example: "/tmp/claude-hooks.log"
75
76
 
77
+ --log-env-var <var>
78
+ Name of the environment variable that will supply the log file path at runtime.
79
+ The Logger reads process.env[VAR_NAME] at startup instead of a hardcoded path.
80
+ Use this when the log path must be determined dynamically (e.g. across worktrees).
81
+ Cannot be combined with --log.
82
+ Example: --log-env-var MY_PLUGIN_LOG_FILE
83
+
76
84
  --executable <path>
77
85
  Node executable path to use in generated commands (default: "node").
78
86
  Use this to specify a custom node path in the generated hooks.json commands.
@@ -88,9 +96,12 @@ Examples:
88
96
  1. Basic Compilation:
89
97
  npx -y @goodfoot/claude-code-hooks -i "hooks/**/*.ts" -o "dist/hooks.json"
90
98
 
91
- 2. With Runtime Logging:
99
+ 2. With Hardcoded Log Path:
92
100
  npx -y @goodfoot/claude-code-hooks -i "src/hooks/*.ts" -o "bin/hooks.json" --log /tmp/claude-hooks.log
93
101
 
102
+ 2b. With Dynamic Log Path (env var set at runtime):
103
+ npx -y @goodfoot/claude-code-hooks -i "src/hooks/*.ts" -o "bin/hooks.json" --log-env-var CLAUDE_CODE_HOOKS_LOG_FILE
104
+
94
105
  3. Scaffold a New Hook Project:
95
106
  npx -y @goodfoot/claude-code-hooks --scaffold ./my-hooks --hooks Stop,SubagentStop -o dist/hooks.json
96
107
 
@@ -106,7 +117,7 @@ Examples:
106
117
  Troubleshooting:
107
118
  - Ensure your hook files use 'export default'.
108
119
  - Use absolute paths in your glob patterns if relative paths aren't finding files.
109
- - Check the log file specified by --log if hooks don't seem to run.
120
+ - Check the log file specified by --log (or the env var named by --log-env-var) if hooks don't seem to run.
110
121
  `;
111
122
  // ============================================================================
112
123
  // Logging
@@ -182,6 +193,9 @@ function parseArgs(argv) {
182
193
  case "--log":
183
194
  args.log = argv[++i];
184
195
  break;
196
+ case "--log-env-var":
197
+ args.logEnvVar = argv[++i];
198
+ break;
185
199
  case "-h":
186
200
  case "--help":
187
201
  args.help = true;
@@ -227,6 +241,9 @@ function validateArgs(args) {
227
241
  return undefined;
228
242
  }
229
243
  // Normal build mode validation
244
+ if (args.log !== undefined && args.logEnvVar !== undefined) {
245
+ return "Cannot use --log and --log-env-var together: choose one method to configure log output";
246
+ }
230
247
  if (args.input === "") {
231
248
  return "Missing required argument: -i/--input <glob>";
232
249
  }
@@ -386,13 +403,9 @@ async function discoverHookFiles(pattern, cwd) {
386
403
  * @returns Compiled content and stable content hash
387
404
  */
388
405
  async function compileHook(options) {
389
- const { sourcePath, logFilePath } = options;
406
+ const { sourcePath, logFilePath, logEnvVar } = options;
390
407
  // Get the path to the runtime module (absolute, then converted to relative)
391
408
  const runtimePathAbsolute = path.resolve(path.dirname(new URL(import.meta.url).pathname), "./runtime.js");
392
- // Build log file injection code if specified
393
- const logFileInjection = logFilePath !== undefined
394
- ? `process.env['CLAUDE_CODE_HOOKS_CLI_LOG_FILE'] = ${JSON.stringify(logFilePath)};\n`
395
- : "";
396
409
  // Compute relative paths from resolveDir to avoid absolute paths in source maps.
397
410
  // This ensures reproducible builds regardless of checkout directory.
398
411
  const resolveDir = path.dirname(sourcePath);
@@ -400,8 +413,7 @@ async function compileHook(options) {
400
413
  const relativeRuntimePath = path.relative(resolveDir, runtimePathAbsolute);
401
414
  // Create wrapper content that imports the hook and calls execute
402
415
  // Uses relative paths to produce reproducible builds
403
- const wrapperContent = `${logFileInjection}
404
- import hook from '${relativeSourcePath.replace(/\\/g, "/")}';
416
+ const wrapperContent = `import hook from '${relativeSourcePath.replace(/\\/g, "/")}';
405
417
  import { execute } from '${relativeRuntimePath.replace(/\\/g, "/")}';
406
418
 
407
419
  execute(hook);
@@ -419,6 +431,22 @@ execute(hook);
419
431
  // Banner to polyfill CJS globals for dependencies bundled into ESM.
420
432
  // Some packages (e.g. typescript) use require(), __filename, and __dirname
421
433
  // internally, which are unavailable in ESM scope.
434
+ //
435
+ // Log configuration is also embedded here (before all bundled code) so the
436
+ // Logger singleton reads it at construction time.
437
+ //
438
+ // --log PATH: sets CLAUDE_CODE_HOOKS_LOG_FILE if not already present
439
+ // (runtime env var wins over the hardcoded path)
440
+ // --log-env-var NAME: unconditionally sets CLAUDE_CODE_HOOKS_LOG_ENV_VAR
441
+ // (the var name is fixed at build time, no runtime override)
442
+ const logFileLines = logFilePath !== undefined
443
+ ? [
444
+ `if (!process.env['CLAUDE_CODE_HOOKS_LOG_FILE']) {`,
445
+ ` process.env['CLAUDE_CODE_HOOKS_LOG_FILE'] = ${JSON.stringify(logFilePath)};`,
446
+ `}`,
447
+ ]
448
+ : [];
449
+ const logEnvVarLines = logEnvVar !== undefined ? [`process.env['CLAUDE_CODE_HOOKS_LOG_ENV_VAR'] = ${JSON.stringify(logEnvVar)};`] : [];
422
450
  const esmRequireBanner = [
423
451
  `import { createRequire as __createRequire } from "node:module";`,
424
452
  `import { fileURLToPath as __fileURLToPath } from "node:url";`,
@@ -426,6 +454,8 @@ execute(hook);
426
454
  `const require = __createRequire(import.meta.url);`,
427
455
  `const __filename = __fileURLToPath(import.meta.url);`,
428
456
  `const __dirname = __pathDirname(__filename);`,
457
+ ...logFileLines,
458
+ ...logEnvVarLines,
429
459
  ].join("\n");
430
460
  // Common esbuild options
431
461
  const commonOptions = {
@@ -498,7 +528,7 @@ function generateContentHash(content) {
498
528
  * @returns Array of compiled hook information
499
529
  */
500
530
  async function compileAllHooks(options) {
501
- const { hookFiles, outputDir, logFilePath } = options;
531
+ const { hookFiles, outputDir, logFilePath, logEnvVar } = options;
502
532
  const compiledHooks = [];
503
533
  // Ensure output directory exists
504
534
  if (!fs.existsSync(outputDir)) {
@@ -518,7 +548,7 @@ async function compileAllHooks(options) {
518
548
  });
519
549
  // Compile the hook (two-step process for stable content hash)
520
550
  log("info", `Compiling: ${sourcePath}`);
521
- const { content, contentHash } = await compileHook({ sourcePath, outputDir, logFilePath });
551
+ const { content, contentHash } = await compileHook({ sourcePath, outputDir, logFilePath, logEnvVar });
522
552
  // Determine output filename using the stable content hash
523
553
  const baseName = path.basename(sourcePath, path.extname(sourcePath));
524
554
  const outputFilename = `${baseName}.${contentHash}.mjs`;
@@ -803,8 +833,8 @@ function writeHooksJson(hooksJson, outputPath) {
803
833
  try {
804
834
  fs.unlinkSync(tempPath);
805
835
  }
806
- catch {
807
- // Ignore cleanup errors
836
+ catch (cleanupError) {
837
+ log("warn", "Failed to clean up temp file", { path: tempPath, error: cleanupError });
808
838
  }
809
839
  }
810
840
  throw error;
@@ -852,12 +882,16 @@ async function main() {
852
882
  const hooksJsonDir = path.dirname(outputPath);
853
883
  // Compiled hooks go in a 'bin' subdirectory relative to hooks.json
854
884
  const buildDir = path.join(hooksJsonDir, "bin");
855
- // Resolve log file path to absolute if provided
856
- const logFilePath = args.log !== undefined ? path.resolve(cwd, args.log) : undefined;
885
+ // Resolve log file path: --log flag takes priority, then CLAUDE_CODE_HOOKS_LOG_FILE env var
886
+ const logFileRaw = args.log ?? process.env.CLAUDE_CODE_HOOKS_LOG_FILE;
887
+ const logFilePath = logFileRaw !== undefined ? path.resolve(cwd, logFileRaw) : undefined;
888
+ // --log-env-var names the env var the Logger should read at runtime
889
+ const logEnvVar = args.logEnvVar;
857
890
  log("info", "Starting hook compilation", {
858
891
  input: args.input,
859
892
  output: args.output,
860
893
  logFilePath,
894
+ logEnvVar,
861
895
  cwd,
862
896
  });
863
897
  // Discover hook files
@@ -880,7 +914,7 @@ async function main() {
880
914
  log("info", `Preserved ${preservedCount} hooks from other sources`);
881
915
  }
882
916
  // Compile all hooks
883
- const compiledHooks = await compileAllHooks({ hookFiles, outputDir: buildDir, logFilePath });
917
+ const compiledHooks = await compileAllHooks({ hookFiles, outputDir: buildDir, logFilePath, logEnvVar });
884
918
  if (compiledHooks.length === 0 && hookFiles.length > 0) {
885
919
  process.stderr.write("Error: No valid hooks found in discovered files.\n");
886
920
  process.exit(1);
package/dist/constants.js CHANGED
@@ -29,4 +29,6 @@ export const HOOK_FACTORY_TO_EVENT = {
29
29
  instructionsLoadedHook: "InstructionsLoaded",
30
30
  worktreeCreateHook: "WorktreeCreate",
31
31
  worktreeRemoveHook: "WorktreeRemove",
32
+ cwdChangedHook: "CwdChanged",
33
+ fileChangedHook: "FileChanged",
32
34
  };
package/dist/hooks.js CHANGED
@@ -741,3 +741,67 @@ export function worktreeCreateHook(config, handler) {
741
741
  export function worktreeRemoveHook(config, handler) {
742
742
  return createHookFunction("WorktreeRemove", config, handler);
743
743
  }
744
+ // ============================================================================
745
+ // CwdChanged Hook Factory
746
+ // ============================================================================
747
+ /**
748
+ * Creates a CwdChanged hook handler.
749
+ *
750
+ * CwdChanged hooks fire when Claude Code's current working directory changes,
751
+ * allowing you to:
752
+ * - React to directory changes within a session
753
+ * - Update file watchers or environment state
754
+ * - Return `watchPaths` via `hookSpecificOutput` to register paths for FileChanged events
755
+ *
756
+ * **Matcher**: No matcher support - fires on all cwd change events
757
+ * @param config - Hook configuration with optional timeout
758
+ * @param handler - The handler function to execute
759
+ * @returns A hook function that can be exported as the default export
760
+ * @example
761
+ * ```typescript
762
+ * import { cwdChangedHook, cwdChangedOutput } from '@goodfoot/claude-code-hooks';
763
+ *
764
+ * export default cwdChangedHook({}, async (input, { logger }) => {
765
+ * logger.info('Working directory changed', { from: input.old_cwd, to: input.new_cwd });
766
+ * return cwdChangedOutput({});
767
+ * });
768
+ * ```
769
+ * @see https://code.claude.com/docs/en/hooks#cwdchanged
770
+ */
771
+ export function cwdChangedHook(config, handler) {
772
+ return createHookFunction("CwdChanged", config, handler);
773
+ }
774
+ // ============================================================================
775
+ // FileChanged Hook Factory
776
+ // ============================================================================
777
+ /**
778
+ * Creates a FileChanged hook handler.
779
+ *
780
+ * FileChanged hooks fire when a watched file changes on disk, allowing you to:
781
+ * - React to file system changes during a session
782
+ * - Invalidate caches or reload configuration
783
+ * - Return `watchPaths` via `hookSpecificOutput` to update the set of watched paths
784
+ *
785
+ * The input `event` field indicates the type of change:
786
+ * - `'change'` - File contents changed
787
+ * - `'add'` - File was created
788
+ * - `'unlink'` - File was deleted
789
+ *
790
+ * **Matcher**: No matcher support - fires on all file change events
791
+ * @param config - Hook configuration with optional timeout
792
+ * @param handler - The handler function to execute
793
+ * @returns A hook function that can be exported as the default export
794
+ * @example
795
+ * ```typescript
796
+ * import { fileChangedHook, fileChangedOutput } from '@goodfoot/claude-code-hooks';
797
+ *
798
+ * export default fileChangedHook({}, async (input, { logger }) => {
799
+ * logger.info('File changed', { path: input.file_path, event: input.event });
800
+ * return fileChangedOutput({});
801
+ * });
802
+ * ```
803
+ * @see https://code.claude.com/docs/en/hooks#filechanged
804
+ */
805
+ export function fileChangedHook(config, handler) {
806
+ return createHookFunction("FileChanged", config, handler);
807
+ }
package/dist/index.js CHANGED
@@ -11,15 +11,15 @@ export {
11
11
  CLAUDE_ENV_VARS, getEnvFilePath,
12
12
  // Getters
13
13
  getProjectDir, isRemoteEnvironment, } from "./env.js";
14
- // Hook factory functions - all 23 hook types
15
- export { configChangeHook, elicitationHook, elicitationResultHook, instructionsLoadedHook, notificationHook, permissionRequestHook, postCompactHook, postToolUseFailureHook, postToolUseHook, preCompactHook, preToolUseHook, sessionEndHook, sessionStartHook, setupHook, stopFailureHook, stopHook, subagentStartHook, subagentStopHook, taskCompletedHook, teammateIdleHook, userPromptSubmitHook, worktreeCreateHook, worktreeRemoveHook, } from "./hooks.js";
14
+ // Hook factory functions - all 25 hook types
15
+ export { configChangeHook, cwdChangedHook, elicitationHook, elicitationResultHook, fileChangedHook, instructionsLoadedHook, notificationHook, permissionRequestHook, postCompactHook, postToolUseFailureHook, postToolUseHook, preCompactHook, preToolUseHook, sessionEndHook, sessionStartHook, setupHook, stopFailureHook, stopHook, subagentStartHook, subagentStopHook, taskCompletedHook, teammateIdleHook, userPromptSubmitHook, worktreeCreateHook, worktreeRemoveHook, } from "./hooks.js";
16
16
  // Logger exports
17
17
  export { LOG_LEVELS, Logger, logger } from "./logger.js";
18
18
  // Output builder functions
19
- export { configChangeOutput,
19
+ export { configChangeOutput, cwdChangedOutput,
20
20
  // Exit codes
21
- EXIT_CODES, elicitationOutput, elicitationResultOutput, instructionsLoadedOutput, notificationOutput, permissionRequestOutput, postCompactOutput, postToolUseFailureOutput, postToolUseOutput, preCompactOutput,
22
- // All 23 output builder functions
21
+ EXIT_CODES, elicitationOutput, elicitationResultOutput, fileChangedOutput, instructionsLoadedOutput, notificationOutput, permissionRequestOutput, postCompactOutput, postToolUseFailureOutput, postToolUseOutput, preCompactOutput,
22
+ // All 25 output builder functions
23
23
  preToolUseOutput, sessionEndOutput, sessionStartOutput, setupOutput, stopFailureOutput, stopOutput, subagentStartOutput, subagentStopOutput, taskCompletedOutput, teammateIdleOutput, userPromptSubmitOutput, worktreeCreateOutput, worktreeRemoveOutput, } from "./outputs.js";
24
24
  // Runtime exports - execute function
25
25
  export {
package/dist/logger.js CHANGED
@@ -108,8 +108,8 @@ export class Logger {
108
108
  for (const level of LOG_LEVELS) {
109
109
  this.handlers.set(level, new Set());
110
110
  }
111
- // Set log file path from config or environment
112
- this.logFilePath = config.logFilePath ?? process.env.CLAUDE_CODE_HOOKS_LOG_FILE ?? null;
111
+ // Set log file path from explicit config, or by reading the configured env var
112
+ this.logFilePath = config.logFilePath ?? (config.logEnvVar ? process.env[config.logEnvVar] : undefined) ?? null;
113
113
  }
114
114
  /**
115
115
  * Logs a debug message.
@@ -290,8 +290,8 @@ export class Logger {
290
290
  try {
291
291
  closeSync(this.logFileFd);
292
292
  }
293
- catch {
294
- // Ignore errors on close
293
+ catch (closeError) {
294
+ process.stderr.write(`[claude-code-hooks] Failed to close log file: ${String(closeError)}\n`);
295
295
  }
296
296
  this.logFileFd = null;
297
297
  }
@@ -314,8 +314,8 @@ export class Logger {
314
314
  try {
315
315
  closeSync(this.logFileFd);
316
316
  }
317
- catch {
318
- // Ignore errors on close
317
+ catch (closeError) {
318
+ process.stderr.write(`[claude-code-hooks] Failed to close log file: ${String(closeError)}\n`);
319
319
  }
320
320
  this.logFileFd = null;
321
321
  }
@@ -366,8 +366,8 @@ export class Logger {
366
366
  try {
367
367
  handler(event);
368
368
  }
369
- catch {
370
- // Silently ignore handler errors to not disrupt hook execution
369
+ catch (handlerError) {
370
+ process.stderr.write(`[claude-code-hooks] Log handler error: ${String(handlerError)}\n`);
371
371
  }
372
372
  }
373
373
  }
@@ -391,10 +391,11 @@ export class Logger {
391
391
  const line = `${JSON.stringify(event)}\n`;
392
392
  writeSync(this.logFileFd, line);
393
393
  }
394
- catch {
395
- // Silently ignore file write errors to not disrupt hook execution
396
- // This follows the risk mitigation: "Graceful degradation - log write
397
- // failures are silently ignored to not disrupt hook execution"
394
+ catch (writeError) {
395
+ // Disable file logging after a write failure to avoid repeated errors
396
+ this.logFileFd = null;
397
+ this.fileInitialized = false;
398
+ process.stderr.write(`[claude-code-hooks] Log file write failed: ${String(writeError)}\n`);
398
399
  }
399
400
  }
400
401
  /**
@@ -500,4 +501,8 @@ export class Logger {
500
501
  * }
501
502
  * ```
502
503
  */
503
- export const logger = new Logger();
504
+ // CLAUDE_CODE_HOOKS_LOG_ENV_VAR is set unconditionally by the --log-env-var banner
505
+ // before this module initialises. If absent, fall back to the default env var name.
506
+ export const logger = new Logger({
507
+ logEnvVar: process.env.CLAUDE_CODE_HOOKS_LOG_ENV_VAR ?? "CLAUDE_CODE_HOOKS_LOG_FILE",
508
+ });
package/dist/outputs.js CHANGED
@@ -431,3 +431,39 @@ export const worktreeCreateOutput = /* @__PURE__ */ createSimpleOutputBuilder("W
431
431
  * ```
432
432
  */
433
433
  export const worktreeRemoveOutput = /* @__PURE__ */ createSimpleOutputBuilder("WorktreeRemove");
434
+ /**
435
+ * Creates an output for CwdChanged hooks.
436
+ * @param options - Configuration options for the hook output
437
+ * @returns A CwdChangedOutput object ready for the runtime
438
+ * @example
439
+ * ```typescript
440
+ * // Return additional paths to watch after the cwd change
441
+ * cwdChangedOutput({
442
+ * hookSpecificOutput: {
443
+ * watchPaths: ['/new/path/to/watch']
444
+ * }
445
+ * });
446
+ *
447
+ * // Simple passthrough
448
+ * cwdChangedOutput({});
449
+ * ```
450
+ */
451
+ export const cwdChangedOutput = /* @__PURE__ */ createHookSpecificOutputBuilder("CwdChanged");
452
+ /**
453
+ * Creates an output for FileChanged hooks.
454
+ * @param options - Configuration options for the hook output
455
+ * @returns A FileChangedOutput object ready for the runtime
456
+ * @example
457
+ * ```typescript
458
+ * // Update the set of watched paths
459
+ * fileChangedOutput({
460
+ * hookSpecificOutput: {
461
+ * watchPaths: ['/path/to/watch', '/another/path']
462
+ * }
463
+ * });
464
+ *
465
+ * // Simple passthrough
466
+ * fileChangedOutput({});
467
+ * ```
468
+ */
469
+ export const fileChangedOutput = /* @__PURE__ */ createHookSpecificOutputBuilder("FileChanged");
package/dist/runtime.js CHANGED
@@ -161,21 +161,6 @@ export function convertToHookOutput(specificOutput) {
161
161
  export async function execute(hookFn) {
162
162
  let output;
163
163
  try {
164
- // Check for log file configuration conflicts
165
- // CLAUDE_CODE_HOOKS_CLI_LOG_FILE is injected by the CLI --log parameter
166
- // CLAUDE_CODE_HOOKS_LOG_FILE is the user's environment variable
167
- const cliLogFile = process.env.CLAUDE_CODE_HOOKS_CLI_LOG_FILE;
168
- const envLogFile = process.env.CLAUDE_CODE_HOOKS_LOG_FILE;
169
- if (cliLogFile !== undefined && envLogFile !== undefined && cliLogFile !== envLogFile) {
170
- // Write error to stderr and exit with error code
171
- process.stderr.write(`Log file configuration conflict: CLI --log="${cliLogFile}" vs CLAUDE_CODE_HOOKS_LOG_FILE="${envLogFile}". ` +
172
- "Use only one method to configure hook logging.\n");
173
- process.exit(EXIT_CODES.ERROR);
174
- }
175
- // If CLI log file is set, configure the logger
176
- if (cliLogFile !== undefined) {
177
- logger.setLogFile(cliLogFile);
178
- }
179
164
  // Read and parse stdin
180
165
  let stdinContent;
181
166
  try {
package/dist/scaffold.js CHANGED
@@ -60,6 +60,8 @@ const EVENT_TO_OUTPUT_FUNCTION = {
60
60
  InstructionsLoaded: "instructionsLoadedOutput",
61
61
  WorktreeCreate: "worktreeCreateOutput",
62
62
  WorktreeRemove: "worktreeRemoveOutput",
63
+ CwdChanged: "cwdChangedOutput",
64
+ FileChanged: "fileChangedOutput",
63
65
  };
64
66
  // ============================================================================
65
67
  // Validation
@@ -127,7 +129,7 @@ function generatePackageJson(projectName, outputPath) {
127
129
  "@goodfoot/claude-code-hooks": "^1.0.9",
128
130
  },
129
131
  devDependencies: {
130
- "@biomejs/biome": "2.4.8",
132
+ "@biomejs/biome": "2.4.9",
131
133
  "@types/node": "^22.0.0",
132
134
  typescript: "^5.9.3",
133
135
  vitest: "^4.0.16",
@@ -170,7 +172,7 @@ function generateTsConfig() {
170
172
  */
171
173
  function generateBiomeConfig() {
172
174
  return `{
173
- "$schema": "https://biomejs.dev/schemas/2.4.8/schema.json",
175
+ "$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
174
176
  "formatter": {
175
177
  "enabled": true,
176
178
  "indentStyle": "space",
package/dist/types.js CHANGED
@@ -43,4 +43,6 @@ export const HOOK_EVENT_NAMES = [
43
43
  "InstructionsLoaded",
44
44
  "WorktreeCreate",
45
45
  "WorktreeRemove",
46
+ "CwdChanged",
47
+ "FileChanged",
46
48
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodfoot/claude-code-hooks",
3
- "version": "1.2.3",
3
+ "version": "1.2.6",
4
4
  "description": "Type-safe Claude Code hooks library with camelCase types and output builders",
5
5
  "homepage": "https://github.com/goodfoot-io/marketplace/tree/main/packages/claude-code-hooks",
6
6
  "repository": {
@@ -53,8 +53,8 @@
53
53
  "typescript": "^5.9.3"
54
54
  },
55
55
  "devDependencies": {
56
- "@anthropic-ai/claude-agent-sdk": "^0.2.80",
57
- "@biomejs/biome": "2.4.8",
56
+ "@anthropic-ai/claude-agent-sdk": "^0.2.83",
57
+ "@biomejs/biome": "2.4.9",
58
58
  "@types/node": "^24",
59
59
  "ts-morph": "^25.0.0",
60
60
  "tsx": "^4.20.3",
package/types/cli.d.ts CHANGED
@@ -31,8 +31,10 @@ interface CliArgs {
31
31
  input: string;
32
32
  /** Path for hooks.json output file. */
33
33
  output: string;
34
- /** Optional log file path. */
34
+ /** Optional log file path (hardcoded into bundle). */
35
35
  log?: string;
36
+ /** Optional env var name whose value supplies the log file path at runtime. */
37
+ logEnvVar?: string;
36
38
  /** Show help. */
37
39
  help: boolean;
38
40
  /** Show version. */
@@ -148,8 +150,10 @@ interface CompileHookOptions {
148
150
  sourcePath: string;
149
151
  /** Directory for compiled output. */
150
152
  outputDir: string;
151
- /** Optional log file path to inject into compiled hook. */
153
+ /** Optional log file path to hardcode into the bundle via the banner. */
152
154
  logFilePath?: string;
155
+ /** Optional env var name the Logger should read for the log file path at runtime. */
156
+ logEnvVar?: string;
153
157
  }
154
158
  /**
155
159
  * Result of compiling a hook.
package/types/hooks.d.ts CHANGED
@@ -22,8 +22,8 @@
22
22
  * @see https://code.claude.com/docs/en/hooks
23
23
  */
24
24
  import type { Logger } from "./logger.js";
25
- import type { ConfigChangeOutput, ElicitationOutput, ElicitationResultOutput, InstructionsLoadedOutput, NotificationOutput, PermissionRequestOutput, PostCompactOutput, PostToolUseFailureOutput, PostToolUseOutput, PreCompactOutput, PreToolUseOutput, SessionEndOutput, SessionStartOutput, SetupOutput, SpecificHookOutput, StopFailureOutput, StopOutput, SubagentStartOutput, SubagentStopOutput, TaskCompletedOutput, TeammateIdleOutput, UserPromptSubmitOutput, WorktreeCreateOutput, WorktreeRemoveOutput } from "./outputs.js";
26
- import type { ConfigChangeInput, ElicitationInput, ElicitationResultInput, HookEventName, InstructionsLoadedInput, KnownToolName, NotificationInput, PermissionRequestInput, PostCompactInput, PostToolUseFailureInput, PostToolUseInput, PreCompactInput, PreToolUseInput, SessionEndInput, SessionStartInput, SetupInput, StopFailureInput, StopInput, SubagentStartInput, SubagentStopInput, TaskCompletedInput, TeammateIdleInput, ToolInputMap, UserPromptSubmitInput, WorktreeCreateInput, WorktreeRemoveInput } from "./types.js";
25
+ import type { ConfigChangeOutput, CwdChangedOutput, ElicitationOutput, ElicitationResultOutput, FileChangedOutput, InstructionsLoadedOutput, NotificationOutput, PermissionRequestOutput, PostCompactOutput, PostToolUseFailureOutput, PostToolUseOutput, PreCompactOutput, PreToolUseOutput, SessionEndOutput, SessionStartOutput, SetupOutput, SpecificHookOutput, StopFailureOutput, StopOutput, SubagentStartOutput, SubagentStopOutput, TaskCompletedOutput, TeammateIdleOutput, UserPromptSubmitOutput, WorktreeCreateOutput, WorktreeRemoveOutput } from "./outputs.js";
26
+ import type { ConfigChangeInput, CwdChangedInput, ElicitationInput, ElicitationResultInput, FileChangedInput, HookEventName, InstructionsLoadedInput, KnownToolName, NotificationInput, PermissionRequestInput, PostCompactInput, PostToolUseFailureInput, PostToolUseInput, PreCompactInput, PreToolUseInput, SessionEndInput, SessionStartInput, SetupInput, StopFailureInput, StopInput, SubagentStartInput, SubagentStopInput, TaskCompletedInput, TeammateIdleInput, ToolInputMap, UserPromptSubmitInput, WorktreeCreateInput, WorktreeRemoveInput } from "./types.js";
27
27
  /**
28
28
  * Configuration options for hook factories.
29
29
  *
@@ -1072,4 +1072,58 @@ export declare function worktreeCreateHook(config: HookConfig, handler: HookHand
1072
1072
  * @see https://code.claude.com/docs/en/hooks#worktreeremove
1073
1073
  */
1074
1074
  export declare function worktreeRemoveHook(config: HookConfig, handler: HookHandler<WorktreeRemoveInput, WorktreeRemoveOutput>): HookFunction<WorktreeRemoveInput, WorktreeRemoveOutput>;
1075
+ /**
1076
+ * Creates a CwdChanged hook handler.
1077
+ *
1078
+ * CwdChanged hooks fire when Claude Code's current working directory changes,
1079
+ * allowing you to:
1080
+ * - React to directory changes within a session
1081
+ * - Update file watchers or environment state
1082
+ * - Return `watchPaths` via `hookSpecificOutput` to register paths for FileChanged events
1083
+ *
1084
+ * **Matcher**: No matcher support - fires on all cwd change events
1085
+ * @param config - Hook configuration with optional timeout
1086
+ * @param handler - The handler function to execute
1087
+ * @returns A hook function that can be exported as the default export
1088
+ * @example
1089
+ * ```typescript
1090
+ * import { cwdChangedHook, cwdChangedOutput } from '@goodfoot/claude-code-hooks';
1091
+ *
1092
+ * export default cwdChangedHook({}, async (input, { logger }) => {
1093
+ * logger.info('Working directory changed', { from: input.old_cwd, to: input.new_cwd });
1094
+ * return cwdChangedOutput({});
1095
+ * });
1096
+ * ```
1097
+ * @see https://code.claude.com/docs/en/hooks#cwdchanged
1098
+ */
1099
+ export declare function cwdChangedHook(config: HookConfig, handler: HookHandler<CwdChangedInput, CwdChangedOutput>): HookFunction<CwdChangedInput, CwdChangedOutput>;
1100
+ /**
1101
+ * Creates a FileChanged hook handler.
1102
+ *
1103
+ * FileChanged hooks fire when a watched file changes on disk, allowing you to:
1104
+ * - React to file system changes during a session
1105
+ * - Invalidate caches or reload configuration
1106
+ * - Return `watchPaths` via `hookSpecificOutput` to update the set of watched paths
1107
+ *
1108
+ * The input `event` field indicates the type of change:
1109
+ * - `'change'` - File contents changed
1110
+ * - `'add'` - File was created
1111
+ * - `'unlink'` - File was deleted
1112
+ *
1113
+ * **Matcher**: No matcher support - fires on all file change events
1114
+ * @param config - Hook configuration with optional timeout
1115
+ * @param handler - The handler function to execute
1116
+ * @returns A hook function that can be exported as the default export
1117
+ * @example
1118
+ * ```typescript
1119
+ * import { fileChangedHook, fileChangedOutput } from '@goodfoot/claude-code-hooks';
1120
+ *
1121
+ * export default fileChangedHook({}, async (input, { logger }) => {
1122
+ * logger.info('File changed', { path: input.file_path, event: input.event });
1123
+ * return fileChangedOutput({});
1124
+ * });
1125
+ * ```
1126
+ * @see https://code.claude.com/docs/en/hooks#filechanged
1127
+ */
1128
+ export declare function fileChangedHook(config: HookConfig, handler: HookHandler<FileChangedInput, FileChangedOutput>): HookFunction<FileChangedInput, FileChangedOutput>;
1075
1129
  export {};
package/types/index.d.ts CHANGED
@@ -8,15 +8,15 @@
8
8
  export type * from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
9
9
  export { CLAUDE_ENV_VARS, getEnvFilePath, getProjectDir, isRemoteEnvironment, } from "./env.js";
10
10
  export type { HookConfig, HookContext, HookFunction, HookHandler, SessionStartContext, TypedHookConfig, TypedPermissionRequestInput, TypedPostToolUseFailureHookInput, TypedPostToolUseHookInput, TypedPreToolUseHookInput, } from "./hooks.js";
11
- export { configChangeHook, elicitationHook, elicitationResultHook, instructionsLoadedHook, notificationHook, permissionRequestHook, postCompactHook, postToolUseFailureHook, postToolUseHook, preCompactHook, preToolUseHook, sessionEndHook, sessionStartHook, setupHook, stopFailureHook, stopHook, subagentStartHook, subagentStopHook, taskCompletedHook, teammateIdleHook, userPromptSubmitHook, worktreeCreateHook, worktreeRemoveHook, } from "./hooks.js";
11
+ export { configChangeHook, cwdChangedHook, elicitationHook, elicitationResultHook, fileChangedHook, instructionsLoadedHook, notificationHook, permissionRequestHook, postCompactHook, postToolUseFailureHook, postToolUseHook, preCompactHook, preToolUseHook, sessionEndHook, sessionStartHook, setupHook, stopFailureHook, stopHook, subagentStartHook, subagentStopHook, taskCompletedHook, teammateIdleHook, userPromptSubmitHook, worktreeCreateHook, worktreeRemoveHook, } from "./hooks.js";
12
12
  export type { LogEvent, LogEventError, LogEventHandler, LoggerConfig, LogLevel, Unsubscribe } from "./logger.js";
13
13
  export { LOG_LEVELS, Logger, logger } from "./logger.js";
14
14
  export type {
15
15
  /** @deprecated Use CommonOptions instead */
16
- BaseOptions, CommonOptions, ConfigChangeOptions, ElicitationHookSpecificOutput, ElicitationOptions, ElicitationResultHookSpecificOutput, ElicitationResultOptions, ExitCode, ExitCodeOptions, HookOutput, HookSpecificOutput, InstructionsLoadedOptions, NotificationHookSpecificOutput, NotificationOptions, PermissionRequestAllowDecision, PermissionRequestDecision, PermissionRequestDenyDecision, PermissionRequestHookSpecificOutput, PermissionRequestOptions, PostCompactOptions, PostToolUseFailureHookSpecificOutput, PostToolUseFailureOptions, PostToolUseHookSpecificOutput, PostToolUseOptions, PreCompactOptions, PreToolUseHookSpecificOutput, PreToolUseOptions, SessionEndOptions, SessionStartHookSpecificOutput, SessionStartOptions, SetupHookSpecificOutput, SetupOptions, StopFailureOptions, StopOptions, SubagentStartHookSpecificOutput, SubagentStartOptions, SubagentStopOptions, SyncHookJSONOutput, TaskCompletedOptions, TeammateIdleOptions, UserPromptSubmitHookSpecificOutput, UserPromptSubmitOptions, WorktreeCreateOptions, WorktreeRemoveOptions, } from "./outputs.js";
17
- export { configChangeOutput, EXIT_CODES, elicitationOutput, elicitationResultOutput, instructionsLoadedOutput, notificationOutput, permissionRequestOutput, postCompactOutput, postToolUseFailureOutput, postToolUseOutput, preCompactOutput, preToolUseOutput, sessionEndOutput, sessionStartOutput, setupOutput, stopFailureOutput, stopOutput, subagentStartOutput, subagentStopOutput, taskCompletedOutput, teammateIdleOutput, userPromptSubmitOutput, worktreeCreateOutput, worktreeRemoveOutput, } from "./outputs.js";
16
+ BaseOptions, CommonOptions, ConfigChangeOptions, CwdChangedHookSpecificOutput, CwdChangedOptions, ElicitationHookSpecificOutput, ElicitationOptions, ElicitationResultHookSpecificOutput, ElicitationResultOptions, ExitCode, ExitCodeOptions, FileChangedHookSpecificOutput, FileChangedOptions, HookOutput, HookSpecificOutput, InstructionsLoadedOptions, NotificationHookSpecificOutput, NotificationOptions, PermissionRequestAllowDecision, PermissionRequestDecision, PermissionRequestDenyDecision, PermissionRequestHookSpecificOutput, PermissionRequestOptions, PostCompactOptions, PostToolUseFailureHookSpecificOutput, PostToolUseFailureOptions, PostToolUseHookSpecificOutput, PostToolUseOptions, PreCompactOptions, PreToolUseHookSpecificOutput, PreToolUseOptions, SessionEndOptions, SessionStartHookSpecificOutput, SessionStartOptions, SetupHookSpecificOutput, SetupOptions, StopFailureOptions, StopOptions, SubagentStartHookSpecificOutput, SubagentStartOptions, SubagentStopOptions, SyncHookJSONOutput, TaskCompletedOptions, TeammateIdleOptions, UserPromptSubmitHookSpecificOutput, UserPromptSubmitOptions, WorktreeCreateOptions, WorktreeRemoveOptions, } from "./outputs.js";
17
+ export { configChangeOutput, cwdChangedOutput, EXIT_CODES, elicitationOutput, elicitationResultOutput, fileChangedOutput, instructionsLoadedOutput, notificationOutput, permissionRequestOutput, postCompactOutput, postToolUseFailureOutput, postToolUseOutput, preCompactOutput, preToolUseOutput, sessionEndOutput, sessionStartOutput, setupOutput, stopFailureOutput, stopOutput, subagentStartOutput, subagentStopOutput, taskCompletedOutput, teammateIdleOutput, userPromptSubmitOutput, worktreeCreateOutput, worktreeRemoveOutput, } from "./outputs.js";
18
18
  export { execute, } from "./runtime.js";
19
19
  export type { ContentContext, PatternCheckResult, ToolUseInput } from "./tool-helpers.js";
20
20
  export { checkContentForPattern, forEachContent, getFilePath, isAskUserQuestionTool, isBashTool, isConfigTool, isEditTool, isExitPlanModeTool, isFileModifyingTool, isGlobTool, isGrepTool, isJsTsFile, isKillShellTool, isListMcpResourcesTool, isMcpTool, isMultiEditTool, isNotebookEditTool, isReadMcpResourceTool, isReadTool, isTaskOutputTool, isTaskTool, isTodoWriteTool, isTsFile, isWebFetchTool, isWebSearchTool, isWriteTool, } from "./tool-helpers.js";
21
- export type { BaseHookInput, ConfigChangeInput, ConfigInput, ElicitationInput, ElicitationResultInput, FileModifyingToolInput, FileModifyingToolName, HookEventName, HookInput, InstructionsLoadedInput, KnownToolInput, KnownToolName, ListMcpResourcesInput, McpInput, MultiEditEntry, MultiEditToolInput, NotificationInput, PermissionMode, PermissionRequestInput, PermissionUpdate, PostCompactInput, PostToolUseFailureInput, PostToolUseInput, PreCompactInput, PreCompactTrigger, PreToolUseInput, ReadMcpResourceInput, SessionEndInput, SessionEndReason, SessionStartInput, SessionStartSource, SetupInput, SetupTrigger, StopFailureInput, StopInput, SubagentStartInput, SubagentStopInput, TaskCompletedInput, TeammateIdleInput, ToolInputMap, UserPromptSubmitInput, WorktreeCreateInput, WorktreeRemoveInput, } from "./types.js";
21
+ export type { BaseHookInput, ConfigChangeInput, ConfigInput, CwdChangedInput, ElicitationInput, ElicitationResultInput, FileChangedInput, FileModifyingToolInput, FileModifyingToolName, HookEventName, HookInput, InstructionsLoadedInput, KnownToolInput, KnownToolName, ListMcpResourcesInput, McpInput, MultiEditEntry, MultiEditToolInput, NotificationInput, PermissionMode, PermissionRequestInput, PermissionUpdate, PostCompactInput, PostToolUseFailureInput, PostToolUseInput, PreCompactInput, PreCompactTrigger, PreToolUseInput, ReadMcpResourceInput, SessionEndInput, SessionEndReason, SessionStartInput, SessionStartSource, SetupInput, SetupTrigger, StopFailureInput, StopInput, SubagentStartInput, SubagentStopInput, TaskCompletedInput, TeammateIdleInput, ToolInputMap, UserPromptSubmitInput, WorktreeCreateInput, WorktreeRemoveInput, } from "./types.js";
22
22
  export { HOOK_EVENT_NAMES } from "./types.js";
package/types/logger.d.ts CHANGED
@@ -147,9 +147,15 @@ export interface LoggerConfig {
147
147
  /**
148
148
  * Path to the log file for file output.
149
149
  * If not set, file logging is disabled.
150
- * Can also be set via `CLAUDE_CODE_HOOKS_LOG_FILE` environment variable.
151
150
  */
152
151
  logFilePath?: string;
152
+ /**
153
+ * Name of the environment variable to read for the log file path.
154
+ * When set, the Logger reads `process.env[logEnvVar]` at construction time.
155
+ * Ignored if `logFilePath` is also provided.
156
+ * Defaults to `'CLAUDE_CODE_HOOKS_LOG_FILE'` for the exported singleton.
157
+ */
158
+ logEnvVar?: string;
153
159
  }
154
160
  /**
155
161
  * Logger for Claude Code hooks with event subscription and file output.
@@ -7,7 +7,7 @@
7
7
  * @see https://code.claude.com/docs/en/hooks
8
8
  * @module
9
9
  */
10
- import type { ElicitationHookSpecificOutput as SDKElicitationHookSpecificOutput, ElicitationResultHookSpecificOutput as SDKElicitationResultHookSpecificOutput } from "@anthropic-ai/claude-agent-sdk";
10
+ import type { CwdChangedHookSpecificOutput as SDKCwdChangedHookSpecificOutput, ElicitationHookSpecificOutput as SDKElicitationHookSpecificOutput, ElicitationResultHookSpecificOutput as SDKElicitationResultHookSpecificOutput, FileChangedHookSpecificOutput as SDKFileChangedHookSpecificOutput } from "@anthropic-ai/claude-agent-sdk";
11
11
  import type { NotificationHookSpecificOutput as SDKNotificationHookSpecificOutput, PermissionRequestHookSpecificOutput as SDKPermissionRequestHookSpecificOutput, PostToolUseFailureHookSpecificOutput as SDKPostToolUseFailureHookSpecificOutput, PostToolUseHookSpecificOutput as SDKPostToolUseHookSpecificOutput, PreToolUseHookSpecificOutput as SDKPreToolUseHookSpecificOutput, SessionStartHookSpecificOutput as SDKSessionStartHookSpecificOutput, SetupHookSpecificOutput as SDKSetupHookSpecificOutput, SubagentStartHookSpecificOutput as SDKSubagentStartHookSpecificOutput, SyncHookJSONOutput as SDKSyncHookJSONOutput, UserPromptSubmitHookSpecificOutput as SDKUserPromptSubmitHookSpecificOutput } from "@anthropic-ai/claude-agent-sdk/sdk.js";
12
12
  /**
13
13
  * Exit codes used by Claude Code hooks.
@@ -36,7 +36,7 @@ export type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];
36
36
  /**
37
37
  * Re-export SDK hook-specific output types (includes hookEventName discriminator).
38
38
  */
39
- export type { SDKElicitationHookSpecificOutput, SDKElicitationResultHookSpecificOutput, SDKNotificationHookSpecificOutput, SDKPermissionRequestHookSpecificOutput, SDKPostToolUseFailureHookSpecificOutput, SDKPostToolUseHookSpecificOutput, SDKPreToolUseHookSpecificOutput, SDKSessionStartHookSpecificOutput, SDKSetupHookSpecificOutput, SDKSubagentStartHookSpecificOutput, SDKSyncHookJSONOutput, SDKUserPromptSubmitHookSpecificOutput, };
39
+ export type { SDKCwdChangedHookSpecificOutput, SDKElicitationHookSpecificOutput, SDKElicitationResultHookSpecificOutput, SDKFileChangedHookSpecificOutput, SDKNotificationHookSpecificOutput, SDKPermissionRequestHookSpecificOutput, SDKPostToolUseFailureHookSpecificOutput, SDKPostToolUseHookSpecificOutput, SDKPreToolUseHookSpecificOutput, SDKSessionStartHookSpecificOutput, SDKSetupHookSpecificOutput, SDKSubagentStartHookSpecificOutput, SDKSyncHookJSONOutput, SDKUserPromptSubmitHookSpecificOutput, };
40
40
  /**
41
41
  * PreToolUse hook-specific output fields.
42
42
  * Omits `hookEventName` which is added automatically by the builder.
@@ -111,10 +111,20 @@ export type PermissionRequestDecision = SDKPermissionRequestHookSpecificOutput["
111
111
  * Omits `hookEventName` which is added automatically by the builder.
112
112
  */
113
113
  export type NotificationHookSpecificOutput = Omit<SDKNotificationHookSpecificOutput, "hookEventName">;
114
+ /**
115
+ * CwdChanged hook-specific output fields.
116
+ * Omits `hookEventName` which is added automatically by the builder.
117
+ */
118
+ export type CwdChangedHookSpecificOutput = Omit<SDKCwdChangedHookSpecificOutput, "hookEventName">;
119
+ /**
120
+ * FileChanged hook-specific output fields.
121
+ * Omits `hookEventName` which is added automatically by the builder.
122
+ */
123
+ export type FileChangedHookSpecificOutput = Omit<SDKFileChangedHookSpecificOutput, "hookEventName">;
114
124
  /**
115
125
  * Full hook-specific output with hookEventName discriminator.
116
126
  */
117
- export type HookSpecificOutput = SDKPreToolUseHookSpecificOutput | SDKPostToolUseHookSpecificOutput | SDKPostToolUseFailureHookSpecificOutput | SDKUserPromptSubmitHookSpecificOutput | SDKSessionStartHookSpecificOutput | SDKSetupHookSpecificOutput | SDKSubagentStartHookSpecificOutput | SDKPermissionRequestHookSpecificOutput | SDKNotificationHookSpecificOutput | SDKElicitationHookSpecificOutput | SDKElicitationResultHookSpecificOutput;
127
+ export type HookSpecificOutput = SDKPreToolUseHookSpecificOutput | SDKPostToolUseHookSpecificOutput | SDKPostToolUseFailureHookSpecificOutput | SDKUserPromptSubmitHookSpecificOutput | SDKSessionStartHookSpecificOutput | SDKSetupHookSpecificOutput | SDKSubagentStartHookSpecificOutput | SDKPermissionRequestHookSpecificOutput | SDKNotificationHookSpecificOutput | SDKElicitationHookSpecificOutput | SDKElicitationResultHookSpecificOutput | SDKCwdChangedHookSpecificOutput | SDKFileChangedHookSpecificOutput;
118
128
  /**
119
129
  * The JSON output format expected by Claude Code (sync hooks only).
120
130
  * Extends SDK's SyncHookJSONOutput to include Notification hook support.
@@ -270,10 +280,18 @@ export type WorktreeCreateOutput = BaseSpecificOutput<"WorktreeCreate">;
270
280
  *
271
281
  */
272
282
  export type WorktreeRemoveOutput = BaseSpecificOutput<"WorktreeRemove">;
283
+ /**
284
+ *
285
+ */
286
+ export type CwdChangedOutput = BaseSpecificOutput<"CwdChanged">;
287
+ /**
288
+ *
289
+ */
290
+ export type FileChangedOutput = BaseSpecificOutput<"FileChanged">;
273
291
  /**
274
292
  * Union of all specific output types.
275
293
  */
276
- export type SpecificHookOutput = PreToolUseOutput | PostToolUseOutput | PostToolUseFailureOutput | NotificationOutput | UserPromptSubmitOutput | SessionStartOutput | SessionEndOutput | StopOutput | StopFailureOutput | SubagentStartOutput | SubagentStopOutput | PreCompactOutput | PostCompactOutput | PermissionRequestOutput | SetupOutput | TeammateIdleOutput | TaskCompletedOutput | ElicitationOutput | ElicitationResultOutput | ConfigChangeOutput | InstructionsLoadedOutput | WorktreeCreateOutput | WorktreeRemoveOutput;
294
+ export type SpecificHookOutput = PreToolUseOutput | PostToolUseOutput | PostToolUseFailureOutput | NotificationOutput | UserPromptSubmitOutput | SessionStartOutput | SessionEndOutput | StopOutput | StopFailureOutput | SubagentStartOutput | SubagentStopOutput | PreCompactOutput | PostCompactOutput | PermissionRequestOutput | SetupOutput | TeammateIdleOutput | TaskCompletedOutput | ElicitationOutput | ElicitationResultOutput | ConfigChangeOutput | InstructionsLoadedOutput | WorktreeCreateOutput | WorktreeRemoveOutput | CwdChangedOutput | FileChangedOutput;
277
295
  /**
278
296
  * Options for decision-based hooks (Stop, SubagentStop).
279
297
  */
@@ -866,6 +884,66 @@ export declare const worktreeRemoveOutput: (options?: CommonOptions) => {
866
884
  readonly _type: "WorktreeRemove";
867
885
  stdout: SyncHookJSONOutput;
868
886
  };
887
+ /**
888
+ * Options for the CwdChanged output builder.
889
+ */
890
+ export type CwdChangedOptions = CommonOptions & {
891
+ /** Hook-specific output matching the wire format. */
892
+ hookSpecificOutput?: CwdChangedHookSpecificOutput;
893
+ };
894
+ /**
895
+ * Creates an output for CwdChanged hooks.
896
+ * @param options - Configuration options for the hook output
897
+ * @returns A CwdChangedOutput object ready for the runtime
898
+ * @example
899
+ * ```typescript
900
+ * // Return additional paths to watch after the cwd change
901
+ * cwdChangedOutput({
902
+ * hookSpecificOutput: {
903
+ * watchPaths: ['/new/path/to/watch']
904
+ * }
905
+ * });
906
+ *
907
+ * // Simple passthrough
908
+ * cwdChangedOutput({});
909
+ * ```
910
+ */
911
+ export declare const cwdChangedOutput: (options?: CommonOptions & {
912
+ hookSpecificOutput?: CwdChangedHookSpecificOutput | undefined;
913
+ }) => {
914
+ readonly _type: "CwdChanged";
915
+ stdout: SyncHookJSONOutput;
916
+ };
917
+ /**
918
+ * Options for the FileChanged output builder.
919
+ */
920
+ export type FileChangedOptions = CommonOptions & {
921
+ /** Hook-specific output matching the wire format. */
922
+ hookSpecificOutput?: FileChangedHookSpecificOutput;
923
+ };
924
+ /**
925
+ * Creates an output for FileChanged hooks.
926
+ * @param options - Configuration options for the hook output
927
+ * @returns A FileChangedOutput object ready for the runtime
928
+ * @example
929
+ * ```typescript
930
+ * // Update the set of watched paths
931
+ * fileChangedOutput({
932
+ * hookSpecificOutput: {
933
+ * watchPaths: ['/path/to/watch', '/another/path']
934
+ * }
935
+ * });
936
+ *
937
+ * // Simple passthrough
938
+ * fileChangedOutput({});
939
+ * ```
940
+ */
941
+ export declare const fileChangedOutput: (options?: CommonOptions & {
942
+ hookSpecificOutput?: FileChangedHookSpecificOutput | undefined;
943
+ }) => {
944
+ readonly _type: "FileChanged";
945
+ stdout: SyncHookJSONOutput;
946
+ };
869
947
  /**
870
948
  * @deprecated Use CommonOptions instead
871
949
  */
package/types/types.d.ts CHANGED
@@ -12,8 +12,8 @@
12
12
  * Re-exports types from @anthropic-ai/claude-agent-sdk with "SDK" prefix.
13
13
  * These are used as base types for extension, ensuring synchronization with the SDK.
14
14
  */
15
- export type { BaseHookInput as SDKBaseHookInput, ConfigChangeHookInput as SDKConfigChangeHookInput, ElicitationHookInput as SDKElicitationHookInput, ElicitationResultHookInput as SDKElicitationResultHookInput, HookEvent as SDKHookEvent, HookInput as SDKHookInput, InstructionsLoadedHookInput as SDKInstructionsLoadedHookInput, NotificationHookInput as SDKNotificationHookInput, PermissionMode as SDKPermissionMode, PermissionRequestHookInput as SDKPermissionRequestHookInput, PermissionUpdate as SDKPermissionUpdate, PostCompactHookInput as SDKPostCompactHookInput, PostToolUseFailureHookInput as SDKPostToolUseFailureHookInput, PostToolUseHookInput as SDKPostToolUseHookInput, PreCompactHookInput as SDKPreCompactHookInput, PreToolUseHookInput as SDKPreToolUseHookInput, SessionEndHookInput as SDKSessionEndHookInput, SessionStartHookInput as SDKSessionStartHookInput, SetupHookInput as SDKSetupHookInput, StopFailureHookInput as SDKStopFailureHookInput, StopHookInput as SDKStopHookInput, SubagentStartHookInput as SDKSubagentStartHookInput, SubagentStopHookInput as SDKSubagentStopHookInput, TaskCompletedHookInput as SDKTaskCompletedHookInput, TeammateIdleHookInput as SDKTeammateIdleHookInput, UserPromptSubmitHookInput as SDKUserPromptSubmitHookInput, WorktreeCreateHookInput as SDKWorktreeCreateHookInput, WorktreeRemoveHookInput as SDKWorktreeRemoveHookInput, } from "@anthropic-ai/claude-agent-sdk";
16
- import type { BaseHookInput as SDKBaseHookInput, ConfigChangeHookInput as SDKConfigChangeHookInput, ElicitationHookInput as SDKElicitationHookInput, ElicitationResultHookInput as SDKElicitationResultHookInput, InstructionsLoadedHookInput as SDKInstructionsLoadedHookInput, NotificationHookInput as SDKNotificationHookInput, PermissionMode as SDKPermissionMode, PermissionRequestHookInput as SDKPermissionRequestHookInput, PermissionUpdate as SDKPermissionUpdate, PostCompactHookInput as SDKPostCompactHookInput, PostToolUseFailureHookInput as SDKPostToolUseFailureHookInput, PostToolUseHookInput as SDKPostToolUseHookInput, PreCompactHookInput as SDKPreCompactHookInput, PreToolUseHookInput as SDKPreToolUseHookInput, SessionEndHookInput as SDKSessionEndHookInput, SessionStartHookInput as SDKSessionStartHookInput, SetupHookInput as SDKSetupHookInput, StopFailureHookInput as SDKStopFailureHookInput, StopHookInput as SDKStopHookInput, SubagentStartHookInput as SDKSubagentStartHookInput, SubagentStopHookInput as SDKSubagentStopHookInput, TaskCompletedHookInput as SDKTaskCompletedHookInput, TeammateIdleHookInput as SDKTeammateIdleHookInput, UserPromptSubmitHookInput as SDKUserPromptSubmitHookInput, WorktreeCreateHookInput as SDKWorktreeCreateHookInput, WorktreeRemoveHookInput as SDKWorktreeRemoveHookInput } from "@anthropic-ai/claude-agent-sdk";
15
+ export type { BaseHookInput as SDKBaseHookInput, ConfigChangeHookInput as SDKConfigChangeHookInput, CwdChangedHookInput as SDKCwdChangedHookInput, ElicitationHookInput as SDKElicitationHookInput, ElicitationResultHookInput as SDKElicitationResultHookInput, FileChangedHookInput as SDKFileChangedHookInput, HookEvent as SDKHookEvent, HookInput as SDKHookInput, InstructionsLoadedHookInput as SDKInstructionsLoadedHookInput, NotificationHookInput as SDKNotificationHookInput, PermissionMode as SDKPermissionMode, PermissionRequestHookInput as SDKPermissionRequestHookInput, PermissionUpdate as SDKPermissionUpdate, PostCompactHookInput as SDKPostCompactHookInput, PostToolUseFailureHookInput as SDKPostToolUseFailureHookInput, PostToolUseHookInput as SDKPostToolUseHookInput, PreCompactHookInput as SDKPreCompactHookInput, PreToolUseHookInput as SDKPreToolUseHookInput, SessionEndHookInput as SDKSessionEndHookInput, SessionStartHookInput as SDKSessionStartHookInput, SetupHookInput as SDKSetupHookInput, StopFailureHookInput as SDKStopFailureHookInput, StopHookInput as SDKStopHookInput, SubagentStartHookInput as SDKSubagentStartHookInput, SubagentStopHookInput as SDKSubagentStopHookInput, TaskCompletedHookInput as SDKTaskCompletedHookInput, TeammateIdleHookInput as SDKTeammateIdleHookInput, UserPromptSubmitHookInput as SDKUserPromptSubmitHookInput, WorktreeCreateHookInput as SDKWorktreeCreateHookInput, WorktreeRemoveHookInput as SDKWorktreeRemoveHookInput, } from "@anthropic-ai/claude-agent-sdk";
16
+ import type { BaseHookInput as SDKBaseHookInput, ConfigChangeHookInput as SDKConfigChangeHookInput, CwdChangedHookInput as SDKCwdChangedHookInput, ElicitationHookInput as SDKElicitationHookInput, ElicitationResultHookInput as SDKElicitationResultHookInput, FileChangedHookInput as SDKFileChangedHookInput, InstructionsLoadedHookInput as SDKInstructionsLoadedHookInput, NotificationHookInput as SDKNotificationHookInput, PermissionMode as SDKPermissionMode, PermissionRequestHookInput as SDKPermissionRequestHookInput, PermissionUpdate as SDKPermissionUpdate, PostCompactHookInput as SDKPostCompactHookInput, PostToolUseFailureHookInput as SDKPostToolUseFailureHookInput, PostToolUseHookInput as SDKPostToolUseHookInput, PreCompactHookInput as SDKPreCompactHookInput, PreToolUseHookInput as SDKPreToolUseHookInput, SessionEndHookInput as SDKSessionEndHookInput, SessionStartHookInput as SDKSessionStartHookInput, SetupHookInput as SDKSetupHookInput, StopFailureHookInput as SDKStopFailureHookInput, StopHookInput as SDKStopHookInput, SubagentStartHookInput as SDKSubagentStartHookInput, SubagentStopHookInput as SDKSubagentStopHookInput, TaskCompletedHookInput as SDKTaskCompletedHookInput, TeammateIdleHookInput as SDKTeammateIdleHookInput, UserPromptSubmitHookInput as SDKUserPromptSubmitHookInput, WorktreeCreateHookInput as SDKWorktreeCreateHookInput, WorktreeRemoveHookInput as SDKWorktreeRemoveHookInput } from "@anthropic-ai/claude-agent-sdk";
17
17
  import type { AgentInput, AskUserQuestionInput, BashInput, ConfigInput, ExitPlanModeInput, FileEditInput, FileReadInput, FileWriteInput, GlobInput, GrepInput, TaskStopInput as KillShellInput, ListMcpResourcesInput, McpInput, NotebookEditInput, ReadMcpResourceInput, TaskOutputInput, TodoWriteInput, WebFetchInput, WebSearchInput } from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
18
18
  /**
19
19
  * Permission mode for controlling how tool executions are handled.
@@ -258,6 +258,35 @@ export type WorktreeCreateInput = {
258
258
  export type WorktreeRemoveInput = {
259
259
  [K in keyof SDKWorktreeRemoveHookInput]: SDKWorktreeRemoveHookInput[K];
260
260
  } & {};
261
+ /**
262
+ * Input for CwdChanged hooks.
263
+ *
264
+ * Fires when Claude Code's current working directory changes, allowing you to:
265
+ * - React to directory changes within a session
266
+ * - Update file watchers or environment state
267
+ * - Return `watchPaths` to register paths for FileChanged events
268
+ * @see https://code.claude.com/docs/en/hooks#cwdchanged
269
+ */
270
+ export type CwdChangedInput = {
271
+ [K in keyof SDKCwdChangedHookInput]: SDKCwdChangedHookInput[K];
272
+ } & {};
273
+ /**
274
+ * Input for FileChanged hooks.
275
+ *
276
+ * Fires when a watched file changes on disk, allowing you to:
277
+ * - React to file system changes during a session
278
+ * - Invalidate caches or reload configuration
279
+ * - Return `watchPaths` to update the set of watched paths
280
+ *
281
+ * The `event` field indicates the type of change:
282
+ * - `'change'` - File contents changed
283
+ * - `'add'` - File was created
284
+ * - `'unlink'` - File was deleted
285
+ * @see https://code.claude.com/docs/en/hooks#filechanged
286
+ */
287
+ export type FileChangedInput = {
288
+ [K in keyof SDKFileChangedHookInput]: SDKFileChangedHookInput[K];
289
+ } & {};
261
290
  /**
262
291
  * Input for SessionEnd hooks.
263
292
  *
@@ -352,7 +381,7 @@ export type SetupTrigger = "init" | "maintenance";
352
381
  * ```
353
382
  * @see https://code.claude.com/docs/en/hooks
354
383
  */
355
- export type HookInput = PreToolUseInput | PostToolUseInput | PostToolUseFailureInput | NotificationInput | UserPromptSubmitInput | SessionStartInput | SessionEndInput | StopInput | StopFailureInput | SubagentStartInput | SubagentStopInput | PreCompactInput | PostCompactInput | PermissionRequestInput | SetupInput | TeammateIdleInput | TaskCompletedInput | ElicitationInput | ElicitationResultInput | ConfigChangeInput | InstructionsLoadedInput | WorktreeCreateInput | WorktreeRemoveInput;
384
+ export type HookInput = PreToolUseInput | PostToolUseInput | PostToolUseFailureInput | NotificationInput | UserPromptSubmitInput | SessionStartInput | SessionEndInput | StopInput | StopFailureInput | SubagentStartInput | SubagentStopInput | PreCompactInput | PostCompactInput | PermissionRequestInput | SetupInput | TeammateIdleInput | TaskCompletedInput | ElicitationInput | ElicitationResultInput | ConfigChangeInput | InstructionsLoadedInput | WorktreeCreateInput | WorktreeRemoveInput | CwdChangedInput | FileChangedInput;
356
385
  /**
357
386
  * Hook event name literal union.
358
387
  *
@@ -370,7 +399,7 @@ export type HookEventName = HookInput["hook_event_name"];
370
399
  * }
371
400
  * ```
372
401
  */
373
- export declare const HOOK_EVENT_NAMES: readonly ["PreToolUse", "PostToolUse", "PostToolUseFailure", "Notification", "UserPromptSubmit", "SessionStart", "SessionEnd", "Stop", "StopFailure", "SubagentStart", "SubagentStop", "PreCompact", "PostCompact", "PermissionRequest", "Setup", "TeammateIdle", "TaskCompleted", "Elicitation", "ElicitationResult", "ConfigChange", "InstructionsLoaded", "WorktreeCreate", "WorktreeRemove"];
402
+ export declare const HOOK_EVENT_NAMES: readonly ["PreToolUse", "PostToolUse", "PostToolUseFailure", "Notification", "UserPromptSubmit", "SessionStart", "SessionEnd", "Stop", "StopFailure", "SubagentStart", "SubagentStop", "PreCompact", "PostCompact", "PermissionRequest", "Setup", "TeammateIdle", "TaskCompleted", "Elicitation", "ElicitationResult", "ConfigChange", "InstructionsLoaded", "WorktreeCreate", "WorktreeRemove", "CwdChanged", "FileChanged"];
374
403
  export type { SDKPermissionUpdate as PermissionUpdate };
375
404
  /**
376
405
  * Re-export all tool input types from the official Claude Agent SDK.