@goodfoot/agent-hooks 1.0.9 → 1.0.10

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/CHANGELOG.md CHANGED
@@ -1,9 +1,13 @@
1
1
  # @goodfoot/agent-hooks npm package changelog
2
2
 
3
- ## 1.0.9
4
- - Added support for Antigravity hooks, including event handling, output formatting, and transport
5
- - Added scaffolding for Antigravity hook projects via the CLI
6
- - Documented the Antigravity hook contract in the README
3
+ ## 1.0.10
4
+ - Fixed scaffolded hook bundles to work when the install path is a symlink or otherwise differs from the project root, so hooks resolve correctly across repository layouts
5
+ - Improved stack traces from hooks by making source map resolution reliable in relocated or symlinked installs
6
+ - Applied the portability fixes consistently across the Claude Code, Codex, and Antigravity entry points
7
+
8
+ ## 1.0.10
9
+
10
+ Makes compiled bundles portable across ordinary hoisted workspace layouts by anchoring esbuild's module-boundary comments and sourcemap source paths at the directory that owns the resolved `node_modules`. Inline sourcemaps are now disabled by default for smaller, reviewable build artifacts and remain available with the explicit `--sourcemap` flag.
7
11
 
8
12
  ## 1.0.9
9
13
 
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  **Build AI coding agent hooks in TypeScript — one package, any supported agent.**
4
4
 
5
+ Compiled bundles omit inline sourcemaps by default. Pass `--sourcemap` when original TypeScript locations are needed in runtime stack traces.
6
+
5
7
  `@goodfoot/agent-hooks` is the unified successor to `@goodfoot/claude-code-hooks` and
6
8
  `@goodfoot/codex-hooks`: a shared agent-neutral core (hook factory primitive, transport
7
9
  driver, `Logger`, env/stdin utilities) with a per-agent entry point on top. Write
@@ -22,7 +22,7 @@ import * as path from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import * as esbuild from "esbuild";
24
24
  import ts from "typescript";
25
- import { buildEsbuildLoaderMap, discoverHookSourceFiles, parseEsbuildLoaderFlag, pruneStaleHashedBundles, sha256Prefix8, symlinkVisiblePath, } from "../../cli.js";
25
+ import { buildEsbuildLoaderMap, discoverHookSourceFiles, moduleWorkingDir, parseEsbuildLoaderFlag, pruneStaleHashedBundles, sha256Prefix8, symlinkVisiblePath, } from "../../cli.js";
26
26
  import { DEFAULT_TIMEOUT_SECONDS, GROUPED_EVENTS, HOOK_FACTORY_TO_EVENT } from "./constants.js";
27
27
  import { HOOK_EVENT_NAMES } from "./events.js";
28
28
  /** The matcher emitted when a grouped event's config names none. `"*"` matches every tool. */
