@hasna/hooks 0.9.1 → 0.9.3

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/dist/index.js CHANGED
@@ -4974,21 +4974,21 @@ __export(exports_profiles, {
4974
4974
  deleteProfile: () => deleteProfile,
4975
4975
  createProfile: () => createProfile
4976
4976
  });
4977
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, readdirSync as readdirSync4, rmSync, cpSync as cpSync2 } from "fs";
4977
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5, readdirSync as readdirSync4, rmSync, cpSync as cpSync2 } from "fs";
4978
4978
  import { join as join8 } from "path";
4979
4979
  function getProfilesDir() {
4980
4980
  const newDir = join8(getEffectiveDataRoot(), "profiles");
4981
4981
  const oldDir = join8(getHomeDir(), ".hooks", "profiles");
4982
- if (!existsSync8(newDir) && existsSync8(oldDir)) {
4983
- mkdirSync5(newDir, { recursive: true });
4982
+ if (!existsSync9(newDir) && existsSync9(oldDir)) {
4983
+ mkdirSync6(newDir, { recursive: true });
4984
4984
  cpSync2(oldDir, newDir, { recursive: true });
4985
4985
  }
4986
4986
  return newDir;
4987
4987
  }
4988
4988
  function ensureProfilesDir() {
4989
4989
  const dir = getProfilesDir();
4990
- if (!existsSync8(dir)) {
4991
- mkdirSync5(dir, { recursive: true });
4990
+ if (!existsSync9(dir)) {
4991
+ mkdirSync6(dir, { recursive: true });
4992
4992
  }
4993
4993
  }
4994
4994
  function profilePath(id) {
@@ -5011,30 +5011,30 @@ function createProfile(input) {
5011
5011
  if (input.name) {
5012
5012
  profile.name = input.name;
5013
5013
  }
5014
- writeFileSync4(profilePath(id), JSON.stringify(profile, null, 2) + `
5014
+ writeFileSync5(profilePath(id), JSON.stringify(profile, null, 2) + `
5015
5015
  `);
5016
5016
  return profile;
5017
5017
  }
5018
5018
  function getProfile(id) {
5019
5019
  const path = profilePath(id);
5020
5020
  try {
5021
- if (!existsSync8(path))
5021
+ if (!existsSync9(path))
5022
5022
  return null;
5023
- return JSON.parse(readFileSync5(path, "utf-8"));
5023
+ return JSON.parse(readFileSync6(path, "utf-8"));
5024
5024
  } catch {
5025
5025
  return null;
5026
5026
  }
5027
5027
  }
5028
5028
  function listProfiles() {
5029
5029
  const dir = getProfilesDir();
5030
- if (!existsSync8(dir))
5030
+ if (!existsSync9(dir))
5031
5031
  return [];
5032
5032
  try {
5033
5033
  const files = readdirSync4(dir).filter((f) => f.endsWith(".json"));
5034
5034
  const profiles = [];
5035
5035
  for (const file of files) {
5036
5036
  try {
5037
- const content = readFileSync5(join8(dir, file), "utf-8");
5037
+ const content = readFileSync6(join8(dir, file), "utf-8");
5038
5038
  profiles.push(JSON.parse(content));
5039
5039
  } catch {}
5040
5040
  }
@@ -5051,13 +5051,13 @@ function updateProfile(id, data) {
5051
5051
  profile.name = data.name;
5052
5052
  if (data.preferences !== undefined)
5053
5053
  profile.preferences = data.preferences;
5054
- writeFileSync4(profilePath(id), JSON.stringify(profile, null, 2) + `
5054
+ writeFileSync5(profilePath(id), JSON.stringify(profile, null, 2) + `
5055
5055
  `);
5056
5056
  return profile;
5057
5057
  }
5058
5058
  function deleteProfile(id) {
5059
5059
  const path = profilePath(id);
5060
- if (!existsSync8(path))
5060
+ if (!existsSync9(path))
5061
5061
  return false;
5062
5062
  try {
5063
5063
  rmSync(path);
@@ -5071,7 +5071,7 @@ function touchProfile(id) {
5071
5071
  if (!profile)
5072
5072
  return;
5073
5073
  profile.last_seen_at = new Date().toISOString();
5074
- writeFileSync4(profilePath(id), JSON.stringify(profile, null, 2) + `
5074
+ writeFileSync5(profilePath(id), JSON.stringify(profile, null, 2) + `
5075
5075
  `);
5076
5076
  }
5077
5077
  function exportProfiles() {
@@ -5087,11 +5087,11 @@ function importProfiles(profiles) {
5087
5087
  continue;
5088
5088
  }
5089
5089
  const path = profilePath(profile.agent_id);
5090
- if (existsSync8(path)) {
5090
+ if (existsSync9(path)) {
5091
5091
  skipped++;
5092
5092
  continue;
5093
5093
  }
5094
- writeFileSync4(path, JSON.stringify(profile, null, 2) + `
5094
+ writeFileSync5(path, JSON.stringify(profile, null, 2) + `
5095
5095
  `);
5096
5096
  imported++;
5097
5097
  }
@@ -5104,7 +5104,7 @@ var init_profiles = __esm(() => {
5104
5104
  // ../../node_modules/.bun/@hasna+contracts@1.0.2+e0db24ae03127387/node_modules/@hasna/contracts/dist/client/transport.js
5105
5105
  import { isIP } from "net";
5106
5106
  import { spawnSync } from "child_process";
5107
- import { closeSync, fstatSync, openSync, readFileSync as readFileSync6 } from "fs";
5107
+ import { closeSync as closeSync2, fstatSync, openSync as openSync2, readFileSync as readFileSync7 } from "fs";
5108
5108
  import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
5109
5109
  import { createRequire } from "module";
5110
5110
  import { hostname as osHostname } from "os";
@@ -5208,7 +5208,7 @@ function readAppConfigFile(path) {
5208
5208
  };
5209
5209
  let fd = -1;
5210
5210
  try {
5211
- fd = openSync(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
5211
+ fd = openSync2(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
5212
5212
  } catch (error) {
5213
5213
  const code = error.code;
5214
5214
  if (code === "ENOENT" || code === "ENOTDIR")
@@ -5229,7 +5229,7 @@ function readAppConfigFile(path) {
5229
5229
  unsafe("the file is not owned by the current user");
5230
5230
  if (before.size > MAX_CREDENTIAL_FILE_BYTES)
5231
5231
  unsafe("the file exceeds the size limit");
5232
- const bytes = readFileSync6(fd);
5232
+ const bytes = readFileSync7(fd);
5233
5233
  const after = fstatSync(fd);
5234
5234
  if (!configFileReadsCoherent(before, after)) {
5235
5235
  unsafe("the file changed while being read");
@@ -5237,7 +5237,7 @@ function readAppConfigFile(path) {
5237
5237
  return parseEnvFile(bytes.toString("utf8"));
5238
5238
  } finally {
5239
5239
  if (fd !== -1)
5240
- closeSync(fd);
5240
+ closeSync2(fd);
5241
5241
  }
5242
5242
  }
5243
5243
  function readCredentialFile(path, apiKeyKeys) {
@@ -6013,8 +6013,8 @@ var init_db_writer = __esm(() => {
6013
6013
  });
6014
6014
 
6015
6015
  // src/lib/hook-env.ts
6016
- import { dirname as dirname5, isAbsolute as isAbsolute3 } from "path";
6017
- import { existsSync as existsSync10, realpathSync as realpathSync2, statSync } from "fs";
6016
+ import { dirname as dirname6, isAbsolute as isAbsolute3 } from "path";
6017
+ import { existsSync as existsSync11, realpathSync as realpathSync2, statSync } from "fs";
6018
6018
  import { tmpdir as tmpdir2 } from "os";
6019
6019
  function isDeniedEnvName(name) {
6020
6020
  const upper = name.toUpperCase();
@@ -6062,9 +6062,9 @@ function isUnsafePathEntry(entry, home) {
6062
6062
  }
6063
6063
  function sanitizeHookPath(pathValue, home) {
6064
6064
  const baseline = PATH_BASELINE.slice();
6065
- if (process.platform === "darwin" && existsSync10("/opt/homebrew/bin"))
6065
+ if (process.platform === "darwin" && existsSync11("/opt/homebrew/bin"))
6066
6066
  baseline.push("/opt/homebrew/bin");
6067
- const bunDir = dirname5(process.execPath);
6067
+ const bunDir = dirname6(process.execPath);
6068
6068
  const seen = new Set;
6069
6069
  const out = [];
6070
6070
  for (const dir of baseline) {
@@ -6188,8 +6188,8 @@ __export(exports_run, {
6188
6188
  HookTimeoutError: () => HookTimeoutError
6189
6189
  });
6190
6190
  import { randomBytes as randomBytes2 } from "crypto";
6191
- import { rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
6192
- import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute4, join as join12 } from "path";
6191
+ import { rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
6192
+ import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute4, join as join12 } from "path";
6193
6193
  function extensionOf(scriptPath) {
6194
6194
  const base = basename2(scriptPath);
6195
6195
  const dot = base.lastIndexOf(".");
@@ -6258,7 +6258,7 @@ async function readPipeWithDeadline(stream, deadlineMs) {
6258
6258
  return chunks.join("");
6259
6259
  }
6260
6260
  async function executeVerifiedScript(options) {
6261
- const scriptDir = dirname6(options.scriptPath);
6261
+ const scriptDir = dirname7(options.scriptPath);
6262
6262
  const interpreter = interpreterFor(options.name, options.scriptPath, options.content);
6263
6263
  const tempPath = join12(scriptDir, `.hooks-verified-${randomBytes2(12).toString("hex")}.${interpreter.tempExt}`);
6264
6264
  let proc = null;
@@ -6268,7 +6268,7 @@ async function executeVerifiedScript(options) {
6268
6268
  killGroup(proc, { leaderAlive: proc !== null && proc.exitCode === null });
6269
6269
  }, options.timeout) : null;
6270
6270
  try {
6271
- writeFileSync5(tempPath, options.content, { flag: "wx", mode: 384 });
6271
+ writeFileSync6(tempPath, options.content, { flag: "wx", mode: 384 });
6272
6272
  proc = Bun.spawn([...interpreter.command, isAbsolute4(tempPath) ? tempPath : `./${tempPath}`, ...options.args ?? []], {
6273
6273
  stdin: new Response(options.stdin),
6274
6274
  stdout: "pipe",
@@ -7016,6 +7016,17 @@ var HOOKS = [
7016
7016
  matcher: "",
7017
7017
  tags: ["knowledge", "context", "codewith", "deterministic", "session-start", "prompt", "subagent"]
7018
7018
  },
7019
+ {
7020
+ name: "mementos-context",
7021
+ displayName: "Mementos Prompt Context",
7022
+ description: "Retrieves scoped memories for a user prompt, with optional relevance judgments",
7023
+ version: "0.1.0",
7024
+ category: "Context Management",
7025
+ event: "UserPromptSubmit",
7026
+ matcher: "",
7027
+ timeoutSeconds: 12,
7028
+ tags: ["mementos", "memory", "prompt", "codex", "claude", "codewith", "opt-in"]
7029
+ },
7019
7030
  {
7020
7031
  name: "autoformat",
7021
7032
  displayName: "Auto Format",
@@ -7341,8 +7352,8 @@ function getHook(name) {
7341
7352
  return HOOKS.find((h) => h.name === name);
7342
7353
  }
7343
7354
  // src/lib/installer.ts
7344
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, readdirSync as readdirSync3, rmdirSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
7345
- import { join as join7, dirname as dirname3 } from "path";
7355
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, readdirSync as readdirSync3, rmdirSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
7356
+ import { join as join7, dirname as dirname4 } from "path";
7346
7357
  import { homedir as homedir3 } from "os";
7347
7358
  import { fileURLToPath as fileURLToPath2 } from "url";
7348
7359
 
@@ -7434,15 +7445,157 @@ function resolveHook(name) {
7434
7445
  // src/lib/installer.ts
7435
7446
  init_manifest();
7436
7447
 
7448
+ // src/lib/mementos-options.ts
7449
+ function validateMementosRegistration(name, value) {
7450
+ if (value === undefined)
7451
+ return;
7452
+ if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)) || !Object.hasOwn(value, "enabled") || Object.keys(value).some((key) => key !== "enabled" && key !== "secretRef") || name.replace(/^hook-/, "") !== "mementos-context" || typeof value.enabled !== "boolean") {
7453
+ throw new Error("Mementos options require the mementos-context hook and an explicit enable/disable choice.");
7454
+ }
7455
+ if (value.secretRef !== undefined && (!value.enabled || typeof value.secretRef !== "string" || value.secretRef.length > 256 || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]*(?:\/[a-zA-Z0-9][a-zA-Z0-9_.-]*){1,12}$/.test(value.secretRef))) {
7456
+ throw new Error("OpenRouter requires an enabled Mementos hook and a valid Secrets reference, never a key value.");
7457
+ }
7458
+ }
7459
+ function mementosRegistrationFromFlags(name, flags) {
7460
+ if (!flags.enableMementos && !flags.disableMementos && flags.openrouterSecretRef === undefined)
7461
+ return;
7462
+ if (Boolean(flags.enableMementos) === Boolean(flags.disableMementos)) {
7463
+ throw new Error("Choose exactly one of --enable-mementos or --disable-mementos.");
7464
+ }
7465
+ const value = { enabled: flags.enableMementos === true, ...flags.openrouterSecretRef !== undefined ? { secretRef: flags.openrouterSecretRef } : {} };
7466
+ validateMementosRegistration(name, value);
7467
+ return value;
7468
+ }
7469
+ function mementosCommandSuffix(value) {
7470
+ validateMementosRegistration("mementos-context", value);
7471
+ if (!value)
7472
+ return "";
7473
+ return value.enabled ? ` --enable-mementos${value.secretRef ? ` --openrouter-secret-ref ${value.secretRef}` : ""}` : " --disable-mementos";
7474
+ }
7475
+ function retainedMementosRegistration(commands) {
7476
+ const values = commands.filter((command) => /^hooks run mementos-context(?:\s|$)/.test(command)).map((command) => {
7477
+ const args = command.trim().split(/\s+/).slice(3);
7478
+ const flags = {};
7479
+ const seen = new Set;
7480
+ while (args.length) {
7481
+ const key = args.shift();
7482
+ if (seen.has(key))
7483
+ throw new Error("Ambiguous Mementos registration; specify its enablement explicitly.");
7484
+ seen.add(key);
7485
+ if (key === "--profile" && /^[\w-]+$/.test(args[0] ?? ""))
7486
+ args.shift();
7487
+ else if (key === "--enable-mementos")
7488
+ flags.enableMementos = true;
7489
+ else if (key === "--disable-mementos")
7490
+ flags.disableMementos = true;
7491
+ else if (key === "--openrouter-secret-ref" && args.length)
7492
+ flags.openrouterSecretRef = args.shift();
7493
+ else
7494
+ throw new Error("Unrecognized Mementos registration options; specify its enablement explicitly.");
7495
+ }
7496
+ return mementosRegistrationFromFlags("mementos-context", flags);
7497
+ });
7498
+ if (new Set(values.map((value) => JSON.stringify(value))).size > 1) {
7499
+ throw new Error("Conflicting Mementos registrations; specify its enablement explicitly.");
7500
+ }
7501
+ return values[0];
7502
+ }
7503
+
7437
7504
  // src/lib/registration.ts
7505
+ var REGISTRATION_COMMAND_RE = /^(?:hooks run ([\w-]+)(?:\s+--profile\s+[\w-]+)?|hook-([\w-]+))$/;
7506
+ function registrationName(command) {
7507
+ if (typeof command !== "string")
7508
+ return;
7509
+ if (/^hooks run mementos-context(?:\s|$)/.test(command.trim())) {
7510
+ try {
7511
+ retainedMementosRegistration([command.trim()]);
7512
+ return "mementos-context";
7513
+ } catch {
7514
+ return;
7515
+ }
7516
+ }
7517
+ const match = command.trim().match(REGISTRATION_COMMAND_RE);
7518
+ return match ? match[1] ?? match[2] : undefined;
7519
+ }
7438
7520
  function matchersOverlap(a, b) {
7439
7521
  return a === b || a.includes(b) || b.includes(a);
7440
7522
  }
7441
7523
 
7442
7524
  // src/lib/installer.ts
7443
7525
  init_store();
7444
- var __dirname2 = dirname3(fileURLToPath2(import.meta.url));
7445
- var HOOKS_DIR = existsSync7(join7(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join7(__dirname2, "..", "..", "hooks") : join7(__dirname2, "..", "hooks");
7526
+
7527
+ // src/lib/codex-settings.ts
7528
+ import { closeSync, existsSync as existsSync7, lstatSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync4, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
7529
+ import { dirname as dirname3 } from "path";
7530
+ import { randomUUID } from "crypto";
7531
+ var snapshots = new WeakMap;
7532
+ function current(path) {
7533
+ try {
7534
+ const stat = lstatSync(path);
7535
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1048576)
7536
+ throw new Error("invalid_file");
7537
+ return readFileSync4(path, "utf8");
7538
+ } catch (error) {
7539
+ if (error.code === "ENOENT")
7540
+ return null;
7541
+ throw new Error("Cannot safely read Codex hooks.json; no settings were changed.");
7542
+ }
7543
+ }
7544
+ function readCodexSettings(path) {
7545
+ const raw = current(path);
7546
+ let settings;
7547
+ try {
7548
+ settings = raw === null ? {} : JSON.parse(raw);
7549
+ if (!settings || typeof settings !== "object" || Array.isArray(settings))
7550
+ throw new Error;
7551
+ if (settings.hooks !== undefined) {
7552
+ if (!settings.hooks || typeof settings.hooks !== "object" || Array.isArray(settings.hooks))
7553
+ throw new Error;
7554
+ for (const entries of Object.values(settings.hooks)) {
7555
+ if (!Array.isArray(entries) || entries.some((entry) => !entry || !Array.isArray(entry.hooks) || entry.hooks.some((hook) => !hook || typeof hook !== "object")))
7556
+ throw new Error;
7557
+ }
7558
+ }
7559
+ } catch {
7560
+ throw new Error("Invalid Codex hooks.json; repair it before installing or removing hooks.");
7561
+ }
7562
+ snapshots.set(settings, { path, raw });
7563
+ return settings;
7564
+ }
7565
+ function writeCodexSettings(path, settings) {
7566
+ const snapshot = snapshots.get(settings);
7567
+ if (!snapshot || snapshot.path !== path)
7568
+ throw new Error("Codex settings require a complete current read before writing.");
7569
+ mkdirSync4(dirname3(path), { recursive: true });
7570
+ const lock = `${path}.hooks-write.lock`;
7571
+ let fd;
7572
+ try {
7573
+ fd = openSync(lock, "wx", 384);
7574
+ } catch {
7575
+ throw new Error("Codex settings are being edited; retry after the active writer finishes.");
7576
+ }
7577
+ const temp = `${path}.${randomUUID()}.tmp`;
7578
+ try {
7579
+ if (current(path) !== snapshot.raw)
7580
+ throw new Error("Codex settings changed since reading; re-read before retrying.");
7581
+ const next = JSON.stringify(settings, null, 2) + `
7582
+ `;
7583
+ writeFileSync3(temp, next, { flag: "wx", mode: 384 });
7584
+ if (current(path) !== snapshot.raw)
7585
+ throw new Error("Codex settings changed since reading; re-read before retrying.");
7586
+ renameSync2(temp, path);
7587
+ snapshots.set(settings, { path, raw: next });
7588
+ } finally {
7589
+ if (existsSync7(temp))
7590
+ unlinkSync(temp);
7591
+ closeSync(fd);
7592
+ unlinkSync(lock);
7593
+ }
7594
+ }
7595
+
7596
+ // src/lib/installer.ts
7597
+ var __dirname2 = dirname4(fileURLToPath2(import.meta.url));
7598
+ var HOOKS_DIR = existsSync8(join7(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join7(__dirname2, "..", "..", "hooks") : join7(__dirname2, "..", "hooks");
7446
7599
  function normalizeHookName(name) {
7447
7600
  return name.startsWith("hook-") ? name : `hook-${name}`;
7448
7601
  }
@@ -7450,10 +7603,15 @@ function shortHookName(name) {
7450
7603
  return name.startsWith("hook-") ? name.slice("hook-".length) : name;
7451
7604
  }
7452
7605
  function removeHookEntriesByName(entries, hookName) {
7453
- return entries.filter((entry) => !entry.hooks?.some((h) => {
7454
- const match = h.command?.match(/^hooks run ([\w-]+)/);
7455
- return match && match[1] === hookName;
7456
- }));
7606
+ return entries.flatMap((entry) => {
7607
+ if (!Array.isArray(entry.hooks))
7608
+ return [entry];
7609
+ const kept = entry.hooks.filter((h) => {
7610
+ const match = h.command?.match(/^hooks run ([\w-]+)/);
7611
+ return !(match && match[1] === hookName);
7612
+ });
7613
+ return kept.length === entry.hooks.length ? [entry] : kept.length ? [{ ...entry, hooks: kept }] : [];
7614
+ });
7457
7615
  }
7458
7616
  var EVENT_MAP = {
7459
7617
  claude: {
@@ -7463,7 +7621,7 @@ var EVENT_MAP = {
7463
7621
  Notification: "Notification",
7464
7622
  SessionStart: "SessionStart",
7465
7623
  SessionEnd: "SessionEnd",
7466
- UserPromptSubmit: null,
7624
+ UserPromptSubmit: "UserPromptSubmit",
7467
7625
  SubagentStart: null
7468
7626
  },
7469
7627
  gemini: {
@@ -7485,9 +7643,21 @@ var EVENT_MAP = {
7485
7643
  SessionEnd: null,
7486
7644
  UserPromptSubmit: "UserPromptSubmit",
7487
7645
  SubagentStart: "SubagentStart"
7646
+ },
7647
+ codex: {
7648
+ PreToolUse: "PreToolUse",
7649
+ PostToolUse: "PostToolUse",
7650
+ Stop: "Stop",
7651
+ Notification: null,
7652
+ SessionStart: "SessionStart",
7653
+ SessionEnd: "SessionEnd",
7654
+ UserPromptSubmit: "UserPromptSubmit",
7655
+ SubagentStart: "SubagentStart"
7488
7656
  }
7489
7657
  };
7490
7658
  function getTargetSettingsDir(target) {
7659
+ if (target === "codex")
7660
+ return ".codex";
7491
7661
  if (target === "codewith")
7492
7662
  return ".codewith";
7493
7663
  if (target === "gemini")
@@ -7495,6 +7665,8 @@ function getTargetSettingsDir(target) {
7495
7665
  return ".claude";
7496
7666
  }
7497
7667
  function getGlobalSettingsPathOverride(target) {
7668
+ if (target === "codex")
7669
+ return process.env.HASNA_HOOKS_CODEX_SETTINGS_PATH;
7498
7670
  if (target === "claude")
7499
7671
  return process.env.HASNA_HOOKS_CLAUDE_SETTINGS_PATH;
7500
7672
  if (target === "gemini")
@@ -7511,6 +7683,8 @@ function getSettingsPath(scope = "global", target = "claude", codewithConfigPath
7511
7683
  if (globalOverride)
7512
7684
  return globalOverride;
7513
7685
  const dir = getTargetSettingsDir(target);
7686
+ if (target === "codex")
7687
+ return join7(scope === "project" ? process.cwd() : homedir3(), dir, "hooks.json");
7514
7688
  if (scope === "project") {
7515
7689
  return target === "codewith" ? join7(process.cwd(), dir, "config.toml") : join7(process.cwd(), dir, "settings.json");
7516
7690
  }
@@ -7524,13 +7698,15 @@ function getHookPath(name) {
7524
7698
  return join7(HOOKS_DIR, normalizeHookName(shortName));
7525
7699
  }
7526
7700
  function hookExists(name) {
7527
- return existsSync7(getHookPath(name));
7701
+ return existsSync8(getHookPath(name));
7528
7702
  }
7529
7703
  function readSettings(scope = "global", target = "claude") {
7530
7704
  const path = getSettingsPath(scope, target);
7705
+ if (target === "codex")
7706
+ return readCodexSettings(path);
7531
7707
  try {
7532
- if (existsSync7(path)) {
7533
- return JSON.parse(readFileSync4(path, "utf-8"));
7708
+ if (existsSync8(path)) {
7709
+ return JSON.parse(readFileSync5(path, "utf-8"));
7534
7710
  }
7535
7711
  } catch (error) {
7536
7712
  console.warn(`[hooks] Failed to read settings at ${path}: ${error instanceof Error ? error.message : String(error)}`);
@@ -7539,11 +7715,13 @@ function readSettings(scope = "global", target = "claude") {
7539
7715
  }
7540
7716
  function writeSettings(settings, scope = "global", target = "claude") {
7541
7717
  const path = getSettingsPath(scope, target);
7542
- const dir = dirname3(path);
7543
- if (!existsSync7(dir)) {
7544
- mkdirSync4(dir, { recursive: true });
7718
+ if (target === "codex")
7719
+ return writeCodexSettings(path, settings);
7720
+ const dir = dirname4(path);
7721
+ if (!existsSync8(dir)) {
7722
+ mkdirSync5(dir, { recursive: true });
7545
7723
  }
7546
- writeFileSync3(path, JSON.stringify(settings, null, 2) + `
7724
+ writeFileSync4(path, JSON.stringify(settings, null, 2) + `
7547
7725
  `);
7548
7726
  }
7549
7727
  function getTargetEventName(internalEvent, target) {
@@ -7566,6 +7744,8 @@ function codewithMatcher(matcher) {
7566
7744
  }
7567
7745
  function codewithTimeout(name) {
7568
7746
  switch (name) {
7747
+ case "mementos-context":
7748
+ return 12;
7569
7749
  case "knowledge-context":
7570
7750
  return 6;
7571
7751
  case "session-start":
@@ -7602,12 +7782,13 @@ function codewithStatusMessage(name) {
7602
7782
  return `Running ${name}`;
7603
7783
  }
7604
7784
  }
7605
- function buildCodewithTomlFragment(name, profile) {
7785
+ function buildCodewithTomlFragment(name, profile, mementos) {
7606
7786
  const shortName = shortHookName(name);
7607
7787
  const meta = resolveHookMeta(shortName);
7608
7788
  if (!meta)
7609
7789
  throw new Error(`Hook '${shortName}' not found`);
7610
- const command = profile ? `hooks run ${shortName} --profile ${profile}` : `hooks run ${shortName}`;
7790
+ validateMementosRegistration(shortName, mementos);
7791
+ const command = (profile ? `hooks run ${shortName} --profile ${profile}` : `hooks run ${shortName}`) + mementosCommandSuffix(mementos);
7611
7792
  const matcher = codewithMatcher(meta.matcher);
7612
7793
  const fragments = [];
7613
7794
  for (const event of getHookEvents(meta)) {
@@ -7632,21 +7813,21 @@ function buildCodewithTomlFragment(name, profile) {
7632
7813
  function readCodewithConfig(scope, configPath) {
7633
7814
  const path = getSettingsPath(scope, "codewith", configPath);
7634
7815
  try {
7635
- return existsSync7(path) ? readFileSync4(path, "utf-8") : "";
7816
+ return existsSync8(path) ? readFileSync5(path, "utf-8") : "";
7636
7817
  } catch {
7637
7818
  return "";
7638
7819
  }
7639
7820
  }
7640
7821
  function appendCodewithFragment(fragment, scope, configPath) {
7641
7822
  const path = getSettingsPath(scope, "codewith", configPath);
7642
- const dir = dirname3(path);
7643
- if (!existsSync7(dir))
7644
- mkdirSync4(dir, { recursive: true });
7645
- const existing = existsSync7(path) ? readFileSync4(path, "utf-8") : "";
7823
+ const dir = dirname4(path);
7824
+ if (!existsSync8(dir))
7825
+ mkdirSync5(dir, { recursive: true });
7826
+ const existing = existsSync8(path) ? readFileSync5(path, "utf-8") : "";
7646
7827
  const sep2 = existing.trim() ? `
7647
7828
 
7648
7829
  ` : "";
7649
- writeFileSync3(path, `${existing.replace(/\s*$/, "")}${sep2}${fragment}`);
7830
+ writeFileSync4(path, `${existing.replace(/\s*$/, "")}${sep2}${fragment}`);
7650
7831
  return path;
7651
7832
  }
7652
7833
  function detectConflict(name, scope, target) {
@@ -7689,14 +7870,14 @@ function detectRewriteConflict(name, scope, target, lookup = getHook) {
7689
7870
  }
7690
7871
  return;
7691
7872
  }
7692
- function installForTarget(name, scope, overwrite, target, profile, codewithMode = "fragment", codewithConfigPath) {
7873
+ function installForTarget(name, scope, overwrite, target, profile, codewithMode = "fragment", codewithConfigPath, mementos) {
7693
7874
  const shortName = shortHookName(name);
7694
7875
  if (!hookExists(shortName)) {
7695
7876
  return { hook: shortName, success: false, error: `Hook '${shortName}' not found`, target };
7696
7877
  }
7697
7878
  if (target === "codewith") {
7698
7879
  try {
7699
- const fragment = buildCodewithTomlFragment(shortName, profile);
7880
+ const fragment = buildCodewithTomlFragment(shortName, profile, mementos);
7700
7881
  if (codewithMode !== "write") {
7701
7882
  return {
7702
7883
  hook: shortName,
@@ -7743,18 +7924,25 @@ function installForTarget(name, scope, overwrite, target, profile, codewithMode
7743
7924
  };
7744
7925
  }
7745
7926
  }
7746
- const registered = getRegisteredHooksForTarget(scope, target);
7747
- if (registered.includes(shortName) && !overwrite) {
7748
- return { hook: shortName, success: false, error: "Already installed. Use --overwrite to replace.", scope, target };
7749
- }
7750
- const conflict = detectConflict(shortName, scope, target);
7751
- const rewriteConflict = detectRewriteConflict(shortName, scope, target);
7752
- if (rewriteConflict) {
7753
- return { hook: shortName, success: false, error: `Refused: ${rewriteConflict}`, scope, target };
7754
- }
7755
7927
  try {
7756
- registerHook(shortName, scope, target, profile);
7757
- return { hook: shortName, success: true, scope, target, ...conflict ? { conflict } : {} };
7928
+ const registered = getRegisteredHooksForTarget(scope, target);
7929
+ if (registered.includes(shortName) && !overwrite) {
7930
+ return { hook: shortName, success: false, error: "Already installed. Use --overwrite to replace.", scope, target };
7931
+ }
7932
+ const conflict = detectConflict(shortName, scope, target);
7933
+ const rewriteConflict = detectRewriteConflict(shortName, scope, target);
7934
+ if (rewriteConflict) {
7935
+ return { hook: shortName, success: false, error: `Refused: ${rewriteConflict}`, scope, target };
7936
+ }
7937
+ registerHook(shortName, scope, target, profile, mementos);
7938
+ return {
7939
+ hook: shortName,
7940
+ success: true,
7941
+ scope,
7942
+ target,
7943
+ ...conflict ? { conflict } : {},
7944
+ ...target === "codex" ? { applied: true, configPath: getSettingsPath(scope, target), note: "Registered in Codex hooks.json. Review and trust the exact definition in Codex /hooks; project hooks also require a trusted project. Registration alone does not prove execution." } : {}
7945
+ };
7758
7946
  } catch (error) {
7759
7947
  return {
7760
7948
  hook: shortName,
@@ -7765,7 +7953,15 @@ function installForTarget(name, scope, overwrite, target, profile, codewithMode
7765
7953
  }
7766
7954
  }
7767
7955
  function installHook(name, options = {}) {
7768
- const { scope = "global", overwrite = false, target = "claude", profile, codewithMode = "fragment", codewithConfigPath } = options;
7956
+ const { scope = "global", overwrite = false, target = "claude", profile, codewithMode = "fragment", codewithConfigPath, mementos } = options;
7957
+ try {
7958
+ validateMementosRegistration(name, mementos);
7959
+ } catch (error) {
7960
+ return { hook: name, success: false, target, error: error instanceof Error ? error.message : "Invalid Mementos options" };
7961
+ }
7962
+ if (!/^[\w-]+$/.test(name) || profile !== undefined && !/^[\w-]+$/.test(profile)) {
7963
+ return { hook: name, success: false, error: "Hook and profile names must contain only letters, digits, underscores or hyphens.", target };
7964
+ }
7769
7965
  if (target === "all") {
7770
7966
  const shortName = shortHookName(name);
7771
7967
  const meta = resolveHookMeta(shortName);
@@ -7780,7 +7976,7 @@ function installHook(name, options = {}) {
7780
7976
  };
7781
7977
  }
7782
7978
  }
7783
- const claudeResult = installForTarget(name, scope, overwrite, "claude", profile);
7979
+ const claudeResult = installForTarget(name, scope, overwrite, "claude", profile, "fragment", undefined, mementos);
7784
7980
  if (!claudeResult.success) {
7785
7981
  return {
7786
7982
  ...claudeResult,
@@ -7788,7 +7984,7 @@ function installHook(name, options = {}) {
7788
7984
  target: "all"
7789
7985
  };
7790
7986
  }
7791
- const codewithResult = installForTarget(name, scope, overwrite, "codewith", profile, codewithMode, codewithConfigPath);
7987
+ const codewithResult = installForTarget(name, scope, overwrite, "codewith", profile, codewithMode, codewithConfigPath, mementos);
7792
7988
  if (!codewithResult.success) {
7793
7989
  return {
7794
7990
  ...codewithResult,
@@ -7798,9 +7994,9 @@ function installHook(name, options = {}) {
7798
7994
  }
7799
7995
  return { ...claudeResult, target: "all" };
7800
7996
  }
7801
- return installForTarget(name, scope, overwrite, target, profile, codewithMode, codewithConfigPath);
7997
+ return installForTarget(name, scope, overwrite, target, profile, codewithMode, codewithConfigPath, mementos);
7802
7998
  }
7803
- function registerHook(name, scope = "global", target = "claude", profile) {
7999
+ function registerHook(name, scope = "global", target = "claude", profile, mementos) {
7804
8000
  const meta = resolveHookMeta(name);
7805
8001
  if (!meta)
7806
8002
  return;
@@ -7818,8 +8014,9 @@ function registerHook(name, scope = "global", target = "claude", profile) {
7818
8014
  const settings = readSettings(scope, target);
7819
8015
  if (!settings.hooks)
7820
8016
  settings.hooks = {};
8017
+ const retained = name === "mementos-context" && mementos === undefined ? retainedMementosRegistration(Object.values(settings.hooks).flatMap((groups) => Array.isArray(groups) ? groups.flatMap((group) => Array.isArray(group.hooks) ? group.hooks.map((hook) => hook.command).filter((command) => typeof command === "string") : []) : [])) : undefined;
7821
8018
  removeHookFromAllEvents(settings, name);
7822
- const hookCommand = profile ? `hooks run ${name} --profile ${profile}` : `hooks run ${name}`;
8019
+ const hookCommand = (profile ? `hooks run ${name} --profile ${profile}` : `hooks run ${name}`) + mementosCommandSuffix(mementos ?? retained);
7823
8020
  for (const eventKey of uniqueEventKeys) {
7824
8021
  if (!settings.hooks[eventKey])
7825
8022
  settings.hooks[eventKey] = [];
@@ -7864,10 +8061,12 @@ function getRegisteredHooksForTarget(scope = "global", target = "claude") {
7864
8061
  if (target === "codewith") {
7865
8062
  const config = readCodewithConfig(scope);
7866
8063
  const registered2 = [];
7867
- const re = /command\s*=\s*["']hooks run ([\w-]+)(?:\s+--profile\s+[\w-]+)?["']/g;
8064
+ const re = /^\s*command\s*=\s*["']([^"'\n]+)["']\s*$/gm;
7868
8065
  let match;
7869
8066
  while (match = re.exec(config)) {
7870
- registered2.push(match[1]);
8067
+ const name = registrationName(match[1]);
8068
+ if (name)
8069
+ registered2.push(name);
7871
8070
  }
7872
8071
  return [...new Set(registered2)];
7873
8072
  }
@@ -7878,12 +8077,9 @@ function getRegisteredHooksForTarget(scope = "global", target = "claude") {
7878
8077
  for (const eventKey of Object.keys(settings.hooks)) {
7879
8078
  for (const entry of settings.hooks[eventKey]) {
7880
8079
  for (const hook of entry.hooks || []) {
7881
- const newMatch = hook.command?.match(/^hooks run ([\w-]+)(?:\s+--profile\s+[\w-]+)?$/);
7882
- const oldMatch = hook.command?.match(/^hook-([\w-]+)$/);
7883
- const match = newMatch || oldMatch;
7884
- if (match) {
7885
- registered.push(match[1]);
7886
- }
8080
+ const name = registrationName(hook.command);
8081
+ if (name)
8082
+ registered.push(name);
7887
8083
  }
7888
8084
  }
7889
8085
  }
@@ -7898,7 +8094,8 @@ function removeHook(name, scope = "global", target = "claude") {
7898
8094
  if (target === "all") {
7899
8095
  const claudeRemoved = removeHookForTarget(shortName, scope, "claude");
7900
8096
  const geminiRemoved = removeHookForTarget(shortName, scope, "gemini");
7901
- return claudeRemoved || geminiRemoved;
8097
+ const codexRemoved = removeHookForTarget(shortName, scope, "codex");
8098
+ return claudeRemoved || geminiRemoved || codexRemoved;
7902
8099
  }
7903
8100
  if (target === "codewith") {
7904
8101
  return false;
@@ -7913,9 +8110,10 @@ function removeHookForTarget(name, scope, target) {
7913
8110
  unregisterHook(name, scope, target);
7914
8111
  return true;
7915
8112
  }
8113
+ var JSON_SETTINGS_TARGETS = ["claude", "gemini", "codex"];
7916
8114
  function removeCodewithHookEntry(configText, name) {
7917
8115
  const sections = configText.split(/\n\s*\n/);
7918
- const nameRe = new RegExp(`^command\\s*=\\s*"hooks run ${escapeRegExp(name)}(?:\\s+--profile\\s+[\\w-]+)?"$`);
8116
+ const commandRe = /^command\s*=\s*"([^"\n]+)"$/;
7919
8117
  const entryHeaderRe = /^\[\[hooks\.([\w]+)\.hooks\]\]$/;
7920
8118
  const eventHeaderRe = /^\[\[hooks\.([\w]+)\]\]$/;
7921
8119
  const eventsWithEntries = new Set;
@@ -7928,7 +8126,7 @@ function removeCodewithHookEntry(configText, name) {
7928
8126
  if (entryMatch) {
7929
8127
  const event = entryMatch[1];
7930
8128
  eventsWithEntries.add(event);
7931
- if (lines.some((line) => nameRe.test(line.trim()))) {
8129
+ if (lines.some((line) => registrationName(commandRe.exec(line.trim())?.[1]) === name)) {
7932
8130
  removed = true;
7933
8131
  continue;
7934
8132
  }
@@ -7969,10 +8167,10 @@ function codewithHasHookEntryInText(configText, name) {
7969
8167
  }
7970
8168
  function codewithHasHookEntry(name, scope = "global") {
7971
8169
  const path = getSettingsPath(scope, "codewith");
7972
- if (!existsSync7(path))
8170
+ if (!existsSync8(path))
7973
8171
  return false;
7974
8172
  try {
7975
- return codewithHasHookEntryInText(readFileSync4(path, "utf-8"), name);
8173
+ return codewithHasHookEntryInText(readFileSync5(path, "utf-8"), name);
7976
8174
  } catch {
7977
8175
  return false;
7978
8176
  }
@@ -7986,7 +8184,7 @@ function removeStoreDirFailClosed(dir) {
7986
8184
  }
7987
8185
  for (const entry of entries) {
7988
8186
  if (!entry.isDirectory()) {
7989
- unlinkSync(join7(dir, entry.name));
8187
+ unlinkSync2(join7(dir, entry.name));
7990
8188
  }
7991
8189
  }
7992
8190
  rmdirSync(dir);
@@ -7996,14 +8194,14 @@ function uninstallHook(name, scope = "global", target = "claude") {
7996
8194
  const custom2 = readCustomManifest(shortName);
7997
8195
  const bundledMeta = custom2 ? undefined : getHook(shortName);
7998
8196
  const existsInTarget = (t) => getRegisteredHooksForTarget("global", t).includes(shortName) || getRegisteredHooksForTarget("project", t).includes(shortName);
7999
- const registeredClaudeOrGemini = target === "all" ? existsInTarget("claude") || existsInTarget("gemini") : false;
8197
+ const registeredClaudeOrGemini = target === "all" ? JSON_SETTINGS_TARGETS.some(existsInTarget) : false;
8000
8198
  const registeredGlobal = registeredClaudeOrGemini || getRegisteredHooksForTarget("global", target === "all" ? "claude" : target).includes(shortName);
8001
8199
  const registeredProject = registeredClaudeOrGemini || getRegisteredHooksForTarget("project", target === "all" ? "claude" : target).includes(shortName);
8002
8200
  const codewithOnly = (target === "codewith" || target === "all") && codewithHasHookEntry(shortName, scope);
8003
8201
  if (!custom2 && !bundledMeta && !registeredGlobal && !registeredProject && !codewithOnly) {
8004
8202
  return { name: shortName, removed: false, source: null, settingsScopes: [], storeDirRemoved: false, pinRemoved: false, dbRecordRemoved: false, registrationsRemaining: [], error: `Hook '${shortName}' not found` };
8005
8203
  }
8006
- const writableTargets = target === "all" ? ["claude", "gemini"] : target === "codewith" ? [] : [target];
8204
+ const writableTargets = target === "all" ? JSON_SETTINGS_TARGETS : target === "codewith" ? [] : [target];
8007
8205
  const scopes = [];
8008
8206
  for (const s of ["global", "project"]) {
8009
8207
  for (const t of writableTargets) {
@@ -8017,11 +8215,11 @@ function uninstallHook(name, scope = "global", target = "claude") {
8017
8215
  const registrationsRemaining = [];
8018
8216
  if (target === "codewith" || target === "all") {
8019
8217
  const codewithPath = getSettingsPath(scope, "codewith");
8020
- if (existsSync7(codewithPath)) {
8021
- const before = readFileSync4(codewithPath, "utf-8");
8218
+ if (existsSync8(codewithPath)) {
8219
+ const before = readFileSync5(codewithPath, "utf-8");
8022
8220
  const after = removeCodewithHookEntry(before, shortName);
8023
8221
  if (after.removed) {
8024
- writeFileSync3(codewithPath, after.text, "utf-8");
8222
+ writeFileSync4(codewithPath, after.text, "utf-8");
8025
8223
  }
8026
8224
  if (codewithHasHookEntryInText(after.removed ? after.text : before, shortName)) {
8027
8225
  registrationsRemaining.push("codewith");
@@ -8060,7 +8258,7 @@ function uninstallHook(name, scope = "global", target = "claude") {
8060
8258
  // src/index.ts
8061
8259
  init_profiles();
8062
8260
  init_config();
8063
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
8261
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
8064
8262
 
8065
8263
  // src/lib/transport.ts
8066
8264
  init_transport();
@@ -8147,15 +8345,15 @@ init_manifest();
8147
8345
  // src/lib/custom-install.ts
8148
8346
  init_config();
8149
8347
  init_manifest();
8150
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, mkdtempSync, readFileSync as readFileSync7, rmSync as rmSync2 } from "fs";
8348
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, mkdtempSync, readFileSync as readFileSync8, rmSync as rmSync2 } from "fs";
8151
8349
  import { join as join10 } from "path";
8152
8350
  import { tmpdir } from "os";
8153
8351
  function manifestAt(dir) {
8154
8352
  const path = join10(dir, "manifest.json");
8155
- if (!existsSync9(path))
8353
+ if (!existsSync10(path))
8156
8354
  return;
8157
8355
  try {
8158
- return parseManifest(readFileSync7(path, "utf-8"));
8356
+ return parseManifest(readFileSync8(path, "utf-8"));
8159
8357
  } catch {
8160
8358
  return;
8161
8359
  }
@@ -8198,7 +8396,7 @@ function isCustomSource(value) {
8198
8396
  return true;
8199
8397
  if (value.startsWith("http://") || value.startsWith("https://"))
8200
8398
  return true;
8201
- return existsSync9(value);
8399
+ return existsSync10(value);
8202
8400
  }
8203
8401
  async function installCustomSource(source) {
8204
8402
  if (isGitUrl(source)) {
@@ -8212,11 +8410,11 @@ async function installCustomSource(source) {
8212
8410
  if (source.startsWith("http://") || source.startsWith("https://")) {
8213
8411
  return installManifestUrl(source);
8214
8412
  }
8215
- if (!existsSync9(source)) {
8413
+ if (!existsSync10(source)) {
8216
8414
  throw new Error(`No such local path: ${source}`);
8217
8415
  }
8218
8416
  if (source.endsWith("manifest.json")) {
8219
- const manifest = parseManifest(readFileSync7(source, "utf-8"));
8417
+ const manifest = parseManifest(readFileSync8(source, "utf-8"));
8220
8418
  return writeFromManifest(manifest, source.substring(0, source.lastIndexOf("/")), source, "local");
8221
8419
  }
8222
8420
  return copyManifestDir(source, source, "local");
@@ -8247,7 +8445,7 @@ async function installManifestUrl(url) {
8247
8445
  }
8248
8446
  // src/lib/sync.ts
8249
8447
  import { createHash as createHash2 } from "crypto";
8250
- import { readFileSync as readFileSync8 } from "fs";
8448
+ import { readFileSync as readFileSync9 } from "fs";
8251
8449
  init_db();
8252
8450
  init_store();
8253
8451
  init_manifest();
@@ -8255,7 +8453,7 @@ function sha256OfText(text) {
8255
8453
  return createHash2("sha256").update(text).digest("hex");
8256
8454
  }
8257
8455
  function sha256OfPath(path) {
8258
- return createHash2("sha256").update(readFileSync8(path)).digest("hex");
8456
+ return createHash2("sha256").update(readFileSync9(path)).digest("hex");
8259
8457
  }
8260
8458
  function collectBundledCatalog() {
8261
8459
  const out = [];
@@ -8549,8 +8747,8 @@ async function installPinnedFromBundled(name, version) {
8549
8747
  // src/serve.ts
8550
8748
  init_manifest();
8551
8749
  init_store();
8552
- import { readFileSync as readFileSync9 } from "fs";
8553
- import { dirname as dirname4, join as join11 } from "path";
8750
+ import { readFileSync as readFileSync10 } from "fs";
8751
+ import { dirname as dirname5, join as join11 } from "path";
8554
8752
  import { fileURLToPath as fileURLToPath3 } from "url";
8555
8753
 
8556
8754
  // src/lib/secure-compare.ts
@@ -8724,8 +8922,8 @@ var SERVE_HOST = "127.0.0.1";
8724
8922
  var SERVE_SERVICE_NAME = "hooks-registry";
8725
8923
  function packageVersion() {
8726
8924
  try {
8727
- const pkgPath = join11(dirname4(fileURLToPath3(import.meta.url)), "..", "package.json");
8728
- return JSON.parse(readFileSync9(pkgPath, "utf-8")).version || "0.0.0";
8925
+ const pkgPath = join11(dirname5(fileURLToPath3(import.meta.url)), "..", "package.json");
8926
+ return JSON.parse(readFileSync10(pkgPath, "utf-8")).version || "0.0.0";
8729
8927
  } catch {
8730
8928
  return "0.0.0";
8731
8929
  }
@@ -8991,11 +9189,11 @@ async function runHook(name, input, options = {}) {
8991
9189
  throw new Error(`Hook '${name}' not found`);
8992
9190
  const hookScript = getHookPath(name) + "/src/hook.ts";
8993
9191
  const resolvedScript = custom2?.scriptPath;
8994
- const script = resolvedScript ?? (existsSync11(hookScript) ? hookScript : undefined);
9192
+ const script = resolvedScript ?? (existsSync12(hookScript) ? hookScript : undefined);
8995
9193
  if (!script)
8996
9194
  throw new Error(`Hook script not found: ${name}`);
8997
9195
  const { sha256Of: sha256Of2, checkScriptHash: checkScriptHash2 } = await Promise.resolve().then(() => (init_store(), exports_store));
8998
- const content = readFileSync10(script);
9196
+ const content = readFileSync11(script);
8999
9197
  const check = checkScriptHash2(name, sha256Of2(content));
9000
9198
  if (!check.ok) {
9001
9199
  throw new Error(`Hook '${name}' script changed since it was trusted (sha256 ${check.expected} != ${check.actual}). Run 'hooks trust ${name}' to trust the new content.`);