@@ -82,9 +82,10 @@ export function analyzeAntigravityHookFile(sourcePath) {
82
82
  * Bundles one hook source into a self-contained ESM executable whose entry
83
83
  * wrapper calls this agent's `execute`.
84
84
  */
85
- export async function compileAntigravityHook(sourcePath, loaders, sourcemap = true) {
85
+ export async function compileAntigravityHook(sourcePath, loaders, sourcemap = false) {
86
86
  const resolveDir = path.dirname(sourcePath);
87
87
  const runtimeAbsolute = symlinkVisiblePath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "./transport.js"), resolveDir);
88
+ const absWorkingDir = moduleWorkingDir(runtimeAbsolute, resolveDir);
88
89
  const runtimeRelative = path.relative(resolveDir, runtimeAbsolute).replace(/\\/g, "/");
89
90
  const runtimeSpecifier = runtimeRelative.startsWith(".") ? runtimeRelative : `./${runtimeRelative}`;
90
91
  const entry = [
@@ -94,6 +95,7 @@ export async function compileAntigravityHook(sourcePath, loaders, sourcemap = tr
94
95
  ``,
95
96
  ].join("\n");
96
97
  const built = await esbuild.build({
98
+ absWorkingDir,
97
99
  stdin: {
98
100
  contents: entry,
99
101
  resolveDir,
@@ -50,7 +50,7 @@ function packageJson(projectName, outputPath) {
50
50
  lint: "biome check .",
51
51
  typecheck: "tsc --noEmit",
52
52
  },
53
- dependencies: { [PACKAGE_NAME]: "^1.0.9" },
53
+ dependencies: { [PACKAGE_NAME]: "^1.0.10" },
54
54
  devDependencies: {
55
55
  "@biomejs/biome": "2.4.9",
56
56
  "@types/node": "^24.0.0",
@@ -15,7 +15,7 @@ import * as path from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
16
  import * as esbuild from "esbuild";
17
17
  import ts from "typescript";
18
- import { buildEsbuildLoaderMap, discoverHookSourceFiles, parseEsbuildLoaderFlag, pruneStaleHashedBundles, sha256Prefix8, symlinkVisiblePath, } from "../../cli.js";
18
+ import { buildEsbuildLoaderMap, discoverHookSourceFiles, moduleWorkingDir, parseEsbuildLoaderFlag, pruneStaleHashedBundles, sha256Prefix8, symlinkVisiblePath, } from "../../cli.js";
19
19
  import { EVENTS_WITH_MATCHER, HOOK_FACTORY_TO_EVENT } from "./constants.js";
20
20
  /**
21
21
  * Extracts Codex hook metadata (event name, matcher, timeout in
@@ -88,9 +88,10 @@ export function analyzeCodexHookFile(sourcePath) {
88
88
  * Compiles one Codex hook to a self-contained ESM executable whose entry
89
89
  * wrapper imports this package's Codex runtime module (`execute`).
90
90
  */
91
- export async function compileCodexHook(sourcePath, loaders, sourcemap = true) {
91
+ export async function compileCodexHook(sourcePath, loaders, sourcemap = false) {
92
92
  const resolveDir = path.dirname(sourcePath);
93
93
  const runtimePathAbsolute = symlinkVisiblePath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "./transport.js"), resolveDir);
94
+ const absWorkingDir = moduleWorkingDir(runtimePathAbsolute, resolveDir);
94
95
  let relativeRuntimePath = path.relative(resolveDir, runtimePathAbsolute).replace(/\\/g, "/");
95
96
  if (!relativeRuntimePath.startsWith(".")) {
96
97
  relativeRuntimePath = `./${relativeRuntimePath}`;
@@ -102,6 +103,7 @@ execute(hook);
102
103
  `;
103
104
  const baseName = path.basename(sourcePath, path.extname(sourcePath));
104
105
  const result = await esbuild.build({
106
+ absWorkingDir,
105
107
  stdin: {
106
108
  contents: wrapperContent,
107
109
  resolveDir,
@@ -55,7 +55,7 @@ function generatePackageJson(projectName, outputPath) {
55
55
  typecheck: "tsc --noEmit",
56
56
  },
57
57
  dependencies: {
58
- [PACKAGE_NAME]: "^1.0.9",
58
+ [PACKAGE_NAME]: "^1.0.10",
59
59
  },
60
60
  devDependencies: {
61
61
  "@biomejs/biome": "2.4.9",
@@ -23,7 +23,7 @@ import { buildEsbuildLoaderMap, discoverHookSourceFiles, parseEsbuildLoaderFlag
23
23
  * Bundles one OpenCode plugin entry to a self-contained ESM artifact. The
24
24
  * source file's own default export is preserved unchanged — no wrapper.
25
25
  */
26
- export async function compileOpenCodePlugin(sourcePath, loaders, sourcemap = true) {
26
+ export async function compileOpenCodePlugin(sourcePath, loaders, sourcemap = false) {
27
27
  const result = await esbuild.build({
28
28
  entryPoints: [sourcePath],
29
29
  loader: loaders,
package/dist/cli.js CHANGED
@@ -26,7 +26,7 @@ import { scaffoldProject } from "./scaffold.js";
26
26
  // ============================================================================
27
27
  // Constants
28
28
  // ============================================================================
29
- const VERSION = "1.0.9";
29
+ const VERSION = "1.0.10";
30
30
  const DEFAULT_ESBUILD_LOADERS = {
31
31
  ".md": "text",
32
32
  };
@@ -142,13 +142,13 @@ Optional Arguments:
142
142
  --no-stable-names
143
143
  Restore the pre-1.7 behavior: hashed compiled bundles (<name>.<hash>.mjs).
144
144
 
145
- --sourcemap (default)
145
+ --sourcemap
146
146
  Embed an inline sourcemap in each compiled bundle so stack traces show
147
147
  original TypeScript source locations.
148
148
 
149
- --no-sourcemap
150
- Emit bundles without the inline sourcemap, shrinking compiled output by
151
- roughly 85-90%. The content hash is unaffected.
149
+ --no-sourcemap (default)
150
+ Emit bundles without the inline sourcemap, shrinking compiled output.
151
+ The content hash is unaffected.
152
152
 
153
153
  -h, --help
154
154
  Show this help message.
@@ -257,7 +257,7 @@ function parseArgs(argv) {
257
257
  // as true, while the Codex branch defaults by command context
258
258
  // (plugin mode → stable, otherwise hashed).
259
259
  stableNames: undefined,
260
- sourcemap: true,
260
+ sourcemap: false,
261
261
  };
262
262
  for (let i = 0; i < argv.length; i++) {
263
263
  const arg = argv[i];
@@ -642,6 +642,28 @@ function symlinkVisiblePath(realPath, resolveDir) {
642
642
  dir = parent;
643
643
  }
644
644
  }
645
+ /**
646
+ * Returns the stable project anchor for a module reached through node_modules.
647
+ *
648
+ * esbuild otherwise uses process.cwd() when rendering module-boundary comments
649
+ * and sourcemap source paths. A workspace script normally runs from the
650
+ * consuming package, while its dependencies may be hoisted several directories
651
+ * higher, making those emitted paths depend on the consumer's nesting depth.
652
+ * Anchoring at the directory which owns the visible node_modules keeps the
653
+ * canonical `node_modules/...` form in every such layout.
654
+ */
655
+ function moduleWorkingDir(modulePath, fallback) {
656
+ for (let dir = path.dirname(modulePath);;) {
657
+ if (path.basename(dir) === "node_modules") {
658
+ return path.dirname(dir);
659
+ }
660
+ const parent = path.dirname(dir);
661
+ if (parent === dir) {
662
+ return fallback;
663
+ }
664
+ dir = parent;
665
+ }
666
+ }
645
667
  /**
646
668
  * Compiles a TypeScript hook file to a self-contained ESM executable.
647
669
  *
@@ -672,6 +694,7 @@ async function compileHook(options) {
672
694
  // nesting depth.
673
695
  const resolveDir = path.dirname(sourcePath);
674
696
  const runtimePathAbsolute = symlinkVisiblePath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "./agents/claude-code/transport.js"), resolveDir);
697
+ const absWorkingDir = moduleWorkingDir(runtimePathAbsolute, resolveDir);
675
698
  // Compute relative paths from resolveDir to avoid absolute paths in source maps.
676
699
  // This ensures reproducible builds regardless of checkout directory.
677
700
  const relativeSourcePath = `./${path.basename(sourcePath)}`;
@@ -731,6 +754,7 @@ execute(hook);
731
754
  ].join("\n");
732
755
  // Common esbuild options
733
756
  const commonOptions = {
757
+ absWorkingDir,
734
758
  stdin: stdinOptions,
735
759
  loader: loaders,
736
760
  format: "esm",
@@ -784,7 +808,7 @@ execute(hook);
784
808
  // output minus the trailing sourceMappingURL comment (verified on esbuild
785
809
  // 0.24.2), so the sourcemap-free content is emitted directly. The content
786
810
  // hash is always derived from pass-1 output, so it is unchanged by the flag.
787
- if (sourcemap === false) {
811
+ if (sourcemap !== true) {
788
812
  return { content: contentForHash, contentHash };
789
813
  }
790
814
  const resultWithSourcemap = await esbuild.build({
@@ -1447,4 +1471,4 @@ if (isDirectExecution) {
1447
1471
  // Shared build primitives reused by the per-agent CLI branches (single
1448
1472
  // source for driver logic — the duplication check forbids re-deriving these
1449
1473
  // inside agents/*).
1450
- export { analyzeHookFile, buildLoaderMap, buildLoaderMap as buildEsbuildLoaderMap, compileHook, detectHookContext, discoverHookFiles, discoverHookFiles as discoverHookSourceFiles, extractPreservedHooks, generateCommandPath, generateContentHash, generateContentHash as sha256Prefix8, generateHooksJson, groupHooksByEventAndMatcher, HOOK_FACTORY_TO_EVENT, mergeHooksJson, parseArgs, parseLoaderFlag, parseLoaderFlag as parseEsbuildLoaderFlag, pruneStaleHashedBundles, readExistingHooksJson, removeOldGeneratedFiles, symlinkVisiblePath, validateArgs, };
1474
+ export { analyzeHookFile, buildLoaderMap, buildLoaderMap as buildEsbuildLoaderMap, compileHook, detectHookContext, discoverHookFiles, discoverHookFiles as discoverHookSourceFiles, extractPreservedHooks, generateCommandPath, generateContentHash, generateContentHash as sha256Prefix8, generateHooksJson, groupHooksByEventAndMatcher, HOOK_FACTORY_TO_EVENT, mergeHooksJson, moduleWorkingDir, parseArgs, parseLoaderFlag, parseLoaderFlag as parseEsbuildLoaderFlag, pruneStaleHashedBundles, readExistingHooksJson, removeOldGeneratedFiles, symlinkVisiblePath, validateArgs, };
package/dist/scaffold.js CHANGED
@@ -131,7 +131,7 @@ function generatePackageJson(projectName, outputPath) {
131
131
  typecheck: "tsc --noEmit",
132
132
  },
133
133
  dependencies: {
134
- "@goodfoot/agent-hooks": "^1.0.9",
134
+ "@goodfoot/agent-hooks": "^1.0.10",
135
135
  },
136
136
  devDependencies: {
137
137
  "@biomejs/biome": "2.4.16",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodfoot/agent-hooks",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "Unified agent hooks library: shared core runtime with per-agent entry points for Claude Code, Codex, and Antigravity",
5
5
  "homepage": "https://github.com/goodfoot-io/marketplace/tree/main/packages/agent-hooks",
6
6
  "repository": {
package/types/cli.d.ts CHANGED
@@ -54,7 +54,7 @@ interface CliArgs {
54
54
  pluginRoot?: boolean;
55
55
  /** Emit hash-free `<name>.mjs` bundles. Defaults to true; set false with --no-stable-names. */
56
56
  stableNames?: boolean;
57
- /** Embed an inline sourcemap in compiled bundles. Defaults to true; set false with --no-sourcemap. */
57
+ /** Embed an inline sourcemap in compiled bundles. Defaults to false; enable with --sourcemap. */
58
58
  sourcemap?: boolean;
59
59
  }
60
60
  type HookLoaderMap = Record<string, esbuild.Loader>;
@@ -173,14 +173,14 @@ interface CompileHookOptions {
173
173
  logEnvVar?: string;
174
174
  /** Explicit esbuild loaders for non-code imports. */
175
175
  loaders: HookLoaderMap;
176
- /** Embed an inline sourcemap in the compiled content. Defaults to true; set false with --no-sourcemap. */
176
+ /** Embed an inline sourcemap in the compiled content. Defaults to false; enable with --sourcemap. */
177
177
  sourcemap?: boolean;
178
178
  }
179
179
  /**
180
180
  * Result of compiling a hook.
181
181
  */
182
182
  interface CompileHookResult {
183
- /** Compiled content, with inline sourcemaps unless disabled. */
183
+ /** Compiled content, with inline sourcemaps when enabled. */
184
184
  content: string;
185
185
  /** Stable content hash generated from sourcemap-free output. */
186
186
  contentHash: string;
@@ -203,6 +203,17 @@ interface CompileHookResult {
203
203
  * checkout-local.
204
204
  */
205
205
  declare function symlinkVisiblePath(realPath: string, resolveDir: string): string;
206
+ /**
207
+ * Returns the stable project anchor for a module reached through node_modules.
208
+ *
209
+ * esbuild otherwise uses process.cwd() when rendering module-boundary comments
210
+ * and sourcemap source paths. A workspace script normally runs from the
211
+ * consuming package, while its dependencies may be hoisted several directories
212
+ * higher, making those emitted paths depend on the consumer's nesting depth.
213
+ * Anchoring at the directory which owns the visible node_modules keeps the
214
+ * canonical `node_modules/...` form in every such layout.
215
+ */
216
+ declare function moduleWorkingDir(modulePath: string, fallback: string): string;
206
217
  /**
207
218
  * Compiles a TypeScript hook file to a self-contained ESM executable.
208
219
  *
@@ -312,4 +323,4 @@ declare function extractPreservedHooks(existingHooksJson: HooksJson): Partial<Re
312
323
  */
313
324
  declare function mergeHooksJson(newHooksJson: HooksJson, preservedHooks: Partial<Record<HookEventName, MatcherEntry[]>>): HooksJson;
314
325
  export type { CliArgs, CompiledHook, HookConfig, HookLoaderMap, HookMetadata, HooksJson, MatcherEntry };
315
- export { analyzeHookFile, buildLoaderMap, buildLoaderMap as buildEsbuildLoaderMap, compileHook, detectHookContext, discoverHookFiles, discoverHookFiles as discoverHookSourceFiles, extractPreservedHooks, generateCommandPath, generateContentHash, generateContentHash as sha256Prefix8, generateHooksJson, groupHooksByEventAndMatcher, HOOK_FACTORY_TO_EVENT, mergeHooksJson, parseArgs, parseLoaderFlag, parseLoaderFlag as parseEsbuildLoaderFlag, pruneStaleHashedBundles, readExistingHooksJson, removeOldGeneratedFiles, symlinkVisiblePath, validateArgs, };
326
+ export { analyzeHookFile, buildLoaderMap, buildLoaderMap as buildEsbuildLoaderMap, compileHook, detectHookContext, discoverHookFiles, discoverHookFiles as discoverHookSourceFiles, extractPreservedHooks, generateCommandPath, generateContentHash, generateContentHash as sha256Prefix8, generateHooksJson, groupHooksByEventAndMatcher, HOOK_FACTORY_TO_EVENT, mergeHooksJson, moduleWorkingDir, parseArgs, parseLoaderFlag, parseLoaderFlag as parseEsbuildLoaderFlag, pruneStaleHashedBundles, readExistingHooksJson, removeOldGeneratedFiles, symlinkVisiblePath, validateArgs, };