@hasna/hooks 0.10.2 → 0.10.4

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/bin/index.js CHANGED
@@ -47,7 +47,7 @@ var __export = (target, all) => {
47
47
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
48
48
  var __require = import.meta.require;
49
49
 
50
- // ../hooks0102-standalone-lock/node_modules/commander/lib/error.js
50
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
51
51
  var require_error = __commonJS((exports) => {
52
52
  class CommanderError extends Error {
53
53
  constructor(exitCode, code, message) {
@@ -71,7 +71,7 @@ var require_error = __commonJS((exports) => {
71
71
  exports.InvalidArgumentError = InvalidArgumentError;
72
72
  });
73
73
 
74
- // ../hooks0102-standalone-lock/node_modules/commander/lib/argument.js
74
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
75
75
  var require_argument = __commonJS((exports) => {
76
76
  var { InvalidArgumentError } = require_error();
77
77
 
@@ -150,7 +150,7 @@ var require_argument = __commonJS((exports) => {
150
150
  exports.humanReadableArgName = humanReadableArgName;
151
151
  });
152
152
 
153
- // ../hooks0102-standalone-lock/node_modules/commander/lib/help.js
153
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
154
154
  var require_help = __commonJS((exports) => {
155
155
  var { humanReadableArgName } = require_argument();
156
156
 
@@ -399,7 +399,7 @@ var require_help = __commonJS((exports) => {
399
399
  exports.Help = Help;
400
400
  });
401
401
 
402
- // ../hooks0102-standalone-lock/node_modules/commander/lib/option.js
402
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
403
403
  var require_option = __commonJS((exports) => {
404
404
  var { InvalidArgumentError } = require_error();
405
405
 
@@ -550,7 +550,7 @@ var require_option = __commonJS((exports) => {
550
550
  exports.DualOptions = DualOptions;
551
551
  });
552
552
 
553
- // ../hooks0102-standalone-lock/node_modules/commander/lib/suggestSimilar.js
553
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
554
554
  var require_suggestSimilar = __commonJS((exports) => {
555
555
  var maxDistance = 3;
556
556
  function editDistance(a, b) {
@@ -623,7 +623,7 @@ var require_suggestSimilar = __commonJS((exports) => {
623
623
  exports.suggestSimilar = suggestSimilar;
624
624
  });
625
625
 
626
- // ../hooks0102-standalone-lock/node_modules/commander/lib/command.js
626
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
627
627
  var require_command = __commonJS((exports) => {
628
628
  var EventEmitter = __require("events").EventEmitter;
629
629
  var childProcess = __require("child_process");
@@ -1866,7 +1866,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1866
1866
  exports.Command = Command;
1867
1867
  });
1868
1868
 
1869
- // ../hooks0102-standalone-lock/node_modules/commander/index.js
1869
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
1870
1870
  var require_commander = __commonJS((exports) => {
1871
1871
  var { Argument } = require_argument();
1872
1872
  var { Command } = require_command();
@@ -1887,76 +1887,76 @@ var require_commander = __commonJS((exports) => {
1887
1887
  });
1888
1888
 
1889
1889
  // src/lib/app-home.ts
1890
- import { existsSync as existsSync2 } from "fs";
1890
+ import { existsSync as existsSync3 } from "fs";
1891
1891
  import { homedir as homedir2 } from "os";
1892
- import { join as join2, resolve } from "path";
1893
- import { homedir as pathsResolverHomedir } from "os";
1894
- import { join as pathsResolverJoin } from "path";
1895
- function pathsResolverAssertApp(app) {
1892
+ import { join as join3, resolve as resolve2 } from "path";
1893
+ import { homedir as pathsResolverHomedir2 } from "os";
1894
+ import { join as pathsResolverJoin2 } from "path";
1895
+ function pathsResolverAssertApp2(app) {
1896
1896
  if (typeof app !== "string" || app.length === 0) {
1897
1897
  throw new TypeError("paths: app must be a non-empty string");
1898
1898
  }
1899
- if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
1899
+ if (!PATHS_RESOLVER_APP_SLUG_RE2.test(app)) {
1900
1900
  throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
1901
1901
  }
1902
1902
  }
1903
- function pathsResolverAssertKind(kind) {
1904
- if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
1905
- throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
1903
+ function pathsResolverAssertKind2(kind) {
1904
+ if (!Object.keys(PATHS_RESOLVER_KIND_ENV2).includes(kind)) {
1905
+ throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV2).join(", ")}`);
1906
1906
  }
1907
1907
  }
1908
- function pathsResolverBaseDir(kind, options) {
1909
- pathsResolverAssertKind(kind);
1908
+ function pathsResolverBaseDir2(kind, options) {
1909
+ pathsResolverAssertKind2(kind);
1910
1910
  const env = options.env ?? process.env;
1911
- const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
1911
+ const override = env[PATHS_RESOLVER_KIND_ENV2[kind]];
1912
1912
  if (typeof override === "string" && override.length > 0)
1913
1913
  return override;
1914
- const home = options.home ?? pathsResolverHomedir();
1914
+ const home = options.home ?? pathsResolverHomedir2();
1915
1915
  const platform = options.platform ?? process.platform;
1916
1916
  if (platform === "darwin") {
1917
1917
  switch (kind) {
1918
1918
  case "config":
1919
1919
  case "data":
1920
- return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
1920
+ return pathsResolverJoin2(home, "Library", "Application Support", "Hasna");
1921
1921
  case "cache":
1922
- return pathsResolverJoin(home, "Library", "Caches", "Hasna");
1922
+ return pathsResolverJoin2(home, "Library", "Caches", "Hasna");
1923
1923
  case "state":
1924
- return pathsResolverJoin(home, "Library", "Logs", "Hasna");
1924
+ return pathsResolverJoin2(home, "Library", "Logs", "Hasna");
1925
1925
  }
1926
1926
  }
1927
1927
  switch (kind) {
1928
1928
  case "config":
1929
- return pathsResolverJoin(home, ".config", "hasna");
1929
+ return pathsResolverJoin2(home, ".config", "hasna");
1930
1930
  case "data":
1931
- return pathsResolverJoin(home, ".local", "share", "hasna");
1931
+ return pathsResolverJoin2(home, ".local", "share", "hasna");
1932
1932
  case "state":
1933
- return pathsResolverJoin(home, ".local", "state", "hasna");
1933
+ return pathsResolverJoin2(home, ".local", "state", "hasna");
1934
1934
  case "cache":
1935
- return pathsResolverJoin(home, ".cache", "hasna");
1935
+ return pathsResolverJoin2(home, ".cache", "hasna");
1936
1936
  }
1937
1937
  }
1938
- function pathsResolverResolve(kind, options) {
1939
- pathsResolverAssertApp(options.app);
1940
- const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
1941
- return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
1938
+ function pathsResolverResolve2(kind, options) {
1939
+ pathsResolverAssertApp2(options.app);
1940
+ const appSegment = options.internal === true ? pathsResolverJoin2("internal", options.app) : options.app;
1941
+ return pathsResolverJoin2(pathsResolverBaseDir2(kind, options), appSegment);
1942
1942
  }
1943
- function dataDir(options) {
1944
- return pathsResolverResolve("data", options);
1943
+ function dataDir2(options) {
1944
+ return pathsResolverResolve2("data", options);
1945
1945
  }
1946
1946
  function getHomeDir(env = process.env) {
1947
1947
  return env.HOME || env.USERPROFILE || homedir2();
1948
1948
  }
1949
1949
  function getResolverDataRoot(env = process.env) {
1950
- return dataDir({ app: "hooks", home: getHomeDir(env), env });
1950
+ return dataDir2({ app: "hooks", home: getHomeDir(env), env });
1951
1951
  }
1952
1952
  function getLegacyDataRoot(env = process.env) {
1953
- return join2(getHomeDir(env), ".hasna", "hooks");
1953
+ return join3(getHomeDir(env), ".hasna", "hooks");
1954
1954
  }
1955
1955
  function adoptResolverDataRoot(resolved, env = process.env) {
1956
1956
  const dataOverride = env.HASNA_DATA_HOME;
1957
1957
  if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
1958
1958
  return true;
1959
- return existsSync2(join2(resolved, STORE_MARKER));
1959
+ return existsSync3(join3(resolved, STORE_MARKER));
1960
1960
  }
1961
1961
  function getExplicitDataDir(env = process.env) {
1962
1962
  const dir = env.HASNA_HOOKS_DATA_DIR ?? env.HOOKS_DATA_DIR;
@@ -1967,7 +1967,7 @@ function getExplicitDataDir(env = process.env) {
1967
1967
  function getExactDataRoot(env = process.env) {
1968
1968
  const dir = env.HASNA_HOOKS_HOME?.trim() || env.HOOKS_HOME?.trim();
1969
1969
  if (dir)
1970
- return resolve(dir);
1970
+ return resolve2(dir);
1971
1971
  return;
1972
1972
  }
1973
1973
  function getEffectiveDataRoot(env = process.env) {
@@ -1978,13 +1978,13 @@ function getEffectiveDataRoot(env = process.env) {
1978
1978
  if (exact)
1979
1979
  return exact;
1980
1980
  const resolved = getResolverDataRoot(env);
1981
- return adoptResolverDataRoot(resolved, env) ? resolve(resolved) : getLegacyDataRoot(env);
1981
+ return adoptResolverDataRoot(resolved, env) ? resolve2(resolved) : getLegacyDataRoot(env);
1982
1982
  }
1983
1983
  function getReportedDbPath(env = process.env) {
1984
1984
  const explicit = getExplicitDbPath(env);
1985
1985
  if (explicit)
1986
1986
  return explicit;
1987
- return join2(getEffectiveDataRoot(env), "hooks.db");
1987
+ return join3(getEffectiveDataRoot(env), "hooks.db");
1988
1988
  }
1989
1989
  function getExplicitDbPath(env = process.env) {
1990
1990
  const db = env.HASNA_HOOKS_DB_PATH ?? env.HOOKS_DB_PATH;
@@ -1992,15 +1992,15 @@ function getExplicitDbPath(env = process.env) {
1992
1992
  return db.trim();
1993
1993
  return;
1994
1994
  }
1995
- var PATHS_RESOLVER_KIND_ENV, PATHS_RESOLVER_APP_SLUG_RE, STORE_MARKER = "hooks.db";
1995
+ var PATHS_RESOLVER_KIND_ENV2, PATHS_RESOLVER_APP_SLUG_RE2, STORE_MARKER = "hooks.db";
1996
1996
  var init_app_home = __esm(() => {
1997
- PATHS_RESOLVER_KIND_ENV = {
1997
+ PATHS_RESOLVER_KIND_ENV2 = {
1998
1998
  config: "HASNA_CONFIG_HOME",
1999
1999
  data: "HASNA_DATA_HOME",
2000
2000
  state: "HASNA_STATE_HOME",
2001
2001
  cache: "HASNA_CACHE_HOME"
2002
2002
  };
2003
- PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2003
+ PATHS_RESOLVER_APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2004
2004
  });
2005
2005
 
2006
2006
  // src/lib/registry.ts
@@ -2571,7 +2571,7 @@ var init_registry = __esm(() => {
2571
2571
  ];
2572
2572
  });
2573
2573
 
2574
- // ../hooks0102-standalone-lock/node_modules/cli-spinners/spinners.json
2574
+ // ../../node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/spinners.json
2575
2575
  var require_spinners = __commonJS((exports, module) => {
2576
2576
  module.exports = {
2577
2577
  dots: {
@@ -4197,7 +4197,7 @@ var require_spinners = __commonJS((exports, module) => {
4197
4197
  };
4198
4198
  });
4199
4199
 
4200
- // ../hooks0102-standalone-lock/node_modules/cli-spinners/index.js
4200
+ // ../../node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/index.js
4201
4201
  var require_cli_spinners = __commonJS((exports, module) => {
4202
4202
  var spinners = Object.assign({}, require_spinners());
4203
4203
  var spinnersList = Object.keys(spinners);
@@ -4212,18 +4212,18 @@ var require_cli_spinners = __commonJS((exports, module) => {
4212
4212
  });
4213
4213
 
4214
4214
  // src/config.ts
4215
- import { join as join3 } from "path";
4215
+ import { join as join5 } from "path";
4216
4216
  function getHooksDataDir() {
4217
4217
  return getEffectiveDataRoot();
4218
4218
  }
4219
4219
  function getCustomHooksDir() {
4220
- return join3(getHooksDataDir(), "hooks");
4220
+ return join5(getHooksDataDir(), "hooks");
4221
4221
  }
4222
4222
  function getLockPath() {
4223
4223
  const explicit = process.env.HASNA_HOOKS_LOCK_PATH ?? process.env.HOOKS_LOCK_PATH;
4224
4224
  if (explicit)
4225
4225
  return explicit;
4226
- return join3(getHooksDataDir(), "hooks.lock");
4226
+ return join5(getHooksDataDir(), "hooks.lock");
4227
4227
  }
4228
4228
  var init_config = __esm(() => {
4229
4229
  init_app_home();
@@ -4253,8 +4253,8 @@ __export(exports_manifest, {
4253
4253
  ScriptContainmentError: () => ScriptContainmentError,
4254
4254
  HOOK_NAME_RE: () => HOOK_NAME_RE
4255
4255
  });
4256
- import { existsSync as existsSync3, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "fs";
4257
- import { basename, dirname, isAbsolute, join as join4, normalize, resolve as resolve2, sep } from "path";
4256
+ import { existsSync as existsSync5, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "fs";
4257
+ import { basename, dirname, isAbsolute, join as join6, normalize, resolve as resolve3, sep } from "path";
4258
4258
  import { z } from "zod";
4259
4259
  function parseManifest(json) {
4260
4260
  const parsed = JSON.parse(json);
@@ -4270,8 +4270,8 @@ function isWithin(child, parent) {
4270
4270
  return child === parent || child.startsWith(parent + sep);
4271
4271
  }
4272
4272
  function assertContainedLexical(target, root, raw) {
4273
- const lexical = resolve2(target);
4274
- const rootLexical = resolve2(root);
4273
+ const lexical = resolve3(target);
4274
+ const rootLexical = resolve3(root);
4275
4275
  if (!isWithin(lexical, rootLexical)) {
4276
4276
  throw new ScriptContainmentError(target, root, raw);
4277
4277
  }
@@ -4280,14 +4280,14 @@ function assertContainedLexical(target, root, raw) {
4280
4280
  function realpathNearest(path) {
4281
4281
  const tail = [];
4282
4282
  let cur = path;
4283
- while (!existsSync3(cur)) {
4283
+ while (!existsSync5(cur)) {
4284
4284
  const parent = dirname(cur);
4285
4285
  if (parent === cur)
4286
4286
  break;
4287
4287
  tail.unshift(basename(cur));
4288
4288
  cur = parent;
4289
4289
  }
4290
- return join4(realpathSync(cur), ...tail);
4290
+ return join6(realpathSync(cur), ...tail);
4291
4291
  }
4292
4292
  function assertContainedReal(root, target, raw) {
4293
4293
  const rootReal = realpathSync(root);
@@ -4320,25 +4320,25 @@ function resolveScript(manifest, manifestDir) {
4320
4320
  if (isInlineScript(manifest))
4321
4321
  return { path: scriptRelFor(manifest), content: manifest.script };
4322
4322
  const rel = scriptRelFor(manifest);
4323
- const resolved = assertContained(join4(manifestDir, rel), manifestDir, manifest.script);
4324
- if (!existsSync3(resolved)) {
4323
+ const resolved = assertContained(join6(manifestDir, rel), manifestDir, manifest.script);
4324
+ if (!existsSync5(resolved)) {
4325
4325
  throw new Error(`manifest script file not found: ${resolved}`);
4326
4326
  }
4327
4327
  return { path: rel, content: readFileSync(resolved, "utf-8") };
4328
4328
  }
4329
4329
  function customHookDir(name) {
4330
- return join4(getCustomHooksDir(), shortManifestName(name));
4330
+ return join6(getCustomHooksDir(), shortManifestName(name));
4331
4331
  }
4332
4332
  function readCustomManifest(name) {
4333
4333
  const dir = customHookDir(name);
4334
- const manifestPath = join4(dir, "manifest.json");
4335
- if (!existsSync3(manifestPath))
4334
+ const manifestPath = join6(dir, "manifest.json");
4335
+ if (!existsSync5(manifestPath))
4336
4336
  return;
4337
4337
  try {
4338
4338
  const manifest = parseManifest(readFileSync(manifestPath, "utf-8"));
4339
4339
  const script = resolveScript(manifest, dir);
4340
4340
  const scriptIsInline = isInlineScript(manifest);
4341
- return { manifest, scriptPath: join4(dir, script.path), scriptContent: script.content, scriptIsInline };
4341
+ return { manifest, scriptPath: join6(dir, script.path), scriptContent: script.content, scriptIsInline };
4342
4342
  } catch (err) {
4343
4343
  if (err instanceof ScriptContainmentError)
4344
4344
  throw err;
@@ -4347,7 +4347,7 @@ function readCustomManifest(name) {
4347
4347
  }
4348
4348
  function listCustomHooks() {
4349
4349
  const dir = getCustomHooksDir();
4350
- if (!existsSync3(dir))
4350
+ if (!existsSync5(dir))
4351
4351
  return [];
4352
4352
  const results = [];
4353
4353
  for (const entry of readdirSafe(dir)) {
@@ -4362,7 +4362,7 @@ function writeCustomHook(name, manifest, scriptContent, scriptRelPath) {
4362
4362
  if (isAbsolute(scriptRelPath)) {
4363
4363
  throw new ScriptContainmentError(scriptRelPath, dir);
4364
4364
  }
4365
- const scriptPath = scriptRelPath.includes("/") ? join4(dir, scriptRelPath) : join4(dir, scriptRelPath);
4365
+ const scriptPath = scriptRelPath.includes("/") ? join6(dir, scriptRelPath) : join6(dir, scriptRelPath);
4366
4366
  assertContainedLexical(scriptPath, dir, scriptRelPath);
4367
4367
  mkdirSync(dir, { recursive: true });
4368
4368
  assertContainedReal(dir, scriptPath, scriptRelPath);
@@ -4370,7 +4370,7 @@ function writeCustomHook(name, manifest, scriptContent, scriptRelPath) {
4370
4370
  if (scriptDir !== dir)
4371
4371
  mkdirSync(scriptDir, { recursive: true });
4372
4372
  writeFileSync(scriptPath, scriptContent, "utf-8");
4373
- writeFileSync(join4(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + `
4373
+ writeFileSync(join6(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + `
4374
4374
  `, "utf-8");
4375
4375
  return { dir, scriptPath };
4376
4376
  }
@@ -4414,14 +4414,14 @@ __export(exports_resolve, {
4414
4414
  resolveHook: () => resolveHook,
4415
4415
  resolveBundledHooksDir: () => resolveBundledHooksDir
4416
4416
  });
4417
- import { dirname as dirname2, join as join5 } from "path";
4418
- import { existsSync as existsSync4 } from "fs";
4417
+ import { dirname as dirname2, join as join7 } from "path";
4418
+ import { existsSync as existsSync6 } from "fs";
4419
4419
  import { fileURLToPath } from "url";
4420
4420
  function resolveBundledHooksDir(moduleDir = dirname2(fileURLToPath(import.meta.url))) {
4421
- const sourceLayout = join5(moduleDir, "..", "..", "hooks");
4422
- if (existsSync4(join5(sourceLayout, "hook-gitguard")))
4421
+ const sourceLayout = join7(moduleDir, "..", "..", "hooks");
4422
+ if (existsSync6(join7(sourceLayout, "hook-gitguard")))
4423
4423
  return sourceLayout;
4424
- return join5(moduleDir, "..", "hooks");
4424
+ return join7(moduleDir, "..", "hooks");
4425
4425
  }
4426
4426
  function resolveHookDir(name) {
4427
4427
  const custom = readCustomManifest(name);
@@ -4432,11 +4432,11 @@ function resolveHookDir(name) {
4432
4432
  return;
4433
4433
  const short = shortManifestName(name);
4434
4434
  const bundledBase = resolveBundledHooksDir();
4435
- const direct = join5(bundledBase, short);
4436
- if (existsSync4(direct))
4435
+ const direct = join7(bundledBase, short);
4436
+ if (existsSync6(direct))
4437
4437
  return direct;
4438
- const prefixed = join5(bundledBase, `hook-${short}`);
4439
- return existsSync4(prefixed) ? prefixed : undefined;
4438
+ const prefixed = join7(bundledBase, `hook-${short}`);
4439
+ return existsSync6(prefixed) ? prefixed : undefined;
4440
4440
  }
4441
4441
  function resolveScriptPath(name) {
4442
4442
  const custom = readCustomManifest(name);
@@ -4445,8 +4445,8 @@ function resolveScriptPath(name) {
4445
4445
  const dir = resolveHookDir(name);
4446
4446
  if (!dir)
4447
4447
  return;
4448
- const script = join5(dir, "src", "hook.ts");
4449
- return existsSync4(script) ? script : undefined;
4448
+ const script = join7(dir, "src", "hook.ts");
4449
+ return existsSync6(script) ? script : undefined;
4450
4450
  }
4451
4451
  function resolveHookMeta(name) {
4452
4452
  const custom = readCustomManifest(name);
@@ -4503,8 +4503,8 @@ var init_resolve = __esm(() => {
4503
4503
 
4504
4504
  // src/lib/native-safety.ts
4505
4505
  import { createHash } from "crypto";
4506
- import { closeSync, constants, existsSync as existsSync5, fstatSync, lstatSync, openSync, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "fs";
4507
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join6 } from "path";
4506
+ import { closeSync, constants, existsSync as existsSync7, fstatSync, lstatSync, openSync, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "fs";
4507
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join8 } from "path";
4508
4508
  import { homedir as homedir3 } from "os";
4509
4509
  function isNativeSafetyName(name) {
4510
4510
  return name === "trash-guard" || name === "workspace-repos-guard";
@@ -4519,6 +4519,9 @@ function buildNativeSafetyCommand(binding) {
4519
4519
  return prefix + [encoded, binding.runtime, binding.home, binding.path].map(quote).join(" ");
4520
4520
  }
4521
4521
  function nativeSafetyRegistration(command) {
4522
+ return nativeSafetyCommandBinding(command)?.name;
4523
+ }
4524
+ function nativeSafetyCommandBinding(command) {
4522
4525
  if (!command.startsWith(prefix))
4523
4526
  return;
4524
4527
  const encoded = command.slice(prefix.length).match(/^'([A-Za-z0-9_-]+)' /)?.[1];
@@ -4526,7 +4529,7 @@ function nativeSafetyRegistration(command) {
4526
4529
  return;
4527
4530
  try {
4528
4531
  const binding = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
4529
- return buildNativeSafetyCommand(binding) === command ? binding.name : undefined;
4532
+ return buildNativeSafetyCommand(binding) === command ? binding : undefined;
4530
4533
  } catch {
4531
4534
  return;
4532
4535
  }
@@ -4558,12 +4561,12 @@ function pinEligibleFile(file, maximum, executable = false) {
4558
4561
  function installedNativeSafetyCommand(name) {
4559
4562
  const home = realpathSync2(homedir3());
4560
4563
  const runtime = realpathSync2(process.execPath);
4561
- const candidates = [join6(import.meta.dir, "../../bin/native-safety-entry.js"), join6(import.meta.dir, "../bin/native-safety-entry.js"), join6(import.meta.dir, "native-safety-entry.js")];
4562
- const worker = candidates.find(existsSync5);
4564
+ const candidates = [join8(import.meta.dir, "../../bin/native-safety-entry.js"), join8(import.meta.dir, "../bin/native-safety-entry.js"), join8(import.meta.dir, "native-safety-entry.js")];
4565
+ const worker = candidates.find(existsSync7);
4563
4566
  if (!worker)
4564
4567
  throw new Error("Bundled native safety runner is missing; build or reinstall @hasna/hooks before installing its guards.");
4565
4568
  const canonicalWorker = realpathSync2(worker);
4566
- return buildNativeSafetyCommand({ name, runtime, runtimeSHA256: pinEligibleFile(runtime, 200000000, true), worker: canonicalWorker, workerSHA256: pinEligibleFile(canonicalWorker, 256000), home, path: `${dirname3(runtime)}:${join6(home, ".bun/bin")}:/usr/local/bin:/usr/bin:/bin` });
4569
+ return buildNativeSafetyCommand({ name, runtime, runtimeSHA256: pinEligibleFile(runtime, 200000000, true), worker: canonicalWorker, workerSHA256: pinEligibleFile(canonicalWorker, 256000), home, path: `${dirname3(runtime)}:${join8(home, ".bun/bin")}:/usr/local/bin:/usr/bin:/bin` });
4567
4570
  }
4568
4571
  var supervisorSource, quote = (value) => "'" + value.replaceAll("'", "'\\''") + "'", program2, shell, prefix;
4569
4572
  var init_native_safety = __esm(() => {
@@ -5010,8 +5013,8 @@ var init_migrations = __esm(() => {
5010
5013
  });
5011
5014
 
5012
5015
  // src/db/legacy-import.ts
5013
- import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
5014
- import { join as join7 } from "path";
5016
+ import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
5017
+ import { join as join9 } from "path";
5015
5018
  import { homedir as homedir4 } from "os";
5016
5019
  function ensureMetaTable(db) {
5017
5020
  db.exec(`
@@ -5091,20 +5094,20 @@ function runLegacyImport(db, homeDir = homedir4()) {
5091
5094
  if (isAlreadyDone(db))
5092
5095
  return;
5093
5096
  let total = 0;
5094
- const claudeProjectsDir = join7(homeDir, ".claude", "projects");
5095
- if (existsSync6(claudeProjectsDir)) {
5097
+ const claudeProjectsDir = join9(homeDir, ".claude", "projects");
5098
+ if (existsSync8(claudeProjectsDir)) {
5096
5099
  try {
5097
5100
  const projectDirs = readdirSync2(claudeProjectsDir);
5098
5101
  for (const dir of projectDirs) {
5099
- const projectDir = join7(claudeProjectsDir, dir);
5102
+ const projectDir = join9(claudeProjectsDir, dir);
5100
5103
  try {
5101
5104
  const files = readdirSync2(projectDir);
5102
5105
  for (const file of files) {
5103
5106
  if (file.match(/^session-log-\d{4}-\d{2}-\d{2}\.jsonl$/)) {
5104
- total += importJsonlFile(db, join7(projectDir, file));
5107
+ total += importJsonlFile(db, join9(projectDir, file));
5105
5108
  }
5106
5109
  if (file === "errors.log") {
5107
- total += importErrorsLog(db, join7(projectDir, file));
5110
+ total += importErrorsLog(db, join9(projectDir, file));
5108
5111
  }
5109
5112
  }
5110
5113
  } catch {}
@@ -5151,8 +5154,8 @@ __export(exports_db, {
5151
5154
  allowLocalStore: () => allowLocalStore
5152
5155
  });
5153
5156
  import { Database } from "bun:sqlite";
5154
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, cpSync } from "fs";
5155
- import { join as join8 } from "path";
5157
+ import { existsSync as existsSync9, mkdirSync as mkdirSync2, cpSync } from "fs";
5158
+ import { join as join10 } from "path";
5156
5159
  function refuseLocalStore(message) {
5157
5160
  localStoreRefusal = message;
5158
5161
  }
@@ -5167,8 +5170,8 @@ function localStoreRefusalMessage() {
5167
5170
  }
5168
5171
  function resolveDataDir() {
5169
5172
  const effective = getEffectiveDataRoot();
5170
- const oldDir = join8(getHomeDir(), ".hooks");
5171
- if (!existsSync7(effective) && existsSync7(oldDir)) {
5173
+ const oldDir = join10(getHomeDir(), ".hooks");
5174
+ if (!existsSync9(effective) && existsSync9(oldDir)) {
5172
5175
  mkdirSync2(effective, { recursive: true });
5173
5176
  cpSync(oldDir, effective, { recursive: true });
5174
5177
  }
@@ -5178,12 +5181,12 @@ function getDbPath() {
5178
5181
  const explicitDb = process.env.HASNA_HOOKS_DB_PATH ?? process.env.HOOKS_DB_PATH;
5179
5182
  if (explicitDb)
5180
5183
  return explicitDb;
5181
- const dataDir2 = resolveDataDir();
5182
- return join8(dataDir2, "hooks.db");
5184
+ const dataDir3 = resolveDataDir();
5185
+ return join10(dataDir3, "hooks.db");
5183
5186
  }
5184
5187
  function ensureDir(dbPath) {
5185
5188
  const dir = dbPath.substring(0, dbPath.lastIndexOf("/"));
5186
- if (dir && !existsSync7(dir)) {
5189
+ if (dir && !existsSync9(dir)) {
5187
5190
  mkdirSync2(dir, { recursive: true });
5188
5191
  }
5189
5192
  }
@@ -5193,7 +5196,7 @@ function getDb() {
5193
5196
  if (instance)
5194
5197
  return instance;
5195
5198
  const dbPath = getDbPath();
5196
- const isNew = dbPath === ":memory:" || !existsSync7(dbPath);
5199
+ const isNew = dbPath === ":memory:" || !existsSync9(dbPath);
5197
5200
  ensureDir(dbPath);
5198
5201
  instance = new Database(dbPath);
5199
5202
  instance.exec("PRAGMA busy_timeout=5000");
@@ -5256,7 +5259,7 @@ __export(exports_store, {
5256
5259
  LockFileError: () => LockFileError
5257
5260
  });
5258
5261
  import { createHash as createHash2 } from "crypto";
5259
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync } from "fs";
5262
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync } from "fs";
5260
5263
  import { readFile as readFile2 } from "fs/promises";
5261
5264
  import { randomBytes } from "crypto";
5262
5265
  function sha256Of(input) {
@@ -5321,7 +5324,7 @@ function assertLockShape(parsed, path) {
5321
5324
  }
5322
5325
  function readLock() {
5323
5326
  const path = getLockPath();
5324
- if (!existsSync8(path))
5327
+ if (!existsSync10(path))
5325
5328
  return { hooks: {} };
5326
5329
  let raw;
5327
5330
  try {
@@ -5455,7 +5458,7 @@ var init_store = __esm(() => {
5455
5458
  });
5456
5459
 
5457
5460
  // src/lib/codex-settings.ts
5458
- import { closeSync as closeSync2, existsSync as existsSync9, lstatSync as lstatSync2, mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync5, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
5461
+ import { closeSync as closeSync2, existsSync as existsSync11, lstatSync as lstatSync2, mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync5, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
5459
5462
  import { dirname as dirname4 } from "path";
5460
5463
  import { randomUUID as randomUUID3 } from "crypto";
5461
5464
  function current(path) {
@@ -5515,7 +5518,7 @@ function writeCodexSettings(path, settings) {
5515
5518
  renameSync2(temp, path);
5516
5519
  snapshots.set(settings, { path, raw: next });
5517
5520
  } finally {
5518
- if (existsSync9(temp))
5521
+ if (existsSync11(temp))
5519
5522
  unlinkSync(temp);
5520
5523
  closeSync2(fd);
5521
5524
  unlinkSync(lock);
@@ -5526,12 +5529,12 @@ var init_codex_settings = __esm(() => {
5526
5529
  snapshots = new WeakMap;
5527
5530
  });
5528
5531
 
5529
- // ../hooks0102-standalone-lock/node_modules/@hasna/skills/dist/index.js
5530
- import { existsSync as existsSync10 } from "fs";
5532
+ // ../../node_modules/.bun/@hasna+skills@0.9.14+a00d3064559565bb/node_modules/@hasna/skills/dist/index.js
5533
+ import { existsSync as existsSync12 } from "fs";
5531
5534
  import { homedir as homedir5 } from "os";
5532
- import { join as join9, resolve as resolve3 } from "path";
5533
- import { homedir as pathsResolverHomedir2 } from "os";
5534
- import { join as pathsResolverJoin2 } from "path";
5535
+ import { join as join11, resolve as resolve4 } from "path";
5536
+ import { homedir as pathsResolverHomedir3 } from "os";
5537
+ import { join as pathsResolverJoin3 } from "path";
5535
5538
  import { createHash as createHash3 } from "crypto";
5536
5539
  import { existsSync as existsSync52, readdirSync as readdirSync3, readFileSync as readFileSync42, statSync as statSync3 } from "fs";
5537
5540
  import { join as join52, sep as sep2 } from "path";
@@ -5543,7 +5546,7 @@ import { dirname as dirname32, isAbsolute as isAbsolute3, join as join72, resolv
5543
5546
  import { lstatSync as lstatSync3, readFileSync as readFileSync6, opendirSync } from "fs";
5544
5547
  import { createHash as createHash22 } from "crypto";
5545
5548
  import { lstatSync as lstatSync4, opendirSync as opendirSync2 } from "fs";
5546
- import { dirname as dirname42, isAbsolute as isAbsolute4, join as join82, resolve as resolve4 } from "path";
5549
+ import { dirname as dirname42, isAbsolute as isAbsolute4, join as join82, resolve as resolve42 } from "path";
5547
5550
  import { createHash as createHash32 } from "crypto";
5548
5551
  import { closeSync as closeSync3, constants as constants2, fstatSync as fstatSync2, lstatSync as lstatSync5, openSync as openSync3, readSync } from "fs";
5549
5552
  import { dirname as dirname5, isAbsolute as isAbsolute5, resolve as resolve5 } from "path";
@@ -5553,7 +5556,7 @@ import { dirname as dirname6, isAbsolute as isAbsolute6, join as join92, parse,
5553
5556
  import { closeSync as closeSync12, constants as constants9, fstatSync as fstatSync12, lstatSync as lstatSync17, openSync as openSync12, opendirSync as opendirSync5, readSync as readSync8 } from "fs";
5554
5557
  import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute12, join as join25, resolve as resolve12 } from "path";
5555
5558
  import { isAbsolute as isAbsolute11, join as join23, resolve as resolve11 } from "path";
5556
- import { createRequire } from "module";
5559
+ import { createRequire as createRequire2 } from "module";
5557
5560
  import { createHash as createHash10, randomUUID as randomUUID22 } from "crypto";
5558
5561
  import { existsSync as existsSync82, lstatSync as lstatSync14, statSync as statSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync11, readdirSync as readdirSync7, opendirSync as opendirSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync3, renameSync as renameSync22, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync10, closeSync as closeSync10, fsyncSync as fsyncSync2, fstatSync as fstatSync10, readSync as readSync6, constants as constants7, linkSync } from "fs";
5559
5562
  import { dirname as dirname10, join as join16, resolve as resolve9, relative as relative4, isAbsolute as isAbsolute9, sep as sep4 } from "path";
@@ -5581,11 +5584,11 @@ import { createHash as createHash20 } from "crypto";
5581
5584
  function __exportSetter2(name, newValue) {
5582
5585
  this[name] = __returnValue2.bind(null, newValue);
5583
5586
  }
5584
- function pathsResolverAssertApp2(app) {
5587
+ function pathsResolverAssertApp3(app) {
5585
5588
  if (typeof app !== "string" || app.length === 0) {
5586
5589
  throw new TypeError("paths: app must be a non-empty string");
5587
5590
  }
5588
- if (!PATHS_RESOLVER_APP_SLUG_RE2.test(app)) {
5591
+ if (!PATHS_RESOLVER_APP_SLUG_RE3.test(app)) {
5589
5592
  throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
5590
5593
  }
5591
5594
  }
@@ -5594,35 +5597,35 @@ function pathsResolverDataBaseDir(options) {
5594
5597
  const override = env[PATHS_RESOLVER_DATA_ENV];
5595
5598
  if (typeof override === "string" && override.length > 0)
5596
5599
  return override;
5597
- const home = options.home ?? pathsResolverHomedir2();
5600
+ const home = options.home ?? pathsResolverHomedir3();
5598
5601
  const platform = options.platform ?? process.platform;
5599
- return platform === "darwin" ? pathsResolverJoin2(home, "Library", "Application Support", "Hasna") : pathsResolverJoin2(home, ".local", "share", "hasna");
5602
+ return platform === "darwin" ? pathsResolverJoin3(home, "Library", "Application Support", "Hasna") : pathsResolverJoin3(home, ".local", "share", "hasna");
5600
5603
  }
5601
- function dataDir2(options) {
5602
- pathsResolverAssertApp2(options.app);
5603
- const appSegment = options.internal === true ? pathsResolverJoin2("internal", options.app) : options.app;
5604
- return pathsResolverJoin2(pathsResolverDataBaseDir(options), appSegment);
5604
+ function dataDir3(options) {
5605
+ pathsResolverAssertApp3(options.app);
5606
+ const appSegment = options.internal === true ? pathsResolverJoin3("internal", options.app) : options.app;
5607
+ return pathsResolverJoin3(pathsResolverDataBaseDir(options), appSegment);
5605
5608
  }
5606
- function effectiveHome() {
5609
+ function effectiveHome2() {
5607
5610
  return process.env["HOME"] || process.env["USERPROFILE"] || homedir5() || "/tmp";
5608
5611
  }
5609
5612
  function legacyDataRoot() {
5610
- return join9(effectiveHome(), ".hasna", "skills");
5613
+ return join11(effectiveHome2(), ".hasna", "skills");
5611
5614
  }
5612
- function resolverDataRoot(home = effectiveHome(), env) {
5613
- return dataDir2({ app: "skills", home, env });
5615
+ function resolverDataRoot(home = effectiveHome2(), env) {
5616
+ return dataDir3({ app: "skills", home, env });
5614
5617
  }
5615
5618
  function adoptResolverDataRoot2(resolved, env = process.env) {
5616
5619
  const dataOverride = env.HASNA_DATA_HOME;
5617
5620
  if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
5618
5621
  return true;
5619
- return existsSync10(join9(resolved, DEFAULT_SQLITE_FILENAME)) || existsSync10(join9(resolved, GLOBAL_CONFIG_FILENAME));
5622
+ return existsSync12(join11(resolved, DEFAULT_SQLITE_FILENAME)) || existsSync12(join11(resolved, GLOBAL_CONFIG_FILENAME));
5620
5623
  }
5621
5624
  function exactDataRoot() {
5622
5625
  for (const key of [DATA_DIR_ENV, HASNA_SKILLS_HOME_ENV, SKILLS_HOME_ENV]) {
5623
5626
  const dir = process.env[key]?.trim();
5624
5627
  if (dir)
5625
- return resolve3(dir);
5628
+ return resolve4(dir);
5626
5629
  }
5627
5630
  return;
5628
5631
  }
@@ -5631,7 +5634,7 @@ function getDataRoot() {
5631
5634
  if (exact)
5632
5635
  return exact;
5633
5636
  const resolved = resolverDataRoot();
5634
- return adoptResolverDataRoot2(resolved) ? resolve3(resolved) : resolve3(legacyDataRoot());
5637
+ return adoptResolverDataRoot2(resolved) ? resolve4(resolved) : resolve4(legacyDataRoot());
5635
5638
  }
5636
5639
  function getDataDirReadOnly() {
5637
5640
  return getDataRoot();
@@ -6253,7 +6256,7 @@ function need(value, message) {
6253
6256
  throw new Error(message);
6254
6257
  }
6255
6258
  function safe(path) {
6256
- need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute4(path) && resolve4(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
6259
+ need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute4(path) && resolve42(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
6257
6260
  for (let cursor = path;; cursor = dirname42(cursor)) {
6258
6261
  need(!lstatSync4(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
6259
6262
  if (dirname42(cursor) === cursor)
@@ -15487,7 +15490,7 @@ var __defProp2, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {}
15487
15490
  configurable: true,
15488
15491
  set: __exportSetter2.bind(all, name)
15489
15492
  });
15490
- }, __require2, require_identity, require_visit, require_directives, require_anchors, require_applyReviver, require_toJS, require_Node, require_Alias, require_Scalar, require_createNode, require_Collection, require_stringifyComment, require_foldFlowLines, require_stringifyString, require_stringify, require_stringifyPair, require_log, require_merge, require_addPairToJSMap, require_Pair, require_stringifyCollection, require_YAMLMap, require_map, require_YAMLSeq, require_seq, require_string, require_null, require_bool, require_stringifyNumber, require_float, require_int, require_schema, require_schema2, require_binary, require_pairs, require_omap, require_bool2, require_float2, require_int2, require_set, require_timestamp, require_schema3, require_tags, require_Schema, require_stringifyDocument, require_Document, require_errors, require_resolve_props, require_util_contains_newline, require_util_flow_indent_check, require_util_map_includes, require_resolve_block_map, require_resolve_block_seq, require_resolve_end, require_resolve_flow_collection, require_compose_collection, require_resolve_block_scalar, require_resolve_flow_scalar, require_compose_scalar, require_util_empty_scalar_position, require_compose_node, require_compose_doc, require_composer, require_cst_scalar, require_cst_stringify, require_cst_visit, require_cst, require_lexer, require_line_counter, require_parser, require_public_api, RETIRED_CONFIG_KEY_REASONS, PATHS_RESOLVER_DATA_ENV = "HASNA_DATA_HOME", PATHS_RESOLVER_APP_SLUG_RE2, DATA_DIR_ENV = "HASNA_SKILLS_DIR", HASNA_SKILLS_HOME_ENV = "HASNA_SKILLS_HOME", SKILLS_HOME_ENV = "SKILLS_HOME", DEFAULT_SQLITE_FILENAME = "server.db", GLOBAL_CONFIG_FILENAME = "config.json", SKILLS, HOSTED_RUNTIMES, HOSTED_SOURCES, HOSTED_METADATA_SET_EMPTY_ERROR, SLUG = "[^,{}/]+", BRACE_SOURCE_EXCLUSION, SINGLE_SOURCE_EXCLUSION, RESERVED_SKILL_ENTRIES, KNOWN_TOP_LEVEL_ENTRIES, VALID_PROVENANCE_SOURCES, CONTENT_HASH_ALGORITHM = "sha256", HASH_EXCLUDE_DIRS, HASH_COVERAGE, CONTENT_HASH_LIMITS, typedArrayPrototype, byteLengthOf, bufferOf, PORTABLE_SKILL_STANDARD = "hasna.skill.v1", SKILL_RUNTIMES, SKILL_SANDBOX_MODES, SKILL_SYSTEM_DEPS_ALLOWLIST, SEMVER_PATTERN2 = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", CONTENT_HASH_PATTERN = "^[a-f0-9]{64}$", ENV_REFERENCE_PATTERN = "^[A-Z0-9_]+$", MAX_RUNTIME_TIMEOUT_SECONDS = 900, ANY_SEGMENT_COPY_EXCLUDES, FIRST_SEGMENT_COPY_EXCLUDES, NATIVE_SKILL_ROOTS, INTEGRATION_AGENTS, AGENT_ADAPTERS, AGENT_POLICY_LIMITS, composer, Document, Schema, errors, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync, HERMES_OPT_OUT = ".no-bundled-skills", package_default, MAX_PACKAGE_BYTES, MAX_CREDENTIAL_FILE_BYTES, INSPECT_CUSTOM, CREDENTIAL_SEAL, AMBIENT_ENVIRONMENT, requireSecretsSdk, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, MAX_REMOTE_FILE_BYTES, MAX_PROFILE_SELECTIONS = 4096, MAX_PROFILE_DOCUMENT_BYTES, MAX_SKILL_SESSION_ID_CHARS = 256, PROFILE_SESSION_ENVELOPE_BYTES, MAX_RESOLVED_PROFILE_BYTES, BLOCK = 512, ANY_SEGMENT_EXCLUDES, ROOT_EXCLUDES, TOOL_SIDECAR_FILENAMES, CREDENTIAL_FILENAMES, ENV_TEMPLATE_NAMES, NON_DOTENV_EXTENSIONS, SKILL_BUNDLE_INSPECTION_LIMITS, SkillBundleInspectionError, SKILL_VERSION_PATTERN, SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, CLI_BRIDGE_NAME = "skills-cli", CLI_BRIDGE_VERSION = 1, markdown = `---
15493
+ }, __require2, require_identity, require_visit, require_directives, require_anchors, require_applyReviver, require_toJS, require_Node, require_Alias, require_Scalar, require_createNode, require_Collection, require_stringifyComment, require_foldFlowLines, require_stringifyString, require_stringify, require_stringifyPair, require_log, require_merge, require_addPairToJSMap, require_Pair, require_stringifyCollection, require_YAMLMap, require_map, require_YAMLSeq, require_seq, require_string, require_null, require_bool, require_stringifyNumber, require_float, require_int, require_schema, require_schema2, require_binary, require_pairs, require_omap, require_bool2, require_float2, require_int2, require_set, require_timestamp, require_schema3, require_tags, require_Schema, require_stringifyDocument, require_Document, require_errors, require_resolve_props, require_util_contains_newline, require_util_flow_indent_check, require_util_map_includes, require_resolve_block_map, require_resolve_block_seq, require_resolve_end, require_resolve_flow_collection, require_compose_collection, require_resolve_block_scalar, require_resolve_flow_scalar, require_compose_scalar, require_util_empty_scalar_position, require_compose_node, require_compose_doc, require_composer, require_cst_scalar, require_cst_stringify, require_cst_visit, require_cst, require_lexer, require_line_counter, require_parser, require_public_api, RETIRED_CONFIG_KEY_REASONS, PATHS_RESOLVER_DATA_ENV = "HASNA_DATA_HOME", PATHS_RESOLVER_APP_SLUG_RE3, DATA_DIR_ENV = "HASNA_SKILLS_DIR", HASNA_SKILLS_HOME_ENV = "HASNA_SKILLS_HOME", SKILLS_HOME_ENV = "SKILLS_HOME", DEFAULT_SQLITE_FILENAME = "server.db", GLOBAL_CONFIG_FILENAME = "config.json", SKILLS, HOSTED_RUNTIMES, HOSTED_SOURCES, HOSTED_METADATA_SET_EMPTY_ERROR, SLUG = "[^,{}/]+", BRACE_SOURCE_EXCLUSION, SINGLE_SOURCE_EXCLUSION, RESERVED_SKILL_ENTRIES, KNOWN_TOP_LEVEL_ENTRIES, VALID_PROVENANCE_SOURCES, CONTENT_HASH_ALGORITHM = "sha256", HASH_EXCLUDE_DIRS, HASH_COVERAGE, CONTENT_HASH_LIMITS, typedArrayPrototype, byteLengthOf, bufferOf, PORTABLE_SKILL_STANDARD = "hasna.skill.v1", SKILL_RUNTIMES, SKILL_SANDBOX_MODES, SKILL_SYSTEM_DEPS_ALLOWLIST, SEMVER_PATTERN2 = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", CONTENT_HASH_PATTERN = "^[a-f0-9]{64}$", ENV_REFERENCE_PATTERN = "^[A-Z0-9_]+$", MAX_RUNTIME_TIMEOUT_SECONDS = 900, ANY_SEGMENT_COPY_EXCLUDES, FIRST_SEGMENT_COPY_EXCLUDES, NATIVE_SKILL_ROOTS, INTEGRATION_AGENTS, AGENT_ADAPTERS, AGENT_POLICY_LIMITS, composer, Document, Schema, errors, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync, HERMES_OPT_OUT = ".no-bundled-skills", package_default, MAX_PACKAGE_BYTES2, MAX_CREDENTIAL_FILE_BYTES2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, AMBIENT_ENVIRONMENT2, requireSecretsSdk2, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, MAX_REMOTE_FILE_BYTES, MAX_PROFILE_SELECTIONS = 4096, MAX_PROFILE_DOCUMENT_BYTES, MAX_SKILL_SESSION_ID_CHARS = 256, PROFILE_SESSION_ENVELOPE_BYTES, MAX_RESOLVED_PROFILE_BYTES, BLOCK = 512, ANY_SEGMENT_EXCLUDES, ROOT_EXCLUDES, TOOL_SIDECAR_FILENAMES, CREDENTIAL_FILENAMES, ENV_TEMPLATE_NAMES, NON_DOTENV_EXTENSIONS, SKILL_BUNDLE_INSPECTION_LIMITS, SkillBundleInspectionError, SKILL_VERSION_PATTERN, SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, CLI_BRIDGE_NAME = "skills-cli", CLI_BRIDGE_VERSION = 1, markdown = `---
15491
15494
  name: skills-cli
15492
15495
  description: Discover, load, author, and run versioned skills through the Skills CLI when a task needs reusable instructions or an executable skill.
15493
15496
  ---
@@ -29705,7 +29708,7 @@ ${end.comment}` : end.comment;
29705
29708
  mode: "Deployment modes were removed: a Skills client either resolves a credential " + "or it does not, and that is the whole of it.",
29706
29709
  apiUrl: "The service address is no longer kept in this app's config file: it is read from " + "HASNA_SKILLS_API_URL, then the macOS Keychain item hasna.credentials.skills.api-url, " + "then ~/.hasna/skills/config/credentials, then the fleet gateway."
29707
29710
  };
29708
- PATHS_RESOLVER_APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
29711
+ PATHS_RESOLVER_APP_SLUG_RE3 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
29709
29712
  SKILLS = [];
29710
29713
  HOSTED_RUNTIMES = new Set(["hosted"]);
29711
29714
  HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
@@ -30032,14 +30035,14 @@ ${end.comment}` : end.comment;
30032
30035
  url: "https://github.com/hasna/apps/issues"
30033
30036
  }
30034
30037
  };
30035
- MAX_PACKAGE_BYTES = 1024 * 1024;
30036
- MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
30037
- INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
30038
- CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
30039
- AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
30040
- requireSecretsSdk = createRequire(import.meta.url);
30041
- IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
30042
- AUTHORITY_OVERRIDE_HEADERS = new Set([
30038
+ MAX_PACKAGE_BYTES2 = 1024 * 1024;
30039
+ MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
30040
+ INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
30041
+ CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
30042
+ AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
30043
+ requireSecretsSdk2 = createRequire2(import.meta.url);
30044
+ IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
30045
+ AUTHORITY_OVERRIDE_HEADERS2 = new Set([
30043
30046
  "host",
30044
30047
  ":authority",
30045
30048
  "forwarded",
@@ -36495,8 +36498,8 @@ __export(exports_installer, {
36495
36498
  detectRewriteConflict: () => detectRewriteConflict,
36496
36499
  buildCodewithTomlFragment: () => buildCodewithTomlFragment
36497
36500
  });
36498
- import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync7, readdirSync as readdirSync4, realpathSync as realpathSync5, rmdirSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "fs";
36499
- import { join as join10, dirname as dirname7, basename as basename3, resolve as resolve7 } from "path";
36501
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync7, readdirSync as readdirSync4, realpathSync as realpathSync5, rmdirSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "fs";
36502
+ import { join as join12, dirname as dirname7, basename as basename3, resolve as resolve7 } from "path";
36500
36503
  import { homedir as homedir6 } from "os";
36501
36504
  import { fileURLToPath as fileURLToPath2 } from "url";
36502
36505
  function normalizeHookName(name) {
@@ -36544,28 +36547,28 @@ function getSettingsPath(scope = "global", target = "claude", codewithConfigPath
36544
36547
  return globalOverride;
36545
36548
  const dir = getTargetSettingsDir(target);
36546
36549
  if (target === "codex")
36547
- return join10(scope === "project" ? process.cwd() : homedir6(), dir, "hooks.json");
36550
+ return join12(scope === "project" ? process.cwd() : homedir6(), dir, "hooks.json");
36548
36551
  if (scope === "project") {
36549
- return target === "codewith" ? join10(process.cwd(), dir, "config.toml") : join10(process.cwd(), dir, "settings.json");
36552
+ return target === "codewith" ? join12(process.cwd(), dir, "config.toml") : join12(process.cwd(), dir, "settings.json");
36550
36553
  }
36551
- return target === "codewith" ? join10(homedir6(), dir, "config.toml") : join10(homedir6(), dir, "settings.json");
36554
+ return target === "codewith" ? join12(homedir6(), dir, "config.toml") : join12(homedir6(), dir, "settings.json");
36552
36555
  }
36553
36556
  function getHookPath(name) {
36554
36557
  const shortName = shortHookName(name);
36555
36558
  const resolved = resolveHookDir(shortName);
36556
36559
  if (resolved)
36557
36560
  return resolved;
36558
- return join10(HOOKS_DIR, normalizeHookName(shortName));
36561
+ return join12(HOOKS_DIR, normalizeHookName(shortName));
36559
36562
  }
36560
36563
  function hookExists(name) {
36561
- return existsSync11(getHookPath(name));
36564
+ return existsSync13(getHookPath(name));
36562
36565
  }
36563
36566
  function readSettings2(scope = "global", target = "claude") {
36564
36567
  const path = getSettingsPath(scope, target);
36565
36568
  if (target === "codex")
36566
36569
  return readCodexSettings(path);
36567
36570
  try {
36568
- if (existsSync11(path)) {
36571
+ if (existsSync13(path)) {
36569
36572
  const text3 = readFileSync7(path, "utf-8"), value = JSON.parse(text3);
36570
36573
  settingsPreimages.set(value, { path, text: text3 });
36571
36574
  return value;
@@ -36574,24 +36577,24 @@ function readSettings2(scope = "global", target = "claude") {
36574
36577
  console.warn(`[hooks] Failed to read settings at ${path}: ${error61 instanceof Error ? error61.message : String(error61)}`);
36575
36578
  }
36576
36579
  const empty = {};
36577
- if (!existsSync11(path))
36580
+ if (!existsSync13(path))
36578
36581
  settingsPreimages.set(empty, { path, text: null });
36579
36582
  return empty;
36580
36583
  }
36581
36584
  function settingsIdentity(path) {
36582
- if (existsSync11(path))
36585
+ if (existsSync13(path))
36583
36586
  return realpathSync5(path);
36584
- return existsSync11(dirname7(path)) ? join10(realpathSync5(dirname7(path)), basename3(path)) : resolve7(path);
36587
+ return existsSync13(dirname7(path)) ? join12(realpathSync5(dirname7(path)), basename3(path)) : resolve7(path);
36585
36588
  }
36586
36589
  function writeSettings(settings, scope = "global", target = "claude") {
36587
36590
  const path = getSettingsPath(scope, target);
36588
36591
  if (target === "codex")
36589
36592
  return writeCodexSettings(path, settings);
36590
- if (target === "claude" && settingsIdentity(path) === settingsIdentity(join10(homedir6(), ".claude/settings.json"))) {
36593
+ if (target === "claude" && settingsIdentity(path) === settingsIdentity(join12(homedir6(), ".claude/settings.json"))) {
36591
36594
  const before = settingsPreimages.get(settings);
36592
36595
  if (!before || before.path !== path)
36593
36596
  throw new Error("Claude settings require a valid captured preimage before installation.");
36594
- const current2 = existsSync11(path) ? readFileSync7(path, "utf8") : null;
36597
+ const current2 = existsSync13(path) ? readFileSync7(path, "utf8") : null;
36595
36598
  if (current2 !== before.text)
36596
36599
  throw new Error("Claude settings changed during installation; no settings were written.");
36597
36600
  if (coordinateClaudeSettings(before.text, JSON.stringify(settings, null, 2) + `
@@ -36599,7 +36602,7 @@ function writeSettings(settings, scope = "global", target = "claude") {
36599
36602
  return;
36600
36603
  }
36601
36604
  const dir = dirname7(path);
36602
- if (!existsSync11(dir)) {
36605
+ if (!existsSync13(dir)) {
36603
36606
  mkdirSync6(dir, { recursive: true });
36604
36607
  }
36605
36608
  writeFileSync5(path, JSON.stringify(settings, null, 2) + `
@@ -36698,7 +36701,7 @@ function buildCodewithTomlFragment(name, profile, mementos) {
36698
36701
  function readCodewithConfig(scope, configPath) {
36699
36702
  const path = getSettingsPath(scope, "codewith", configPath);
36700
36703
  try {
36701
- return existsSync11(path) ? readFileSync7(path, "utf-8") : "";
36704
+ return existsSync13(path) ? readFileSync7(path, "utf-8") : "";
36702
36705
  } catch {
36703
36706
  return "";
36704
36707
  }
@@ -36706,9 +36709,9 @@ function readCodewithConfig(scope, configPath) {
36706
36709
  function appendCodewithFragment(fragment, scope, configPath) {
36707
36710
  const path = getSettingsPath(scope, "codewith", configPath);
36708
36711
  const dir = dirname7(path);
36709
- if (!existsSync11(dir))
36712
+ if (!existsSync13(dir))
36710
36713
  mkdirSync6(dir, { recursive: true });
36711
- const existing = existsSync11(path) ? readFileSync7(path, "utf-8") : "";
36714
+ const existing = existsSync13(path) ? readFileSync7(path, "utf-8") : "";
36712
36715
  const sep3 = existing.trim() ? `
36713
36716
 
36714
36717
  ` : "";
@@ -37046,7 +37049,7 @@ function removeHookForTarget(name, scope, target) {
37046
37049
  }
37047
37050
  function readSettingsAt(path) {
37048
37051
  try {
37049
- if (!existsSync11(path))
37052
+ if (!existsSync13(path))
37050
37053
  return;
37051
37054
  const raw = readFileSync7(path, "utf-8");
37052
37055
  const settings = JSON.parse(raw);
@@ -37172,7 +37175,7 @@ function codewithHasHookEntryInText(configText, name) {
37172
37175
  }
37173
37176
  function codewithHasHookEntry(name, scope = "global") {
37174
37177
  const path = getSettingsPath(scope, "codewith");
37175
- if (!existsSync11(path))
37178
+ if (!existsSync13(path))
37176
37179
  return false;
37177
37180
  try {
37178
37181
  return codewithHasHookEntryInText(readFileSync7(path, "utf-8"), name);
@@ -37184,12 +37187,12 @@ function removeStoreDirFailClosed(dir) {
37184
37187
  const entries = readdirSync4(dir, { withFileTypes: true });
37185
37188
  for (const entry of entries) {
37186
37189
  if (entry.isDirectory()) {
37187
- removeStoreDirFailClosed(join10(dir, entry.name));
37190
+ removeStoreDirFailClosed(join12(dir, entry.name));
37188
37191
  }
37189
37192
  }
37190
37193
  for (const entry of entries) {
37191
37194
  if (!entry.isDirectory()) {
37192
- unlinkSync2(join10(dir, entry.name));
37195
+ unlinkSync2(join12(dir, entry.name));
37193
37196
  }
37194
37197
  }
37195
37198
  rmdirSync(dir);
@@ -37220,7 +37223,7 @@ function uninstallHook(name, scope = "global", target = "claude") {
37220
37223
  const registrationsRemaining = [];
37221
37224
  if (target === "codewith" || target === "all") {
37222
37225
  const codewithPath = getSettingsPath(scope, "codewith");
37223
- if (existsSync11(codewithPath)) {
37226
+ if (existsSync13(codewithPath)) {
37224
37227
  const before = readFileSync7(codewithPath, "utf-8");
37225
37228
  const after = removeCodewithHookEntry(before, shortName);
37226
37229
  if (after.removed) {
@@ -37271,7 +37274,7 @@ var init_installer = __esm(() => {
37271
37274
  init_native_safety();
37272
37275
  init_claude_skills_coordination();
37273
37276
  __dirname2 = dirname7(fileURLToPath2(import.meta.url));
37274
- HOOKS_DIR = existsSync11(join10(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join10(__dirname2, "..", "..", "hooks") : join10(__dirname2, "..", "hooks");
37277
+ HOOKS_DIR = existsSync13(join12(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join12(__dirname2, "..", "..", "hooks") : join12(__dirname2, "..", "hooks");
37275
37278
  EVENT_MAP = {
37276
37279
  claude: {
37277
37280
  PreToolUse: "PreToolUse",
@@ -37385,25 +37388,25 @@ var init_redact = __esm(() => {
37385
37388
  });
37386
37389
 
37387
37390
  // src/lib/profiles.ts
37388
- import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync8, readdirSync as readdirSync8, rmSync, cpSync as cpSync2 } from "fs";
37389
- import { join as join11 } from "path";
37391
+ import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10, readdirSync as readdirSync8, rmSync, cpSync as cpSync2 } from "fs";
37392
+ import { join as join19 } from "path";
37390
37393
  function getProfilesDir() {
37391
- const newDir = join11(getEffectiveDataRoot(), "profiles");
37392
- const oldDir = join11(getHomeDir(), ".hooks", "profiles");
37393
- if (!existsSync12(newDir) && existsSync12(oldDir)) {
37394
- mkdirSync9(newDir, { recursive: true });
37394
+ const newDir = join19(getEffectiveDataRoot(), "profiles");
37395
+ const oldDir = join19(getHomeDir(), ".hooks", "profiles");
37396
+ if (!existsSync15(newDir) && existsSync15(oldDir)) {
37397
+ mkdirSync11(newDir, { recursive: true });
37395
37398
  cpSync2(oldDir, newDir, { recursive: true });
37396
37399
  }
37397
37400
  return newDir;
37398
37401
  }
37399
37402
  function ensureProfilesDir() {
37400
37403
  const dir = getProfilesDir();
37401
- if (!existsSync12(dir)) {
37402
- mkdirSync9(dir, { recursive: true });
37404
+ if (!existsSync15(dir)) {
37405
+ mkdirSync11(dir, { recursive: true });
37403
37406
  }
37404
37407
  }
37405
37408
  function profilePath(id) {
37406
- return join11(getProfilesDir(), `${id}.json`);
37409
+ return join19(getProfilesDir(), `${id}.json`);
37407
37410
  }
37408
37411
  function shortUuid() {
37409
37412
  return crypto.randomUUID().slice(0, 8);
@@ -37422,30 +37425,30 @@ function createProfile(input2) {
37422
37425
  if (input2.name) {
37423
37426
  profile.name = input2.name;
37424
37427
  }
37425
- writeFileSync8(profilePath(id), JSON.stringify(profile, null, 2) + `
37428
+ writeFileSync10(profilePath(id), JSON.stringify(profile, null, 2) + `
37426
37429
  `);
37427
37430
  return profile;
37428
37431
  }
37429
37432
  function getProfile(id) {
37430
37433
  const path = profilePath(id);
37431
37434
  try {
37432
- if (!existsSync12(path))
37435
+ if (!existsSync15(path))
37433
37436
  return null;
37434
- return JSON.parse(readFileSync9(path, "utf-8"));
37437
+ return JSON.parse(readFileSync14(path, "utf-8"));
37435
37438
  } catch {
37436
37439
  return null;
37437
37440
  }
37438
37441
  }
37439
37442
  function listProfiles() {
37440
37443
  const dir = getProfilesDir();
37441
- if (!existsSync12(dir))
37444
+ if (!existsSync15(dir))
37442
37445
  return [];
37443
37446
  try {
37444
37447
  const files = readdirSync8(dir).filter((f) => f.endsWith(".json"));
37445
37448
  const profiles = [];
37446
37449
  for (const file2 of files) {
37447
37450
  try {
37448
- const content = readFileSync9(join11(dir, file2), "utf-8");
37451
+ const content = readFileSync14(join19(dir, file2), "utf-8");
37449
37452
  profiles.push(JSON.parse(content));
37450
37453
  } catch {}
37451
37454
  }
@@ -37459,7 +37462,7 @@ function touchProfile(id) {
37459
37462
  if (!profile)
37460
37463
  return;
37461
37464
  profile.last_seen_at = new Date().toISOString();
37462
- writeFileSync8(profilePath(id), JSON.stringify(profile, null, 2) + `
37465
+ writeFileSync10(profilePath(id), JSON.stringify(profile, null, 2) + `
37463
37466
  `);
37464
37467
  }
37465
37468
  function exportProfiles() {
@@ -37475,11 +37478,11 @@ function importProfiles(profiles) {
37475
37478
  continue;
37476
37479
  }
37477
37480
  const path = profilePath(profile.agent_id);
37478
- if (existsSync12(path)) {
37481
+ if (existsSync15(path)) {
37479
37482
  skipped++;
37480
37483
  continue;
37481
37484
  }
37482
- writeFileSync8(path, JSON.stringify(profile, null, 2) + `
37485
+ writeFileSync10(path, JSON.stringify(profile, null, 2) + `
37483
37486
  `);
37484
37487
  imported++;
37485
37488
  }
@@ -37489,18 +37492,18 @@ var init_profiles = __esm(() => {
37489
37492
  init_app_home();
37490
37493
  });
37491
37494
 
37492
- // ../hooks0102-standalone-lock/node_modules/@hasna/contracts/dist/client/transport.js
37493
- import { isIP } from "net";
37494
- import { spawnSync } from "child_process";
37495
+ // ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
37496
+ import { isIP as isIP2 } from "net";
37497
+ import { spawnSync as spawnSync2 } from "child_process";
37495
37498
  import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
37496
37499
  import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
37497
37500
  import { hostname as osHostname } from "os";
37498
- import { isAbsolute as isAbsolute7, join as join22 } from "path";
37499
- import { createRequire as createRequire2 } from "module";
37501
+ import { isAbsolute as isAbsolute17, join as join22 } from "path";
37502
+ import { createRequire as createRequire3 } from "module";
37500
37503
  import { fileURLToPath as fileURLToPath22 } from "url";
37501
- import { closeSync as closeSync4, fstatSync as fstatSync3, lstatSync as lstatSync7, openSync as openSync4, readFileSync as readFileSync12, realpathSync as realpathSync7, statSync } from "fs";
37504
+ import { closeSync as closeSync6, fstatSync as fstatSync5, lstatSync as lstatSync10, openSync as openSync6, readFileSync as readFileSync15, realpathSync as realpathSync9, statSync as statSync2 } from "fs";
37502
37505
  import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
37503
- import { basename as basename5, dirname as dirname11, join as join12, relative, sep as sep3 } from "path";
37506
+ import { basename as basename5, dirname as dirname19, join as join20, relative, sep as sep3 } from "path";
37504
37507
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
37505
37508
  function envToken2(name) {
37506
37509
  return name.toUpperCase().replace(/-/g, "_");
@@ -37574,16 +37577,16 @@ function o(e2, r2, t2) {
37574
37577
  }
37575
37578
  }
37576
37579
  function entryPoint(directory2) {
37577
- const root = realpathSync7(directory2);
37578
- const fd = openSync4(join12(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
37580
+ const root = realpathSync9(directory2);
37581
+ const fd = openSync6(join20(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
37579
37582
  let pkg;
37580
37583
  try {
37581
- const stat2 = fstatSync3(fd);
37582
- if (!stat2.isFile() || stat2.size > MAX_PACKAGE_BYTES2)
37584
+ const stat2 = fstatSync5(fd);
37585
+ if (!stat2.isFile() || stat2.size > MAX_PACKAGE_BYTES3)
37583
37586
  throw new Error("Invalid Secrets package metadata");
37584
- pkg = JSON.parse(readFileSync12(fd, "utf8"));
37587
+ pkg = JSON.parse(readFileSync15(fd, "utf8"));
37585
37588
  } finally {
37586
- closeSync4(fd);
37589
+ closeSync6(fd);
37587
37590
  }
37588
37591
  if (!pkg || typeof pkg !== "object" || !("name" in pkg) || pkg.name !== PACKAGE) {
37589
37592
  throw new Error("Invalid Secrets package identity");
@@ -37595,21 +37598,21 @@ function entryPoint(directory2) {
37595
37598
  if (/[\\%?#\0]/.test(target) || parts.some((part) => !part || part === "." || part === ".." || part === "node_modules")) {
37596
37599
  throw new Error("Invalid Secrets import export");
37597
37600
  }
37598
- const file2 = realpathSync7(join12(root, ...parts));
37601
+ const file2 = realpathSync9(join20(root, ...parts));
37599
37602
  const within = relative(root, file2);
37600
- if (!within || within === ".." || within.startsWith(`..${sep3}`) || !statSync(file2).isFile()) {
37603
+ if (!within || within === ".." || within.startsWith(`..${sep3}`) || !statSync2(file2).isFile()) {
37601
37604
  throw new Error("Secrets import export escapes its package or is not a file");
37602
37605
  }
37603
37606
  return pathToFileURL(file2).href;
37604
37607
  }
37605
37608
  function resolveInstalledSecrets(parentUrl) {
37606
- let directory2 = dirname11(fileURLToPath3(parentUrl));
37609
+ let directory2 = dirname19(fileURLToPath3(parentUrl));
37607
37610
  for (;; ) {
37608
37611
  if (basename5(directory2) !== "node_modules") {
37609
- const candidate = join12(directory2, "node_modules", PACKAGE);
37612
+ const candidate = join20(directory2, "node_modules", PACKAGE);
37610
37613
  let absent = false;
37611
37614
  try {
37612
- lstatSync7(candidate);
37615
+ lstatSync10(candidate);
37613
37616
  } catch (error61) {
37614
37617
  if (error61.code !== "ENOENT")
37615
37618
  throw error61;
@@ -37618,7 +37621,7 @@ function resolveInstalledSecrets(parentUrl) {
37618
37621
  if (!absent)
37619
37622
  return entryPoint(candidate);
37620
37623
  }
37621
- const parent = dirname11(directory2);
37624
+ const parent = dirname19(directory2);
37622
37625
  if (parent === directory2)
37623
37626
  throw new Error("Secrets SDK is not installed for this consumer");
37624
37627
  directory2 = parent;
@@ -37630,7 +37633,7 @@ function homeDir(env) {
37630
37633
  }
37631
37634
  function absoluteOverride(env, key) {
37632
37635
  const value = env[key]?.trim();
37633
- return value && isAbsolute7(value) ? value : null;
37636
+ return value && isAbsolute17(value) ? value : null;
37634
37637
  }
37635
37638
  function hasnaHomeDir(env) {
37636
37639
  const override = absoluteOverride(env, HASNA_HOME_ENV_KEY);
@@ -37726,7 +37729,7 @@ function readAppConfigFile(path) {
37726
37729
  const uid2 = process.getuid?.() ?? process.geteuid?.();
37727
37730
  if (uid2 !== undefined && before.uid !== uid2)
37728
37731
  unsafe("the file is not owned by the current user");
37729
- if (before.size > MAX_CREDENTIAL_FILE_BYTES2)
37732
+ if (before.size > MAX_CREDENTIAL_FILE_BYTES3)
37730
37733
  unsafe("the file exceeds the size limit");
37731
37734
  const bytes = readFileSync22(fd);
37732
37735
  const after = fstatSync22(fd);
@@ -37818,13 +37821,13 @@ function sealCredential(fields) {
37818
37821
  configurable: false
37819
37822
  });
37820
37823
  }
37821
- Object.defineProperty(sealed, INSPECT_CUSTOM2, {
37824
+ Object.defineProperty(sealed, INSPECT_CUSTOM3, {
37822
37825
  value: () => ({ ...visible, apiKey: "[redacted]" }),
37823
37826
  enumerable: false,
37824
37827
  writable: false,
37825
37828
  configurable: false
37826
37829
  });
37827
- Object.defineProperty(sealed, CREDENTIAL_SEAL2, {
37830
+ Object.defineProperty(sealed, CREDENTIAL_SEAL3, {
37828
37831
  value: true,
37829
37832
  enumerable: false,
37830
37833
  writable: false,
@@ -37855,10 +37858,10 @@ function firstEnvValue(env, keys) {
37855
37858
  return null;
37856
37859
  }
37857
37860
  function isAmbientEnvironment(env) {
37858
- return env === process.env || env[AMBIENT_ENVIRONMENT2] === true;
37861
+ return env === process.env || env[AMBIENT_ENVIRONMENT3] === true;
37859
37862
  }
37860
37863
  function defaultKeychainRunner(argv) {
37861
- const result = spawnSync(KEYCHAIN_SECURITY_BIN, [...argv], {
37864
+ const result = spawnSync2(KEYCHAIN_SECURITY_BIN, [...argv], {
37862
37865
  encoding: "utf8",
37863
37866
  stdio: ["ignore", "pipe", "pipe"],
37864
37867
  timeout: KEYCHAIN_SPAWN_TIMEOUT_MS
@@ -37949,7 +37952,7 @@ function snapshotClientEnvironment(name, env) {
37949
37952
  snapshot2[key] = descriptor.value;
37950
37953
  }
37951
37954
  if (ambient) {
37952
- Object.defineProperty(snapshot2, AMBIENT_ENVIRONMENT2, {
37955
+ Object.defineProperty(snapshot2, AMBIENT_ENVIRONMENT3, {
37953
37956
  value: true,
37954
37957
  enumerable: false,
37955
37958
  writable: false,
@@ -38122,7 +38125,7 @@ async function completePointerCredential(name, pointerResolution, env = process.
38122
38125
  let secretsSdk;
38123
38126
  try {
38124
38127
  const sdkUrl = resolveInstalledSecrets(import.meta.url);
38125
- secretsSdk = requireSecretsSdk2(fileURLToPath22(sdkUrl));
38128
+ secretsSdk = requireSecretsSdk3(fileURLToPath22(sdkUrl));
38126
38129
  } catch {
38127
38130
  throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
38128
38131
  }
@@ -38206,7 +38209,7 @@ function canonicalAuthorityHostname(authority) {
38206
38209
  }
38207
38210
  assertCanonicalPort(portSuffix.slice(1));
38208
38211
  }
38209
- if (isIP(rawHostname.slice(1, -1)) !== 6) {
38212
+ if (isIP2(rawHostname.slice(1, -1)) !== 6) {
38210
38213
  throw new Error("API URL authority must contain a canonical IPv6 literal.");
38211
38214
  }
38212
38215
  } else {
@@ -38222,7 +38225,7 @@ function canonicalAuthorityHostname(authority) {
38222
38225
  } else {
38223
38226
  rawHostname = authority;
38224
38227
  }
38225
- const ipVersion = isIP(rawHostname);
38228
+ const ipVersion = isIP2(rawHostname);
38226
38229
  const numericAddressParts = rawHostname.split(".");
38227
38230
  const looksLikeNonCanonicalIpv4 = numericAddressParts.every((part) => /^(?:0x[0-9a-f]+|[0-9]+)$/i.test(part));
38228
38231
  if (ipVersion !== 4 && looksLikeNonCanonicalIpv4 || ipVersion !== 4 && !isValidDnsDomain(rawHostname.toLowerCase())) {
@@ -38358,9 +38361,9 @@ function credentialDiskSourcesForMessage(name, env) {
38358
38361
  const paths = credentialDiskSources(name, env);
38359
38362
  return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
38360
38363
  }
38361
- var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets", MAX_PACKAGE_BYTES2, CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, AMBIENT_ENVIRONMENT2, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, ClientTransportConfigurationError, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2;
38364
+ var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets", MAX_PACKAGE_BYTES3, CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES3, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM3, CREDENTIAL_SEAL3, AMBIENT_ENVIRONMENT3, requireSecretsSdk3, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, ClientTransportConfigurationError, IDEMPOTENT_METHODS3, AUTHORITY_OVERRIDE_HEADERS3;
38362
38365
  var init_transport = __esm(() => {
38363
- MAX_PACKAGE_BYTES2 = 1024 * 1024;
38366
+ MAX_PACKAGE_BYTES3 = 1024 * 1024;
38364
38367
  CredentialResolutionError = class CredentialResolutionError extends Error {
38365
38368
  appName;
38366
38369
  attempted;
@@ -38379,16 +38382,16 @@ var init_transport = __esm(() => {
38379
38382
  this.path = path;
38380
38383
  }
38381
38384
  };
38382
- MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
38385
+ MAX_CREDENTIAL_FILE_BYTES3 = 64 * 1024;
38383
38386
  SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
38384
38387
  SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
38385
38388
  ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
38386
38389
  VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
38387
38390
  CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
38388
- INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
38389
- CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
38390
- AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
38391
- requireSecretsSdk2 = createRequire2(import.meta.url);
38391
+ INSPECT_CUSTOM3 = Symbol.for("nodejs.util.inspect.custom");
38392
+ CREDENTIAL_SEAL3 = Symbol.for("hasna:contracts:sealedCredential");
38393
+ AMBIENT_ENVIRONMENT3 = Symbol.for("hasna:contracts:ambientClientEnvironment");
38394
+ requireSecretsSdk3 = createRequire3(import.meta.url);
38392
38395
  ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
38393
38396
  DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
38394
38397
  ClientTransportConfigurationError = class ClientTransportConfigurationError extends Error {
@@ -38401,8 +38404,8 @@ var init_transport = __esm(() => {
38401
38404
  this.sources = Object.freeze([...sources]);
38402
38405
  }
38403
38406
  };
38404
- IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
38405
- AUTHORITY_OVERRIDE_HEADERS2 = new Set([
38407
+ IDEMPOTENT_METHODS3 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
38408
+ AUTHORITY_OVERRIDE_HEADERS3 = new Set([
38406
38409
  "host",
38407
38410
  ":authority",
38408
38411
  "forwarded",
@@ -38737,8 +38740,8 @@ var init_db_writer = __esm(() => {
38737
38740
  });
38738
38741
 
38739
38742
  // src/lib/hook-env.ts
38740
- import { dirname as dirname17, isAbsolute as isAbsolute15 } from "path";
38741
- import { existsSync as existsSync13, realpathSync as realpathSync8, statSync as statSync2 } from "fs";
38743
+ import { dirname as dirname20, isAbsolute as isAbsolute18 } from "path";
38744
+ import { existsSync as existsSync16, realpathSync as realpathSync10, statSync as statSync4 } from "fs";
38742
38745
  import { tmpdir } from "os";
38743
38746
  function isDeniedEnvName(name) {
38744
38747
  const upper = name.toUpperCase();
@@ -38757,7 +38760,7 @@ function isBashFunctionEnvName(name) {
38757
38760
  return name.startsWith("BASH_FUNC_");
38758
38761
  }
38759
38762
  function isUnsafePathEntry(entry, home) {
38760
- if (entry === "" || !isAbsolute15(entry))
38763
+ if (entry === "" || !isAbsolute18(entry))
38761
38764
  return true;
38762
38765
  if (home && (entry === home || entry.startsWith(home + "/")))
38763
38766
  return true;
@@ -38767,7 +38770,7 @@ function isUnsafePathEntry(entry, home) {
38767
38770
  return true;
38768
38771
  const canonical4 = (path) => {
38769
38772
  try {
38770
- return realpathSync8(path);
38773
+ return realpathSync10(path);
38771
38774
  } catch {
38772
38775
  return path;
38773
38776
  }
@@ -38779,16 +38782,16 @@ function isUnsafePathEntry(entry, home) {
38779
38782
  return true;
38780
38783
  }
38781
38784
  try {
38782
- if ((statSync2(entry).mode & 2) !== 0)
38785
+ if ((statSync4(entry).mode & 2) !== 0)
38783
38786
  return true;
38784
38787
  } catch {}
38785
38788
  return false;
38786
38789
  }
38787
38790
  function sanitizeHookPath(pathValue, home) {
38788
38791
  const baseline = PATH_BASELINE.slice();
38789
- if (process.platform === "darwin" && existsSync13("/opt/homebrew/bin"))
38792
+ if (process.platform === "darwin" && existsSync16("/opt/homebrew/bin"))
38790
38793
  baseline.push("/opt/homebrew/bin");
38791
- const bunDir = dirname17(process.execPath);
38794
+ const bunDir = dirname20(process.execPath);
38792
38795
  const seen = new Set;
38793
38796
  const out = [];
38794
38797
  for (const dir of baseline) {
@@ -38912,8 +38915,8 @@ __export(exports_run, {
38912
38915
  HookTimeoutError: () => HookTimeoutError
38913
38916
  });
38914
38917
  import { randomBytes as randomBytes2 } from "crypto";
38915
- import { rmSync as rmSync2, writeFileSync as writeFileSync10 } from "fs";
38916
- import { basename as basename9, dirname as dirname19, isAbsolute as isAbsolute17, join as join13 } from "path";
38918
+ import { rmSync as rmSync2, writeFileSync as writeFileSync11 } from "fs";
38919
+ import { basename as basename9, dirname as dirname21, isAbsolute as isAbsolute19, join as join24 } from "path";
38917
38920
  function extensionOf(scriptPath) {
38918
38921
  const base = basename9(scriptPath);
38919
38922
  const dot = base.lastIndexOf(".");
@@ -38982,9 +38985,9 @@ async function readPipeWithDeadline(stream, deadlineMs) {
38982
38985
  return chunks.join("");
38983
38986
  }
38984
38987
  async function executeVerifiedScript(options) {
38985
- const scriptDir = dirname19(options.scriptPath);
38988
+ const scriptDir = dirname21(options.scriptPath);
38986
38989
  const interpreter = interpreterFor(options.name, options.scriptPath, options.content);
38987
- const tempPath = join13(scriptDir, `.hooks-verified-${randomBytes2(12).toString("hex")}.${interpreter.tempExt}`);
38990
+ const tempPath = join24(scriptDir, `.hooks-verified-${randomBytes2(12).toString("hex")}.${interpreter.tempExt}`);
38988
38991
  let proc = null;
38989
38992
  let timedOut = false;
38990
38993
  const timeoutTimer = options.timeout ? setTimeout(() => {
@@ -38992,8 +38995,8 @@ async function executeVerifiedScript(options) {
38992
38995
  killGroup(proc, { leaderAlive: proc !== null && proc.exitCode === null });
38993
38996
  }, options.timeout) : null;
38994
38997
  try {
38995
- writeFileSync10(tempPath, options.content, { flag: "wx", mode: 384 });
38996
- proc = Bun.spawn([...interpreter.command, isAbsolute17(tempPath) ? tempPath : `./${tempPath}`, ...options.args ?? []], {
38998
+ writeFileSync11(tempPath, options.content, { flag: "wx", mode: 384 });
38999
+ proc = Bun.spawn([...interpreter.command, isAbsolute19(tempPath) ? tempPath : `./${tempPath}`, ...options.args ?? []], {
38997
39000
  stdin: new Response(options.stdin),
38998
39001
  stdout: "pipe",
38999
39002
  stderr: "pipe",
@@ -39075,15 +39078,15 @@ __export(exports_custom_install, {
39075
39078
  installCustomSource: () => installCustomSource,
39076
39079
  ensureCustomDir: () => ensureCustomDir
39077
39080
  });
39078
- import { existsSync as existsSync14, mkdirSync as mkdirSync11, mkdtempSync, readFileSync as readFileSync14, rmSync as rmSync4 } from "fs";
39079
- import { join as join17 } from "path";
39081
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync, readFileSync as readFileSync17, rmSync as rmSync4 } from "fs";
39082
+ import { join as join27 } from "path";
39080
39083
  import { tmpdir as tmpdir2 } from "os";
39081
39084
  function manifestAt(dir) {
39082
- const path = join17(dir, "manifest.json");
39083
- if (!existsSync14(path))
39085
+ const path = join27(dir, "manifest.json");
39086
+ if (!existsSync17(path))
39084
39087
  return;
39085
39088
  try {
39086
- return parseManifest(readFileSync14(path, "utf-8"));
39089
+ return parseManifest(readFileSync17(path, "utf-8"));
39087
39090
  } catch {
39088
39091
  return;
39089
39092
  }
@@ -39102,8 +39105,8 @@ function writeFromManifest(manifest, srcDir, source, kind) {
39102
39105
  return { name, version: manifest.version, kind, source, dir, scriptPath };
39103
39106
  }
39104
39107
  async function cloneToTemp(gitUrl) {
39105
- const tmp = mkdtempSync(join17(tmpdir2(), "hooks-install-"));
39106
- const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl, join17(tmp, "repo")], {
39108
+ const tmp = mkdtempSync(join27(tmpdir2(), "hooks-install-"));
39109
+ const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl, join27(tmp, "repo")], {
39107
39110
  stdout: "pipe",
39108
39111
  stderr: "pipe"
39109
39112
  });
@@ -39116,7 +39119,7 @@ async function cloneToTemp(gitUrl) {
39116
39119
  rmSync4(tmp, { recursive: true, force: true });
39117
39120
  throw new Error(`git clone failed (${exitCode}): ${stderr.trim()}`);
39118
39121
  }
39119
- return join17(tmp, "repo");
39122
+ return join27(tmp, "repo");
39120
39123
  }
39121
39124
  function isGitUrl(value) {
39122
39125
  return value.startsWith("git@") || value.startsWith("ssh://") || value.startsWith("file://") || value.endsWith(".git");
@@ -39126,7 +39129,7 @@ function isCustomSource(value) {
39126
39129
  return true;
39127
39130
  if (value.startsWith("http://") || value.startsWith("https://"))
39128
39131
  return true;
39129
- return existsSync14(value);
39132
+ return existsSync17(value);
39130
39133
  }
39131
39134
  async function installCustomSource(source) {
39132
39135
  if (isGitUrl(source)) {
@@ -39140,11 +39143,11 @@ async function installCustomSource(source) {
39140
39143
  if (source.startsWith("http://") || source.startsWith("https://")) {
39141
39144
  return installManifestUrl(source);
39142
39145
  }
39143
- if (!existsSync14(source)) {
39146
+ if (!existsSync17(source)) {
39144
39147
  throw new Error(`No such local path: ${source}`);
39145
39148
  }
39146
39149
  if (source.endsWith("manifest.json")) {
39147
- const manifest = parseManifest(readFileSync14(source, "utf-8"));
39150
+ const manifest = parseManifest(readFileSync17(source, "utf-8"));
39148
39151
  return writeFromManifest(manifest, source.substring(0, source.lastIndexOf("/")), source, "local");
39149
39152
  }
39150
39153
  return copyManifestDir(source, source, "local");
@@ -39175,7 +39178,7 @@ async function installManifestUrl(url2) {
39175
39178
  }
39176
39179
  function ensureCustomDir() {
39177
39180
  const dir = getCustomHooksDir();
39178
- mkdirSync11(dir, { recursive: true });
39181
+ mkdirSync12(dir, { recursive: true });
39179
39182
  return dir;
39180
39183
  }
39181
39184
  var init_custom_install = __esm(() => {
@@ -39193,13 +39196,13 @@ __export(exports_sync, {
39193
39196
  fetchPinnedHook: () => fetchPinnedHook,
39194
39197
  commitSyncArtifacts: () => commitSyncArtifacts
39195
39198
  });
39196
- import { createHash as createHash7 } from "crypto";
39197
- import { readFileSync as readFileSync15 } from "fs";
39199
+ import { createHash as createHash12 } from "crypto";
39200
+ import { readFileSync as readFileSync19 } from "fs";
39198
39201
  function sha256OfText(text3) {
39199
- return createHash7("sha256").update(text3).digest("hex");
39202
+ return createHash12("sha256").update(text3).digest("hex");
39200
39203
  }
39201
39204
  function sha256OfPath(path) {
39202
- return createHash7("sha256").update(readFileSync15(path)).digest("hex");
39205
+ return createHash12("sha256").update(readFileSync19(path)).digest("hex");
39203
39206
  }
39204
39207
  function collectBundledCatalog() {
39205
39208
  const out = [];
@@ -40354,13 +40357,13 @@ __export(exports_serve, {
40354
40357
  SERVE_HOST: () => SERVE_HOST,
40355
40358
  DEFAULT_SERVE_PORT: () => DEFAULT_SERVE_PORT
40356
40359
  });
40357
- import { readFileSync as readFileSync17 } from "fs";
40358
- import { dirname as dirname20, join as join19 } from "path";
40360
+ import { readFileSync as readFileSync20 } from "fs";
40361
+ import { dirname as dirname22, join as join29 } from "path";
40359
40362
  import { fileURLToPath as fileURLToPath4 } from "url";
40360
40363
  function packageVersion() {
40361
40364
  try {
40362
- const pkgPath = join19(dirname20(fileURLToPath4(import.meta.url)), "..", "package.json");
40363
- return JSON.parse(readFileSync17(pkgPath, "utf-8")).version || "0.0.0";
40365
+ const pkgPath = join29(dirname22(fileURLToPath4(import.meta.url)), "..", "package.json");
40366
+ return JSON.parse(readFileSync20(pkgPath, "utf-8")).version || "0.0.0";
40364
40367
  } catch {
40365
40368
  return "0.0.0";
40366
40369
  }
@@ -40660,17 +40663,17 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
40660
40663
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
40661
40664
  import { z as z3 } from "zod";
40662
40665
  import { createServer } from "http";
40663
- import { existsSync as existsSync15, readFileSync as readFileSync19 } from "fs";
40664
- import { join as join20, dirname as dirname21 } from "path";
40666
+ import { existsSync as existsSync18, readFileSync as readFileSync21 } from "fs";
40667
+ import { join as join30, dirname as dirname23 } from "path";
40665
40668
  import { fileURLToPath as fileURLToPath5 } from "url";
40666
40669
  async function runVerifiedHook(name, stdin, timeoutMs) {
40667
40670
  const { resolveHook: resolveHook2, resolveScriptPath: resolveScriptPath2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
40668
40671
  const resolved = resolveHook2(name);
40669
40672
  const hookScript = resolveScriptPath2(name);
40670
- if (!resolved || !hookScript || !existsSync15(hookScript)) {
40673
+ if (!resolved || !hookScript || !existsSync18(hookScript)) {
40671
40674
  throw new Error(`Hook '${name}' not found`);
40672
40675
  }
40673
- const content = readFileSync19(hookScript);
40676
+ const content = readFileSync21(hookScript);
40674
40677
  const sha4 = sha256Of(content);
40675
40678
  const check2 = checkScriptHash(name, sha4);
40676
40679
  if (!check2.ok) {
@@ -40875,7 +40878,7 @@ function createHooksServer() {
40875
40878
  const settingsPath = getSettingsPath(scope);
40876
40879
  const issues = [];
40877
40880
  const healthy = [];
40878
- const settingsExist = existsSync15(settingsPath);
40881
+ const settingsExist = existsSync18(settingsPath);
40879
40882
  if (!settingsExist) {
40880
40883
  issues.push({ hook: "(settings)", issue: `${settingsPath} not found`, severity: "warning" });
40881
40884
  }
@@ -40885,7 +40888,7 @@ function createHooksServer() {
40885
40888
  const meta3 = custom2 ? resolveHookMeta(name) : getHook(name);
40886
40889
  let hookHealthy = true;
40887
40890
  if (custom2) {
40888
- if (!existsSync15(custom2.scriptPath)) {
40891
+ if (!existsSync18(custom2.scriptPath)) {
40889
40892
  issues.push({ hook: name, issue: `Custom hook script missing: ${custom2.scriptPath}`, severity: "error" });
40890
40893
  hookHealthy = false;
40891
40894
  }
@@ -40895,14 +40898,14 @@ function createHooksServer() {
40895
40898
  continue;
40896
40899
  }
40897
40900
  const hookDir = getHookPath(name);
40898
- if (!existsSync15(join20(hookDir, "src", "hook.ts"))) {
40901
+ if (!existsSync18(join30(hookDir, "src", "hook.ts"))) {
40899
40902
  issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
40900
40903
  hookHealthy = false;
40901
40904
  }
40902
40905
  }
40903
40906
  if (meta3 && settingsExist) {
40904
40907
  try {
40905
- const settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
40908
+ const settings = JSON.parse(readFileSync21(settingsPath, "utf-8"));
40906
40909
  if (!hookRegisteredInSettings(settings, name, meta3.event, meta3.matcher)) {
40907
40910
  const eventName = meta3.event.split(":")[0];
40908
40911
  issues.push({ hook: name, issue: `Not registered under correct event (${eventName})`, severity: "error" });
@@ -40939,10 +40942,10 @@ function createHooksServer() {
40939
40942
  return { content: [{ type: "text", text: JSON.stringify({ error: `Hook '${name}' not found` }) }] };
40940
40943
  }
40941
40944
  const hookPath = getHookPath(name);
40942
- const readmePath = join20(hookPath, "README.md");
40945
+ const readmePath = join30(hookPath, "README.md");
40943
40946
  let readme = "";
40944
- if (existsSync15(readmePath)) {
40945
- readme = readFileSync19(readmePath, "utf-8");
40947
+ if (existsSync18(readmePath)) {
40948
+ readme = readFileSync21(readmePath, "utf-8");
40946
40949
  }
40947
40950
  if (verbose) {
40948
40951
  return { content: [{ type: "text", text: JSON.stringify({ ...meta3, readme }) }] };
@@ -41125,7 +41128,7 @@ function createHooksServer() {
41125
41128
  const ctx = {
41126
41129
  scope,
41127
41130
  settings_path: settingsPath,
41128
- settings_exists: existsSync15(settingsPath),
41131
+ settings_exists: existsSync18(settingsPath),
41129
41132
  registered_hooks: hooks,
41130
41133
  hook_count: hooks.length,
41131
41134
  healthy,
@@ -41271,8 +41274,8 @@ function createHooksServer() {
41271
41274
  const settingsPath = getSettingsPath(scope);
41272
41275
  let settings = {};
41273
41276
  try {
41274
- if (existsSync15(settingsPath))
41275
- settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
41277
+ if (existsSync18(settingsPath))
41278
+ settings = JSON.parse(readFileSync21(settingsPath, "utf-8"));
41276
41279
  } catch {}
41277
41280
  if (!settings.hooks)
41278
41281
  settings.hooks = {};
@@ -41294,8 +41297,8 @@ function createHooksServer() {
41294
41297
  const settingsPath = getSettingsPath(scope);
41295
41298
  let settings = {};
41296
41299
  try {
41297
- if (existsSync15(settingsPath))
41298
- settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
41300
+ if (existsSync18(settingsPath))
41301
+ settings = JSON.parse(readFileSync21(settingsPath, "utf-8"));
41299
41302
  } catch {}
41300
41303
  if (settings.hooks?.__disabled) {
41301
41304
  settings.hooks.__disabled = settings.hooks.__disabled.filter((n2) => n2 !== name);
@@ -41665,13 +41668,13 @@ var init_server = __esm(() => {
41665
41668
  init_redact();
41666
41669
  init_authority();
41667
41670
  init_storage();
41668
- __dirname3 = dirname21(fileURLToPath5(import.meta.url));
41671
+ __dirname3 = dirname23(fileURLToPath5(import.meta.url));
41669
41672
  pkg = { name: "@hasna/hooks", version: "0.0.0" };
41670
41673
  try {
41671
41674
  for (const rel of ["../../package.json", "../package.json", "../../../package.json"]) {
41672
- const p = join20(__dirname3, rel);
41673
- if (existsSync15(p)) {
41674
- pkg = JSON.parse(readFileSync19(p, "utf-8"));
41675
+ const p = join30(__dirname3, rel);
41676
+ if (existsSync18(p)) {
41677
+ pkg = JSON.parse(readFileSync21(p, "utf-8"));
41675
41678
  break;
41676
41679
  }
41677
41680
  }
@@ -41739,16 +41742,25 @@ function startMcpHttpServer(options) {
41739
41742
  var DEFAULT_MCP_HTTP_PORT = 8847, MCP_HTTP_HOST = "127.0.0.1", MCP_SERVICE_NAME = "hooks";
41740
41743
  var init_http = () => {};
41741
41744
 
41742
- // ../hooks0102-standalone-lock/node_modules/@hasna/events/dist/commander.js
41745
+ // ../events/dist/commander.js
41743
41746
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
41744
41747
  import { Buffer as Buffer2 } from "buffer";
41748
+ import { existsSync as existsSync2 } from "fs";
41749
+ import { join as join2 } from "path";
41745
41750
  import { existsSync } from "fs";
41746
41751
  import { homedir } from "os";
41747
- import { join } from "path";
41752
+ import { join, resolve } from "path";
41753
+ import { homedir as pathsResolverHomedir } from "os";
41754
+ import { join as pathsResolverJoin } from "path";
41748
41755
  import { createHmac, timingSafeEqual } from "crypto";
41756
+ import { lookup as dnsLookup } from "dns/promises";
41757
+ import { isIP } from "net";
41749
41758
  import { randomUUID } from "crypto";
41750
41759
  import { spawn } from "child_process";
41760
+ import { request as nodeHttpRequest } from "http";
41761
+ import { request as nodeHttpsRequest } from "https";
41751
41762
  import { randomUUID as randomUUID2 } from "crypto";
41763
+ import { createRequire } from "module";
41752
41764
  function getPathValue(input, path) {
41753
41765
  return path.split(".").reduce((value, part) => {
41754
41766
  if (value && typeof value === "object" && part in value) {
@@ -41844,13 +41856,103 @@ function channelMatchesEvent(channel, event) {
41844
41856
  return true;
41845
41857
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
41846
41858
  }
41859
+ var PATHS_RESOLVER_KIND_ENV = {
41860
+ config: "HASNA_CONFIG_HOME",
41861
+ data: "HASNA_DATA_HOME",
41862
+ state: "HASNA_STATE_HOME",
41863
+ cache: "HASNA_CACHE_HOME"
41864
+ };
41865
+ var PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
41866
+ function pathsResolverAssertApp(app) {
41867
+ if (typeof app !== "string" || app.length === 0) {
41868
+ throw new TypeError("paths: app must be a non-empty string");
41869
+ }
41870
+ if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
41871
+ throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
41872
+ }
41873
+ }
41874
+ function pathsResolverAssertKind(kind) {
41875
+ if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
41876
+ throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
41877
+ }
41878
+ }
41879
+ function pathsResolverBaseDir(kind, options) {
41880
+ pathsResolverAssertKind(kind);
41881
+ const env = options.env ?? process.env;
41882
+ const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
41883
+ if (typeof override === "string" && override.length > 0)
41884
+ return override;
41885
+ const home = options.home ?? pathsResolverHomedir();
41886
+ const platform = options.platform ?? process.platform;
41887
+ if (platform === "darwin") {
41888
+ switch (kind) {
41889
+ case "config":
41890
+ case "data":
41891
+ return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
41892
+ case "cache":
41893
+ return pathsResolverJoin(home, "Library", "Caches", "Hasna");
41894
+ case "state":
41895
+ return pathsResolverJoin(home, "Library", "Logs", "Hasna");
41896
+ }
41897
+ }
41898
+ switch (kind) {
41899
+ case "config":
41900
+ return pathsResolverJoin(home, ".config", "hasna");
41901
+ case "data":
41902
+ return pathsResolverJoin(home, ".local", "share", "hasna");
41903
+ case "state":
41904
+ return pathsResolverJoin(home, ".local", "state", "hasna");
41905
+ case "cache":
41906
+ return pathsResolverJoin(home, ".cache", "hasna");
41907
+ }
41908
+ }
41909
+ function pathsResolverResolve(kind, options) {
41910
+ pathsResolverAssertApp(options.app);
41911
+ const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
41912
+ return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
41913
+ }
41914
+ function dataDir(options) {
41915
+ return pathsResolverResolve("data", options);
41916
+ }
41847
41917
  var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
41848
41918
  var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
41919
+ var EVENTS_STORE_SENTINEL_FILE = "events.json";
41920
+ function effectiveHome() {
41921
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
41922
+ }
41923
+ function legacyHomeDir() {
41924
+ return join(effectiveHome(), ".hasna", "events");
41925
+ }
41926
+ function resolverHome() {
41927
+ return dataDir({ app: "events", home: effectiveHome() || undefined });
41928
+ }
41929
+ function adoptResolverHome(resolved, env = process.env) {
41930
+ const dataOverride = env.HASNA_DATA_HOME;
41931
+ if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
41932
+ return true;
41933
+ return existsSync(join(resolved, EVENTS_STORE_SENTINEL_FILE));
41934
+ }
41935
+ function exactEventsHome() {
41936
+ const dir = process.env[HASNA_EVENTS_DIR_ENV];
41937
+ if (dir && dir.trim())
41938
+ return dir.trim();
41939
+ const home = process.env[HASNA_EVENTS_HOME_ENV];
41940
+ if (home && home.trim())
41941
+ return home.trim();
41942
+ return;
41943
+ }
41944
+ function getEventsHome() {
41945
+ const exact = exactEventsHome();
41946
+ if (exact)
41947
+ return resolve(exact);
41948
+ const resolved = resolverHome();
41949
+ return adoptResolverHome(resolved) ? resolve(resolved) : resolve(legacyHomeDir());
41950
+ }
41849
41951
  var LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:";
41850
41952
  var DEFAULT_EVENT_PAGE_LIMIT = 100;
41851
41953
  var MAX_EVENT_PAGE_LIMIT = 1000;
41852
41954
  function getEventsDataDir(override) {
41853
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
41955
+ return override || getEventsHome();
41854
41956
  }
41855
41957
  function getActiveEventsDirEnv() {
41856
41958
  if (process.env[HASNA_EVENTS_DIR_ENV])
@@ -41866,12 +41968,12 @@ class JsonEventsStore {
41866
41968
  channelsPath;
41867
41969
  eventsPath;
41868
41970
  deliveriesPath;
41869
- constructor(dataDir = getEventsDataDir()) {
41870
- this.dataDir = dataDir;
41871
- this.runtime = localJsonRuntime(dataDir);
41872
- this.channelsPath = join(dataDir, "channels.json");
41873
- this.eventsPath = join(dataDir, "events.json");
41874
- this.deliveriesPath = join(dataDir, "deliveries.json");
41971
+ constructor(dataDir2 = getEventsDataDir()) {
41972
+ this.dataDir = dataDir2;
41973
+ this.runtime = localJsonRuntime(dataDir2);
41974
+ this.channelsPath = join2(dataDir2, "channels.json");
41975
+ this.eventsPath = join2(dataDir2, "events.json");
41976
+ this.deliveriesPath = join2(dataDir2, "deliveries.json");
41875
41977
  }
41876
41978
  async init() {
41877
41979
  await mkdir(this.dataDir, { recursive: true, mode: 448 });
@@ -41988,7 +42090,7 @@ class JsonEventsStore {
41988
42090
  };
41989
42091
  }
41990
42092
  async ensureArrayFile(path) {
41991
- if (!existsSync(path)) {
42093
+ if (!existsSync2(path)) {
41992
42094
  await writeFile(path, `[]
41993
42095
  `, { encoding: "utf-8", mode: 384 });
41994
42096
  }
@@ -42018,7 +42120,7 @@ class JsonEventsStore {
42018
42120
  });
42019
42121
  }
42020
42122
  }
42021
- function localJsonRuntime(dataDir = getEventsDataDir()) {
42123
+ function localJsonRuntime(dataDir2 = getEventsDataDir()) {
42022
42124
  return {
42023
42125
  mode: "local-files",
42024
42126
  name: "json-events-store",
@@ -42031,7 +42133,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
42031
42133
  durable: true,
42032
42134
  idempotency: "best-effort-local",
42033
42135
  replayCursors: true,
42034
- description: `Local JSON files in ${dataDir}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
42136
+ description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
42035
42137
  };
42036
42138
  }
42037
42139
  function encodeLocalJsonEventCursor(offset, options = {}) {
@@ -42095,8 +42197,8 @@ function assertCursorFilter(name, cursorValue, optionValue) {
42095
42197
  function findEventByIdentity(events, identity) {
42096
42198
  return events.find((event) => identity.id !== undefined && event.id === identity.id || identity.dedupeKey !== undefined && event.dedupeKey === identity.dedupeKey);
42097
42199
  }
42098
- async function getEventsStatus(dataDir) {
42099
- const store = new JsonEventsStore(dataDir);
42200
+ async function getEventsStatus(dataDir2) {
42201
+ const store = new JsonEventsStore(dataDir2);
42100
42202
  await store.init();
42101
42203
  const [channels, events, deliveries] = await Promise.all([
42102
42204
  store.listChannels(),
@@ -42138,9 +42240,9 @@ async function getEventsStatus(dataDir) {
42138
42240
  }
42139
42241
  };
42140
42242
  }
42141
- function statusFile(dataDir, fileName, records) {
42142
- const path = join(dataDir, fileName);
42143
- return { path, exists: existsSync(path), records };
42243
+ function statusFile(dataDir2, fileName, records) {
42244
+ const path = join2(dataDir2, fileName);
42245
+ return { path, exists: existsSync2(path), records };
42144
42246
  }
42145
42247
  var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
42146
42248
  function buildSignatureBase(timestamp, body) {
@@ -42150,6 +42252,214 @@ function signPayload(secret, timestamp, body) {
42150
42252
  const digest = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
42151
42253
  return `sha256=${digest}`;
42152
42254
  }
42255
+ var DEFAULT_MAX_REDIRECTS = 5;
42256
+ var IPV4_PRIVATE_RANGES = [
42257
+ [0, 16777215],
42258
+ [167772160, 184549375],
42259
+ [1681915904, 1686110207],
42260
+ [2130706432, 2147483647],
42261
+ [2851995648, 2852061183],
42262
+ [2886729728, 2887778303],
42263
+ [3221225472, 3221225727],
42264
+ [3221225984, 3221226239],
42265
+ [3227017984, 3227018239],
42266
+ [3232235520, 3232301055],
42267
+ [3323068416, 3323199487],
42268
+ [3325256704, 3325256959],
42269
+ [3405803776, 3405804031],
42270
+ [3758096384, 4294967295]
42271
+ ];
42272
+ var IPV6_SPECIAL_PREFIXES = [
42273
+ { groups: [0, 0, 0, 0, 0, 0, 0, 0], bits: 128 },
42274
+ { groups: [0, 0, 0, 0, 0, 0, 0, 1], bits: 128 },
42275
+ { groups: [0, 0, 0, 0, 0, 65535, 0, 0], bits: 96 },
42276
+ { groups: [100, 65435, 0, 0, 0, 0, 0, 0], bits: 96 },
42277
+ { groups: [256, 0, 0, 0, 0, 0, 0, 0], bits: 64 },
42278
+ { groups: [8193, 0, 0, 0, 0, 0, 0, 0], bits: 32 },
42279
+ { groups: [8193, 2, 0, 0, 0, 0, 0, 0], bits: 48 },
42280
+ { groups: [8193, 16, 0, 0, 0, 0, 0, 0], bits: 28 },
42281
+ { groups: [8193, 3512, 0, 0, 0, 0, 0, 0], bits: 32 },
42282
+ { groups: [8194, 0, 0, 0, 0, 0, 0, 0], bits: 16 },
42283
+ { groups: [16383, 0, 0, 0, 0, 0, 0, 0], bits: 20 },
42284
+ { groups: [64512, 0, 0, 0, 0, 0, 0, 0], bits: 7 },
42285
+ { groups: [65152, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
42286
+ { groups: [65216, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
42287
+ { groups: [65280, 0, 0, 0, 0, 0, 0, 0], bits: 8 }
42288
+ ];
42289
+ function isPrivateAddress(address) {
42290
+ const normalized = stripZoneId(address);
42291
+ const version = isIP(normalized);
42292
+ if (version === 4) {
42293
+ const integer = ipv4ToInt(normalized);
42294
+ if (integer === undefined)
42295
+ return true;
42296
+ return IPV4_PRIVATE_RANGES.some(([low, high]) => integer >= low && integer <= high);
42297
+ }
42298
+ if (version === 6) {
42299
+ const groups = ipv6Groups(normalized);
42300
+ if (!groups)
42301
+ return true;
42302
+ for (const prefix of IPV6_SPECIAL_PREFIXES) {
42303
+ if (!ipv6MatchesPrefix(groups, prefix.groups, prefix.bits))
42304
+ continue;
42305
+ if (prefix.bits === 96 && groups[5] === 65535) {
42306
+ return isPrivateAddress(ipv4IntToString(groups[6] << 16 | groups[7]));
42307
+ }
42308
+ if (prefix.bits === 16 && groups[0] === 8194) {
42309
+ return isPrivateAddress(ipv4IntToString(groups[1] << 16 | groups[2]));
42310
+ }
42311
+ return true;
42312
+ }
42313
+ return false;
42314
+ }
42315
+ return true;
42316
+ }
42317
+ async function resolveWebhookTarget(url, policy = {}) {
42318
+ const hostname = normalizeHostname(url.hostname);
42319
+ const allowlist = (policy.allowPrivateHosts ?? []).map((entry) => normalizeHostname(entry.toLowerCase()));
42320
+ if (allowlist.includes(hostname)) {
42321
+ const version2 = isIP(hostname);
42322
+ if (version2 === 4 || version2 === 6) {
42323
+ return { hostname, addresses: [hostname] };
42324
+ }
42325
+ const lookup2 = policy.lookup ?? defaultTargetLookup;
42326
+ let resolved2;
42327
+ try {
42328
+ resolved2 = await lookup2(hostname);
42329
+ } catch {
42330
+ throw new Error(`Webhook target ${hostname} could not be resolved`);
42331
+ }
42332
+ if (!Array.isArray(resolved2) || resolved2.length === 0) {
42333
+ throw new Error(`Webhook target ${hostname} resolved to no addresses`);
42334
+ }
42335
+ const addresses = resolved2.map((entry) => normalizeHostname(entry.address));
42336
+ return { hostname, addresses };
42337
+ }
42338
+ const version = isIP(hostname);
42339
+ if (version === 4 || version === 6) {
42340
+ if (isPrivateAddress(hostname)) {
42341
+ throw new Error(`Webhook target ${hostname} is a private or special-use address`);
42342
+ }
42343
+ return { hostname, addresses: [hostname] };
42344
+ }
42345
+ const lookup = policy.lookup ?? defaultTargetLookup;
42346
+ let resolved;
42347
+ try {
42348
+ resolved = await lookup(hostname);
42349
+ } catch {
42350
+ throw new Error(`Webhook target ${hostname} could not be resolved`);
42351
+ }
42352
+ if (!Array.isArray(resolved) || resolved.length === 0) {
42353
+ throw new Error(`Webhook target ${hostname} resolved to no addresses`);
42354
+ }
42355
+ const allowed = [];
42356
+ for (const entry of resolved) {
42357
+ const address = normalizeHostname(entry.address);
42358
+ if (isPrivateAddress(address)) {
42359
+ if (allowlist.includes(address)) {
42360
+ allowed.push(address);
42361
+ continue;
42362
+ }
42363
+ throw new Error(`Webhook target ${hostname} resolves to private or special-use address ${address}`);
42364
+ }
42365
+ allowed.push(address);
42366
+ }
42367
+ if (allowed.length === 0) {
42368
+ throw new Error(`Webhook target ${hostname} resolved to no public addresses`);
42369
+ }
42370
+ return { hostname, addresses: allowed };
42371
+ }
42372
+ function normalizeMaxRedirects(value) {
42373
+ if (value === undefined)
42374
+ return DEFAULT_MAX_REDIRECTS;
42375
+ if (!Number.isInteger(value) || value < 0)
42376
+ throw new Error("webhookTargetPolicy.maxRedirects must be a non-negative integer");
42377
+ return value;
42378
+ }
42379
+ var defaultTargetLookup = async (hostname) => {
42380
+ return dnsLookup(hostname, { all: true, verbatim: false });
42381
+ };
42382
+ function normalizeHostname(hostname) {
42383
+ const lower = hostname.toLowerCase();
42384
+ if (lower.startsWith("[") && lower.endsWith("]"))
42385
+ return lower.slice(1, -1);
42386
+ return lower;
42387
+ }
42388
+ function stripZoneId(address) {
42389
+ const percent = address.indexOf("%");
42390
+ return percent === -1 ? address : address.slice(0, percent);
42391
+ }
42392
+ function ipv4ToInt(address) {
42393
+ const parts = address.split(".");
42394
+ if (parts.length !== 4)
42395
+ return;
42396
+ let value = 0;
42397
+ for (const part of parts) {
42398
+ if (!/^\d{1,3}$/.test(part))
42399
+ return;
42400
+ const octet = Number(part);
42401
+ if (octet > 255)
42402
+ return;
42403
+ value = value << 8 | octet;
42404
+ }
42405
+ return value >>> 0;
42406
+ }
42407
+ function ipv4IntToString(integer) {
42408
+ return [
42409
+ integer >>> 24 & 255,
42410
+ integer >>> 16 & 255,
42411
+ integer >>> 8 & 255,
42412
+ integer & 255
42413
+ ].join(".");
42414
+ }
42415
+ function ipv6Groups(address) {
42416
+ const raw = stripZoneId(address);
42417
+ const doubleColon = raw.indexOf("::");
42418
+ const headText = doubleColon === -1 ? raw : raw.slice(0, doubleColon);
42419
+ const tailText = doubleColon === -1 ? "" : raw.slice(doubleColon + 2);
42420
+ const parseGroups = (text) => {
42421
+ if (text === "")
42422
+ return [];
42423
+ const out = [];
42424
+ for (const part of text.split(":")) {
42425
+ if (part.includes(".")) {
42426
+ const v4 = ipv4ToInt(part);
42427
+ if (v4 === undefined)
42428
+ return;
42429
+ out.push(v4 >>> 16 & 65535, v4 & 65535);
42430
+ } else {
42431
+ if (!/^[0-9a-fA-F]{1,4}$/.test(part))
42432
+ return;
42433
+ out.push(parseInt(part, 16));
42434
+ }
42435
+ }
42436
+ return out;
42437
+ };
42438
+ const head = parseGroups(headText);
42439
+ if (!head)
42440
+ return;
42441
+ const tail = parseGroups(tailText);
42442
+ if (!tail)
42443
+ return;
42444
+ const total = head.length + tail.length;
42445
+ if (doubleColon === -1) {
42446
+ return total === 8 ? head : undefined;
42447
+ }
42448
+ if (total >= 8)
42449
+ return;
42450
+ return [...head, ...new Array(8 - total).fill(0), ...tail];
42451
+ }
42452
+ function ipv6MatchesPrefix(groups, prefixGroups, prefixBits) {
42453
+ let remaining = prefixBits;
42454
+ for (let index = 0;index < prefixGroups.length && remaining > 0; index += 1) {
42455
+ const take = Math.min(16, remaining);
42456
+ const mask = 65535 << 16 - take & 65535;
42457
+ if ((groups[index] & mask) !== (prefixGroups[index] & mask))
42458
+ return false;
42459
+ remaining -= take;
42460
+ }
42461
+ return true;
42462
+ }
42153
42463
  function now() {
42154
42464
  return new Date().toISOString();
42155
42465
  }
@@ -42180,9 +42490,18 @@ function buildWebhookRequest(event, channel, options = {}) {
42180
42490
  }
42181
42491
  return { body, headers };
42182
42492
  }
42493
+ function normalizeWebhookUrl(raw) {
42494
+ const url = new URL(raw);
42495
+ if (url.username !== "" || url.password !== "") {
42496
+ url.username = "";
42497
+ url.password = "";
42498
+ }
42499
+ return url.toString();
42500
+ }
42183
42501
  async function dispatchWebhook(event, channel, options = {}) {
42184
42502
  if (!channel.webhook)
42185
42503
  throw new Error(`Channel ${channel.id} has no webhook config`);
42504
+ const webhookUrl = normalizeWebhookUrl(channel.webhook.url);
42186
42505
  const startedAt = now();
42187
42506
  let secret = channel.webhook.secret;
42188
42507
  if (channel.webhook.secretRef) {
@@ -42199,10 +42518,14 @@ async function dispatchWebhook(event, channel, options = {}) {
42199
42518
  }
42200
42519
  const timestamp = (options.now?.() ?? new Date).toISOString();
42201
42520
  const { body, headers } = buildWebhookRequest(event, channel, { secret, timestamp });
42521
+ const validateTargets = options.webhookTargetPolicy !== undefined || options.fetchImpl === undefined;
42522
+ if (validateTargets) {
42523
+ return dispatchValidatedWebhook(event, channel, { body, headers, startedAt, options });
42524
+ }
42202
42525
  const controller = new AbortController;
42203
42526
  const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
42204
42527
  try {
42205
- const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
42528
+ const response = await (options.fetchImpl ?? fetch)(webhookUrl, {
42206
42529
  method: "POST",
42207
42530
  headers,
42208
42531
  body,
@@ -42230,6 +42553,130 @@ async function dispatchWebhook(event, channel, options = {}) {
42230
42553
  clearTimeout(timeout);
42231
42554
  }
42232
42555
  }
42556
+ function isRedirectStatus(status) {
42557
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
42558
+ }
42559
+ function redirectKeepsBody(status) {
42560
+ return status === 307 || status === 308;
42561
+ }
42562
+ async function pinnedNativeRequest(target, addresses, method, headers, body, signal, tls) {
42563
+ const isHttps = target.protocol === "https:";
42564
+ if (!isHttps && target.protocol !== "http:") {
42565
+ throw new Error(`Webhook target uses unsupported protocol ${target.protocol}`);
42566
+ }
42567
+ const defaultPort = isHttps ? 443 : 80;
42568
+ const port = target.port ? Number(target.port) : defaultPort;
42569
+ const requestOptions = {
42570
+ hostname: target.hostname,
42571
+ port,
42572
+ path: `${target.pathname}${target.search}`,
42573
+ method,
42574
+ headers,
42575
+ ...tls?.ca ? { ca: tls.ca } : {},
42576
+ lookup: (hostname, _options, callback) => {
42577
+ const entries = addresses.map((address) => ({
42578
+ address,
42579
+ family: address.includes(":") ? 6 : 4
42580
+ }));
42581
+ callback(null, entries);
42582
+ }
42583
+ };
42584
+ return new Promise((resolve2, reject) => {
42585
+ const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
42586
+ const onAbort = () => {
42587
+ const error = new Error("The operation was aborted.");
42588
+ error.name = "AbortError";
42589
+ request.destroy(error);
42590
+ };
42591
+ if (signal.aborted)
42592
+ onAbort();
42593
+ else
42594
+ signal.addEventListener("abort", onAbort, { once: true });
42595
+ request.on("error", reject);
42596
+ if (body !== undefined)
42597
+ request.write(body);
42598
+ request.end();
42599
+ function onResponse(response) {
42600
+ const chunks = [];
42601
+ response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
42602
+ response.on("error", reject);
42603
+ response.on("end", () => {
42604
+ const headersRecord = {};
42605
+ for (const [name, value] of Object.entries(response.headers)) {
42606
+ if (typeof value === "string")
42607
+ headersRecord[name] = value;
42608
+ else if (Array.isArray(value))
42609
+ headersRecord[name] = value.join(", ");
42610
+ }
42611
+ resolve2(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
42612
+ });
42613
+ }
42614
+ });
42615
+ }
42616
+ async function dispatchValidatedWebhook(event, channel, input) {
42617
+ const { body, headers, startedAt, options } = input;
42618
+ const webhook = channel.webhook;
42619
+ if (!webhook)
42620
+ throw new Error(`Channel ${channel.id} has no webhook config`);
42621
+ const policy = options.webhookTargetPolicy ?? {};
42622
+ const maxRedirects = normalizeMaxRedirects(policy.maxRedirects);
42623
+ const controller = new AbortController;
42624
+ const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs ?? 15000);
42625
+ try {
42626
+ let target = new URL(normalizeWebhookUrl(webhook.url));
42627
+ let requestHeaders = headers;
42628
+ let method = "POST";
42629
+ let requestBody = body;
42630
+ let redirectsFollowed = 0;
42631
+ for (;; ) {
42632
+ const resolved = await resolveWebhookTarget(target, policy).catch((error) => {
42633
+ throw new Error(`Webhook target rejected by SSRF guard: ${error.message}`);
42634
+ });
42635
+ const response = options.fetchImpl ? await options.fetchImpl(target, {
42636
+ method,
42637
+ headers: requestHeaders,
42638
+ body: requestBody,
42639
+ signal: controller.signal,
42640
+ redirect: "manual"
42641
+ }) : await pinnedNativeRequest(target, resolved.addresses, method, requestHeaders, requestBody, controller.signal, options.tls);
42642
+ const location = response.headers.get("location");
42643
+ if (isRedirectStatus(response.status) && location) {
42644
+ if (redirectsFollowed >= maxRedirects) {
42645
+ return failedAttempt(startedAt, `Webhook target exceeded ${maxRedirects} redirects`);
42646
+ }
42647
+ redirectsFollowed += 1;
42648
+ const next = new URL(location, target);
42649
+ target = next;
42650
+ if (!redirectKeepsBody(response.status)) {
42651
+ method = "GET";
42652
+ requestBody = undefined;
42653
+ requestHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => name.toLowerCase() !== "content-type" && name.toLowerCase() !== "content-length"));
42654
+ }
42655
+ continue;
42656
+ }
42657
+ const responseBody = truncate(await response.text());
42658
+ return {
42659
+ attempt: 1,
42660
+ status: response.ok ? "success" : "failed",
42661
+ startedAt,
42662
+ completedAt: now(),
42663
+ responseStatus: response.status,
42664
+ responseBody,
42665
+ error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
42666
+ };
42667
+ }
42668
+ } catch (error) {
42669
+ return {
42670
+ attempt: 1,
42671
+ status: "failed",
42672
+ startedAt,
42673
+ completedAt: now(),
42674
+ error: error instanceof Error ? error.message : String(error)
42675
+ };
42676
+ } finally {
42677
+ clearTimeout(timeout);
42678
+ }
42679
+ }
42233
42680
  function failedAttempt(startedAt, error) {
42234
42681
  return {
42235
42682
  attempt: 1,
@@ -42258,7 +42705,7 @@ async function dispatchCommand(event, channel) {
42258
42705
  HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
42259
42706
  HASNA_EVENT_JSON: eventJson
42260
42707
  };
42261
- return new Promise((resolve) => {
42708
+ return new Promise((resolve2) => {
42262
42709
  const child = spawn(channel.command.command, channel.command.args ?? [], {
42263
42710
  cwd: channel.command.cwd,
42264
42711
  env,
@@ -42276,7 +42723,7 @@ async function dispatchCommand(event, channel) {
42276
42723
  });
42277
42724
  child.on("error", (error) => {
42278
42725
  clearTimeout(timeout);
42279
- resolve({
42726
+ resolve2({
42280
42727
  attempt: 1,
42281
42728
  status: "failed",
42282
42729
  startedAt,
@@ -42289,7 +42736,7 @@ async function dispatchCommand(event, channel) {
42289
42736
  child.on("close", (code, signal) => {
42290
42737
  clearTimeout(timeout);
42291
42738
  const success = code === 0;
42292
- resolve({
42739
+ resolve2({
42293
42740
  attempt: 1,
42294
42741
  status: success ? "success" : "failed",
42295
42742
  startedAt,
@@ -42411,6 +42858,22 @@ function setPath(input, path, replacement) {
42411
42858
  if (last && last in cursor)
42412
42859
  cursor[last] = replacement;
42413
42860
  }
42861
+ var MAX_PACKAGE_BYTES = 1024 * 1024;
42862
+ var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
42863
+ var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
42864
+ var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
42865
+ var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
42866
+ var requireSecretsSdk = createRequire(import.meta.url);
42867
+ var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
42868
+ var AUTHORITY_OVERRIDE_HEADERS = new Set([
42869
+ "host",
42870
+ ":authority",
42871
+ "forwarded",
42872
+ "x-forwarded-host",
42873
+ "x-original-host"
42874
+ ]);
42875
+ var MAX_ENVELOPE_BYTES = 256 * 1024;
42876
+ var MAX_REQUEST_BYTES = MAX_ENVELOPE_BYTES * 2 + 8192;
42414
42877
  function createEvent(input) {
42415
42878
  return {
42416
42879
  id: input.id ?? randomUUID2(),
@@ -42439,7 +42902,9 @@ class EventsClient {
42439
42902
  this.transportOptions = {
42440
42903
  fetchImpl: options.fetchImpl,
42441
42904
  secretResolver: options.secretResolver,
42442
- now: options.now
42905
+ now: options.now,
42906
+ tls: options.tls,
42907
+ webhookTargetPolicy: options.webhookTargetPolicy
42443
42908
  };
42444
42909
  this.catalog = options.catalog ?? defaultEventTypeCatalog;
42445
42910
  this.validateCatalogTypes = options.validateCatalogTypes ?? false;
@@ -42726,6 +43191,13 @@ function parseMatcherExpression(value, label) {
42726
43191
  negated: false
42727
43192
  };
42728
43193
  }
43194
+ function webhookTargetPolicyFromEnv() {
43195
+ const value = process.env.HASNA_EVENTS_ALLOW_PRIVATE_WEBHOOK_TARGETS;
43196
+ if (!value)
43197
+ return;
43198
+ const hosts = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
43199
+ return hosts.length > 0 ? { allowPrivateHosts: hosts } : undefined;
43200
+ }
42729
43201
  var DEFAULT_EVENT_LIST_LIMIT = 100;
42730
43202
  function parseJsonObject(value, fallback) {
42731
43203
  if (!value)
@@ -42751,7 +43223,7 @@ function parseHeaders(values) {
42751
43223
  function createClient(options) {
42752
43224
  if (options.createClient)
42753
43225
  return options.createClient();
42754
- return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
43226
+ return new EventsClient({ store: new JsonEventsStore(options.dataDir), webhookTargetPolicy: webhookTargetPolicyFromEnv() });
42755
43227
  }
42756
43228
  function print(value, json, text) {
42757
43229
  if (json)
@@ -42832,6 +43304,8 @@ function registerChannelCommands(program, options) {
42832
43304
  metadata: parseJsonObject(actionOptions.metadata, {})
42833
43305
  }, { honorFilters: actionOptions.honorFilters });
42834
43306
  print(result, json, `${result.status}: ${result.channelId}`);
43307
+ if (result.status === "failed")
43308
+ process.exitCode = 1;
42835
43309
  } catch (error) {
42836
43310
  fail(error, json);
42837
43311
  }
@@ -42924,7 +43398,7 @@ function replaySummary(events, deliveries, nextCursor) {
42924
43398
  // src/cli/index.tsx
42925
43399
  import { render } from "ink";
42926
43400
 
42927
- // ../hooks0102-standalone-lock/node_modules/commander/esm.mjs
43401
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
42928
43402
  var import__ = __toESM(require_commander(), 1);
42929
43403
  var {
42930
43404
  program,
@@ -42942,19 +43416,19 @@ var {
42942
43416
 
42943
43417
  // src/cli/index.tsx
42944
43418
  import chalk2 from "chalk";
42945
- import { existsSync as existsSync16, readFileSync as readFileSync20, rmSync as rmSync6 } from "fs";
42946
- import { join as join24, dirname as dirname22 } from "path";
43419
+ import { existsSync as existsSync19, readFileSync as readFileSync23, rmSync as rmSync6 } from "fs";
43420
+ import { join as join31, dirname as dirname24 } from "path";
42947
43421
  import { fileURLToPath as fileURLToPath6 } from "url";
42948
43422
 
42949
43423
  // src/cli/components/App.tsx
42950
43424
  import { useState as useState7 } from "react";
42951
43425
  import { Box as Box8, Text as Text10, useApp, useInput as useInput5 } from "ink";
42952
43426
 
42953
- // ../hooks0102-standalone-lock/node_modules/ink-select-input/build/Indicator.js
43427
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
42954
43428
  import React from "react";
42955
43429
  import { Box, Text } from "ink";
42956
43430
 
42957
- // ../hooks0102-standalone-lock/node_modules/is-unicode-supported/index.js
43431
+ // ../../node_modules/.bun/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
42958
43432
  import process2 from "process";
42959
43433
  function isUnicodeSupported() {
42960
43434
  const { env } = process2;
@@ -42965,7 +43439,7 @@ function isUnicodeSupported() {
42965
43439
  return Boolean(env.WT_SESSION) || Boolean(env.TERMINUS_SUBLIME) || env.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
42966
43440
  }
42967
43441
 
42968
- // ../hooks0102-standalone-lock/node_modules/figures/index.js
43442
+ // ../../node_modules/.bun/figures@6.1.0/node_modules/figures/index.js
42969
43443
  var common = {
42970
43444
  circleQuestionMark: "(?)",
42971
43445
  questionMarkPrefix: "(?)",
@@ -43241,23 +43715,23 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
43241
43715
  var figures_default = figures;
43242
43716
  var replacements = Object.entries(specialMainSymbols);
43243
43717
 
43244
- // ../hooks0102-standalone-lock/node_modules/ink-select-input/build/Indicator.js
43718
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
43245
43719
  function Indicator({ isSelected = false }) {
43246
43720
  return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures_default.pointer) : React.createElement(Text, null, " "));
43247
43721
  }
43248
43722
  var Indicator_default = Indicator;
43249
- // ../hooks0102-standalone-lock/node_modules/ink-select-input/build/Item.js
43723
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Item.js
43250
43724
  import * as React2 from "react";
43251
43725
  import { Text as Text2 } from "ink";
43252
43726
  function Item({ isSelected = false, label }) {
43253
43727
  return React2.createElement(Text2, { color: isSelected ? "blue" : undefined }, label);
43254
43728
  }
43255
43729
  var Item_default = Item;
43256
- // ../hooks0102-standalone-lock/node_modules/ink-select-input/build/SelectInput.js
43730
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
43257
43731
  import { isDeepStrictEqual } from "util";
43258
43732
  import React3, { useState, useEffect, useRef, useCallback } from "react";
43259
43733
 
43260
- // ../hooks0102-standalone-lock/node_modules/to-rotated/index.js
43734
+ // ../../node_modules/.bun/to-rotated@1.0.0/node_modules/to-rotated/index.js
43261
43735
  function toRotated(array, steps) {
43262
43736
  if (!Array.isArray(array)) {
43263
43737
  throw new TypeError(`Expected an array, got \`${typeof array}\`.`);
@@ -43279,7 +43753,7 @@ function toRotated(array, steps) {
43279
43753
  ];
43280
43754
  }
43281
43755
 
43282
- // ../hooks0102-standalone-lock/node_modules/ink-select-input/build/SelectInput.js
43756
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
43283
43757
  import { Box as Box2, useInput } from "ink";
43284
43758
  function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator_default, itemComponent = Item_default, limit: customLimit, onSelect, onHighlight }) {
43285
43759
  const hasLimit = typeof customLimit === "number" && items.length > customLimit;
@@ -43575,7 +44049,7 @@ function HookSelect({
43575
44049
  import { useState as useState4, useEffect as useEffect3 } from "react";
43576
44050
  import { Box as Box6, Text as Text7, useInput as useInput4 } from "ink";
43577
44051
 
43578
- // ../hooks0102-standalone-lock/node_modules/ink-text-input/build/index.js
44052
+ // ../../node_modules/.bun/ink-text-input@6.0.0+fa875fef9f949ebd/node_modules/ink-text-input/build/index.js
43579
44053
  import React5, { useState as useState3, useEffect as useEffect2 } from "react";
43580
44054
  import { Text as Text6, useInput as useInput3 } from "ink";
43581
44055
  import chalk from "chalk";
@@ -43753,7 +44227,7 @@ function SearchView({
43753
44227
  import { useState as useState6, useEffect as useEffect5 } from "react";
43754
44228
  import { Box as Box7, Text as Text9 } from "ink";
43755
44229
 
43756
- // ../hooks0102-standalone-lock/node_modules/ink-spinner/build/index.js
44230
+ // ../../node_modules/.bun/ink-spinner@5.0.0+fa875fef9f949ebd/node_modules/ink-spinner/build/index.js
43757
44231
  var import_cli_spinners = __toESM(require_cli_spinners(), 1);
43758
44232
  import React7, { useState as useState5, useEffect as useEffect4 } from "react";
43759
44233
  import { Text as Text8 } from "ink";
@@ -44117,6 +44591,403 @@ function App({ initialHooks, overwrite = false }) {
44117
44591
 
44118
44592
  // src/cli/index.tsx
44119
44593
  init_native_safety();
44594
+
44595
+ // src/native-safety.ts
44596
+ init_native_safety();
44597
+ import { execFile } from "child_process";
44598
+ import { createHash as createHash7, randomUUID as randomUUID5 } from "crypto";
44599
+ import { closeSync as closeSync4, constants as constants3, existsSync as existsSync14, fstatSync as fstatSync3, fsyncSync, linkSync as linkSync3, lstatSync as lstatSync7, mkdirSync as mkdirSync9, openSync as openSync4, readFileSync as readFileSync9, realpathSync as realpathSync7, renameSync as renameSync3, unlinkSync as unlinkSync5, writeFileSync as writeFileSync8 } from "fs";
44600
+ import { homedir as homedir7 } from "os";
44601
+ import { dirname as dirname11, isAbsolute as isAbsolute7, join as join13, resolve as resolve15 } from "path";
44602
+
44603
+ class NativeSafetyError extends Error {
44604
+ code;
44605
+ reason;
44606
+ constructor(code2, reason) {
44607
+ super(`Native deletion safety refused (${code2}). Run the reviewed Hooks safety setup before using shell or patch tools.`);
44608
+ this.code = code2;
44609
+ this.reason = reason;
44610
+ this.name = "NativeSafetyError";
44611
+ }
44612
+ }
44613
+ var hash = (value) => createHash7("sha256").update(value).digest("hex");
44614
+ var filename = "sumi-trash-guard.json";
44615
+ var owner2 = (uid2) => uid2 === 0 || uid2 === process.getuid?.();
44616
+ function safeDirectory(path) {
44617
+ for (let cursor = path;; cursor = dirname11(cursor)) {
44618
+ const stat2 = lstatSync7(cursor);
44619
+ if (!stat2.isDirectory() || !owner2(stat2.uid) || stat2.mode & 18)
44620
+ throw new NativeSafetyError("binding_invalid");
44621
+ if (dirname11(cursor) === cursor)
44622
+ return;
44623
+ }
44624
+ }
44625
+ function canonicalHome(home) {
44626
+ if (!isAbsolute7(home) || home.includes("\x00") || realpathSync7(home) !== resolve15(home))
44627
+ throw new NativeSafetyError("binding_invalid");
44628
+ safeDirectory(home);
44629
+ return resolve15(home);
44630
+ }
44631
+ function readOwned(path) {
44632
+ safeDirectory(dirname11(path));
44633
+ const fd = openSync4(path, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
44634
+ try {
44635
+ const stat2 = fstatSync3(fd);
44636
+ if (!stat2.isFile() || !owner2(stat2.uid) || stat2.mode & 63 || stat2.size > 32768)
44637
+ throw new NativeSafetyError("binding_invalid");
44638
+ const value = readFileSync9(fd, "utf8");
44639
+ if (Buffer.byteLength(value) > 32768)
44640
+ throw new NativeSafetyError("binding_invalid");
44641
+ return value;
44642
+ } finally {
44643
+ closeSync4(fd);
44644
+ }
44645
+ }
44646
+ function parseRecord(text3, home) {
44647
+ const record3 = JSON.parse(text3);
44648
+ if (!record3 || Array.isArray(record3) || Object.keys(record3).sort().join() !== "command,harness,schema" || record3.schema !== "hasna.hooks.native-safety.v1" || record3.harness !== "sumi" || typeof record3.command !== "string")
44649
+ throw new NativeSafetyError("binding_invalid");
44650
+ const binding = nativeSafetyCommandBinding(record3.command);
44651
+ if (binding?.name !== "trash-guard" || binding.home !== home)
44652
+ throw new NativeSafetyError("binding_invalid");
44653
+ return record3;
44654
+ }
44655
+ function syncDirectory(path) {
44656
+ const fd = openSync4(path, constants3.O_RDONLY | constants3.O_DIRECTORY | constants3.O_NOFOLLOW);
44657
+ try {
44658
+ fsyncSync(fd);
44659
+ } finally {
44660
+ closeSync4(fd);
44661
+ }
44662
+ }
44663
+ function readNativeSafetyRegistration(home = homedir7()) {
44664
+ try {
44665
+ home = canonicalHome(home);
44666
+ const path = join13(home, ".hasna/hooks/native", filename), text3 = readOwned(path);
44667
+ return { record: parseRecord(text3, home), sha256: hash(text3), path };
44668
+ } catch (error61) {
44669
+ if (error61 instanceof NativeSafetyError)
44670
+ throw error61;
44671
+ throw new NativeSafetyError(error61?.code === "ENOENT" ? "binding_missing" : "binding_invalid");
44672
+ }
44673
+ }
44674
+ function registerNativeSafety(options = {}) {
44675
+ const home = canonicalHome(options.home ?? homedir7());
44676
+ const record3 = { schema: "hasna.hooks.native-safety.v1", harness: "sumi", command: options.command ?? installedNativeSafetyCommand("trash-guard") };
44677
+ const text3 = JSON.stringify(record3) + `
44678
+ `;
44679
+ parseRecord(text3, home);
44680
+ for (const dir of [join13(home, ".hasna"), join13(home, ".hasna/hooks"), join13(home, ".hasna/hooks/native")]) {
44681
+ try {
44682
+ mkdirSync9(dir, { mode: 448 });
44683
+ syncDirectory(dirname11(dir));
44684
+ } catch (error61) {
44685
+ if (error61.code !== "EEXIST")
44686
+ throw error61;
44687
+ }
44688
+ safeDirectory(dir);
44689
+ }
44690
+ const directory2 = join13(home, ".hasna/hooks/native"), path = join13(directory2, filename), lock = path + ".lock";
44691
+ let lockFD;
44692
+ try {
44693
+ lockFD = openSync4(lock, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
44694
+ } catch {
44695
+ throw new NativeSafetyError("binding_busy");
44696
+ }
44697
+ const lockIdentity = fstatSync3(lockFD);
44698
+ let temporaryIdentity;
44699
+ const temporary = join13(directory2, `.${filename}.${randomUUID5()}`);
44700
+ try {
44701
+ writeFileSync8(lockFD, JSON.stringify({ pid: process.pid, expectedSHA256: options.expectedSHA256 ?? "absent" }));
44702
+ fsyncSync(lockFD);
44703
+ syncDirectory(directory2);
44704
+ let before;
44705
+ try {
44706
+ before = readNativeSafetyRegistration(home);
44707
+ } catch (error61) {
44708
+ if (!(error61 instanceof NativeSafetyError) || error61.code !== "binding_missing")
44709
+ throw error61;
44710
+ }
44711
+ if (before?.sha256 === hash(text3))
44712
+ return { ok: true, changed: false, path, sha256: before.sha256 };
44713
+ if (before ? options.expectedSHA256 !== before.sha256 : options.expectedSHA256 !== undefined && options.expectedSHA256 !== "absent")
44714
+ throw new NativeSafetyError("binding_changed");
44715
+ if (before) {
44716
+ const backup = path + ".before-" + before.sha256;
44717
+ if (existsSync14(backup)) {
44718
+ if (hash(readOwned(backup)) !== before.sha256)
44719
+ throw new NativeSafetyError("binding_changed");
44720
+ } else {
44721
+ const original = readOwned(path);
44722
+ if (hash(original) !== before.sha256)
44723
+ throw new NativeSafetyError("binding_changed");
44724
+ const fd2 = openSync4(backup, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
44725
+ try {
44726
+ writeFileSync8(fd2, original);
44727
+ fsyncSync(fd2);
44728
+ } finally {
44729
+ closeSync4(fd2);
44730
+ }
44731
+ syncDirectory(directory2);
44732
+ }
44733
+ }
44734
+ const fd = openSync4(temporary, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
44735
+ try {
44736
+ temporaryIdentity = fstatSync3(fd);
44737
+ writeFileSync8(fd, text3);
44738
+ fsyncSync(fd);
44739
+ } finally {
44740
+ closeSync4(fd);
44741
+ }
44742
+ if (before) {
44743
+ if (hash(readOwned(path)) !== before.sha256)
44744
+ throw new NativeSafetyError("binding_changed");
44745
+ renameSync3(temporary, path);
44746
+ } else {
44747
+ linkSync3(temporary, path);
44748
+ unlinkSync5(temporary);
44749
+ }
44750
+ syncDirectory(directory2);
44751
+ const after = readNativeSafetyRegistration(home);
44752
+ if (after.sha256 !== hash(text3))
44753
+ throw new NativeSafetyError("binding_changed");
44754
+ return { ok: true, changed: true, path, sha256: after.sha256 };
44755
+ } finally {
44756
+ closeSync4(lockFD);
44757
+ const currentTemporary = lstatSync7(temporary, { throwIfNoEntry: false });
44758
+ if (temporaryIdentity && currentTemporary?.dev === temporaryIdentity.dev && currentTemporary.ino === temporaryIdentity.ino)
44759
+ unlinkSync5(temporary);
44760
+ const currentLock = lstatSync7(lock, { throwIfNoEntry: false });
44761
+ if (currentLock?.dev !== lockIdentity.dev || currentLock.ino !== lockIdentity.ino)
44762
+ throw new NativeSafetyError("binding_changed");
44763
+ unlinkSync5(lock);
44764
+ syncDirectory(directory2);
44765
+ }
44766
+ }
44767
+ async function evaluateRecord(event, record3, signal) {
44768
+ if (!event || event.hook_event_name !== "PreToolUse" || !["Bash", "apply_patch"].includes(event.tool_name) || typeof event.cwd !== "string" || !isAbsolute7(event.cwd) || !event.tool_input || typeof event.tool_input !== "object" || Array.isArray(event.tool_input))
44769
+ throw new NativeSafetyError("input_invalid");
44770
+ const input2 = JSON.stringify(event);
44771
+ if (Buffer.byteLength(input2) > 1048576)
44772
+ throw new NativeSafetyError("input_invalid");
44773
+ const output2 = await new Promise((accept, reject) => {
44774
+ const child = execFile("/bin/sh", ["-c", record3.command], { cwd: "/", env: {}, encoding: "utf8", timeout: 8000, maxBuffer: 1048576, signal }, (error61, stdout, stderr) => {
44775
+ if (error61 || stderr) {
44776
+ reject(new NativeSafetyError("guard_failed"));
44777
+ return;
44778
+ }
44779
+ accept(stdout);
44780
+ });
44781
+ child.stdin?.on("error", () => {});
44782
+ child.stdin?.end(input2);
44783
+ });
44784
+ if (!output2)
44785
+ return { decision: "continue" };
44786
+ try {
44787
+ const value = JSON.parse(output2);
44788
+ if (Object.keys(value).join() !== "hookSpecificOutput")
44789
+ throw new Error;
44790
+ const verdict = value.hookSpecificOutput;
44791
+ if (verdict.hookEventName !== "PreToolUse")
44792
+ throw new Error;
44793
+ if (verdict.permissionDecision === "deny" && Object.keys(verdict).sort().join() === "hookEventName,permissionDecision,permissionDecisionReason" && typeof verdict.permissionDecisionReason === "string" && verdict.permissionDecisionReason.trim())
44794
+ return { decision: "deny", reason: verdict.permissionDecisionReason };
44795
+ if (event.tool_name === "Bash" && verdict.permissionDecision === "allow" && Object.keys(verdict).sort().join() === "hookEventName,permissionDecision,updatedInput" && typeof verdict.updatedInput?.command === "string" && verdict.updatedInput.command.trim())
44796
+ return { decision: "rewrite", command: verdict.updatedInput.command };
44797
+ } catch {}
44798
+ throw new NativeSafetyError("guard_failed");
44799
+ }
44800
+ async function verifyNativeSafetyCommand(command, home = homedir7()) {
44801
+ home = canonicalHome(home);
44802
+ const record3 = parseRecord(JSON.stringify({ schema: "hasna.hooks.native-safety.v1", harness: "sumi", command }), home);
44803
+ const verdict = await evaluateRecord({ hook_event_name: "PreToolUse", tool_name: "Bash", cwd: home, tool_input: { command: "rm -- .hasna-trash-verification-only" } }, record3);
44804
+ if (verdict.decision !== "rewrite")
44805
+ throw new NativeSafetyError("guard_failed", verdict.decision === "deny" ? verdict.reason.slice(0, 512) : undefined);
44806
+ }
44807
+ async function verifyNativeSafetyRegistration(home = homedir7()) {
44808
+ const before = readNativeSafetyRegistration(home);
44809
+ await verifyNativeSafetyCommand(before.record.command, home);
44810
+ const after = readNativeSafetyRegistration(home);
44811
+ if (after.sha256 !== before.sha256)
44812
+ throw new NativeSafetyError("binding_changed");
44813
+ return { path: before.path, sha256: before.sha256 };
44814
+ }
44815
+
44816
+ // hooks/hook-trash-guard/src/binary.ts
44817
+ import { dirname as dirname17, isAbsolute as isAbsolute15, join as join17, resolve as resolve17 } from "path";
44818
+ import { accessSync, closeSync as closeSync5, constants as constants4, fstatSync as fstatSync4, lstatSync as lstatSync9, openSync as openSync5, readFileSync as readFileSync12, readlinkSync as readlinkSync3, readSync as readSync2, realpathSync as realpathSync8, statSync } from "fs";
44819
+ import { spawnSync } from "child_process";
44820
+ function trustedOwner(uid2) {
44821
+ return uid2 === 0 || uid2 === process.getuid?.();
44822
+ }
44823
+ function safeExecutableFile(path, systemBinAlias = false) {
44824
+ let current2 = path;
44825
+ for (let hop = 0;hop < 32; hop++) {
44826
+ if (!isAbsolute15(current2) || current2.length > 4096 || !safeBinaryDirectory("/"))
44827
+ return false;
44828
+ const parts = current2.split("/"), name = parts.pop();
44829
+ if (!name || name === "." || name === "..")
44830
+ return false;
44831
+ let parent = "/";
44832
+ for (const part of parts) {
44833
+ if (!part || part === ".")
44834
+ continue;
44835
+ if (part === "..") {
44836
+ parent = dirname17(parent);
44837
+ continue;
44838
+ }
44839
+ const next = join17(parent, part), info2 = lstatSync9(next);
44840
+ if (systemBinAlias && next === "/bin" && info2.isSymbolicLink() && info2.uid === 0) {
44841
+ const target = realpathSync8(next);
44842
+ if (!safeBinaryDirectory(target))
44843
+ return false;
44844
+ parent = target;
44845
+ continue;
44846
+ }
44847
+ if (!info2.isDirectory() || !trustedOwner(info2.uid) || info2.mode & 18)
44848
+ return false;
44849
+ parent = next;
44850
+ }
44851
+ const candidate = join17(parent, name), info = lstatSync9(candidate);
44852
+ if (!trustedOwner(info.uid))
44853
+ return false;
44854
+ if (info.isSymbolicLink()) {
44855
+ const target = readlinkSync3(candidate);
44856
+ current2 = isAbsolute15(target) ? target : parent + "/" + target;
44857
+ continue;
44858
+ }
44859
+ return info.isFile() && Boolean(info.mode & 73) && !(info.mode & 18);
44860
+ }
44861
+ return false;
44862
+ }
44863
+ function safeInterpreterSearchDirectory(path) {
44864
+ if (!isAbsolute15(path) || resolve17(path) !== (path.replace(/\/+$/, "") || "/"))
44865
+ return false;
44866
+ for (let cursor = resolve17(path);; cursor = dirname17(cursor)) {
44867
+ try {
44868
+ lstatSync9(cursor);
44869
+ return safeBinaryDirectory(cursor);
44870
+ } catch (error61) {
44871
+ if (error61.code !== "ENOENT")
44872
+ return false;
44873
+ }
44874
+ if (dirname17(cursor) === cursor)
44875
+ return false;
44876
+ }
44877
+ }
44878
+ function safeScriptInterpreter(executable, pathValue) {
44879
+ const fd = openSync5(executable, constants4.O_RDONLY | constants4.O_NONBLOCK | constants4.O_NOFOLLOW);
44880
+ let header;
44881
+ try {
44882
+ if (!fstatSync4(fd).isFile())
44883
+ return false;
44884
+ const bytes = Buffer.alloc(256), length = readSync2(fd, bytes, 0, bytes.length, 0);
44885
+ header = bytes.subarray(0, length).toString("utf8").split(`
44886
+ `)[0];
44887
+ } finally {
44888
+ closeSync5(fd);
44889
+ }
44890
+ const direct = /^#!(\/[A-Za-z0-9_./-]+)$/.exec(header);
44891
+ if (direct && direct[1] !== "/usr/bin/env")
44892
+ return safeExecutableFile(direct[1], true);
44893
+ if (header !== "#!/usr/bin/env bun" || !safeExecutableFile("/usr/bin/env", true))
44894
+ return false;
44895
+ for (const dir of pathValue.split(":").slice(0, 64)) {
44896
+ if (!safeInterpreterSearchDirectory(dir))
44897
+ return false;
44898
+ const interpreter = resolve17(dir, "bun");
44899
+ try {
44900
+ if (!statSync(interpreter).isFile())
44901
+ continue;
44902
+ accessSync(interpreter, constants4.X_OK);
44903
+ } catch {
44904
+ continue;
44905
+ }
44906
+ return safeExecutableFile(interpreter, true);
44907
+ }
44908
+ return false;
44909
+ }
44910
+ function safeBinaryDirectory(path) {
44911
+ let current2 = path;
44912
+ for (;; ) {
44913
+ const info = lstatSync9(current2);
44914
+ if (!info.isDirectory() || !trustedOwner(info.uid) || (info.mode & 18) !== 0)
44915
+ return false;
44916
+ const parent = dirname17(current2);
44917
+ if (parent === current2)
44918
+ return true;
44919
+ current2 = parent;
44920
+ }
44921
+ }
44922
+ function inspectTrashBinary(env = process.env) {
44923
+ const pathValue = env.PATH ?? "";
44924
+ const deadline = Date.now() + 2000;
44925
+ let failure = "missing";
44926
+ const reject = (code2) => {
44927
+ if (failure === "missing" || failure === "unrecognized_package" || code2.startsWith("unsafe_"))
44928
+ failure = code2;
44929
+ };
44930
+ for (const dir of pathValue.split(":").slice(0, 64)) {
44931
+ if (!isAbsolute15(dir) || Date.now() >= deadline)
44932
+ continue;
44933
+ const candidate = resolve17(dir, "trash");
44934
+ try {
44935
+ const stat2 = statSync(candidate);
44936
+ if (!stat2.isFile() || !trustedOwner(stat2.uid) || (stat2.mode & 73) === 0 || (stat2.mode & 18) !== 0) {
44937
+ reject("unsafe_executable");
44938
+ continue;
44939
+ }
44940
+ const executable = realpathSync8(candidate);
44941
+ if (!safeBinaryDirectory(resolve17(dir)) || !safeBinaryDirectory(dirname17(executable))) {
44942
+ reject("unsafe_directory");
44943
+ continue;
44944
+ }
44945
+ if (!safeExecutableFile(candidate)) {
44946
+ reject("unsafe_directory");
44947
+ continue;
44948
+ }
44949
+ const packageRoot = resolve17(dirname17(executable), "../..");
44950
+ const manifestPath = join17(packageRoot, "package.json");
44951
+ const manifestStat = statSync(manifestPath);
44952
+ if (!manifestStat.isFile() || !trustedOwner(manifestStat.uid) || manifestStat.size > 16384 || (manifestStat.mode & 18) !== 0 || lstatSync9(manifestPath).isSymbolicLink()) {
44953
+ reject("unsafe_manifest");
44954
+ continue;
44955
+ }
44956
+ const manifest = JSON.parse(readFileSync12(manifestPath, "utf8"));
44957
+ if (manifest.name !== "@hasna/trash" || typeof manifest.version !== "string" || typeof manifest.bin?.trash !== "string" || realpathSync8(resolve17(packageRoot, manifest.bin.trash)) !== executable) {
44958
+ reject("unrecognized_package");
44959
+ continue;
44960
+ }
44961
+ try {
44962
+ if (!safeScriptInterpreter(executable, pathValue)) {
44963
+ reject("unsafe_interpreter");
44964
+ continue;
44965
+ }
44966
+ } catch {
44967
+ reject("unsafe_interpreter");
44968
+ continue;
44969
+ }
44970
+ const probe = spawnSync(candidate, ["--identity"], {
44971
+ encoding: "utf8",
44972
+ timeout: Math.max(1, Math.min(500, deadline - Date.now())),
44973
+ maxBuffer: 2048,
44974
+ env: { PATH: pathValue },
44975
+ stdio: ["ignore", "pipe", "pipe"]
44976
+ });
44977
+ if (probe.error || probe.status !== 0) {
44978
+ reject("identity_failed");
44979
+ continue;
44980
+ }
44981
+ const identity3 = JSON.parse(probe.stdout);
44982
+ if (identity3.name === "@hasna/trash" && identity3.version === manifest.version && identity3.guardProtocol === "hasna.trash.guard.v1")
44983
+ return { ok: true, path: candidate, version: manifest.version };
44984
+ reject("unsupported_protocol");
44985
+ } catch {}
44986
+ }
44987
+ return { ok: false, code: failure };
44988
+ }
44989
+
44990
+ // src/cli/index.tsx
44120
44991
  init_registry();
44121
44992
  init_installer();
44122
44993
  init_registration();
@@ -44132,9 +45003,9 @@ init_local_opt_in();
44132
45003
  init_transport2();
44133
45004
  init_db();
44134
45005
  import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
44135
- var __dirname4 = dirname22(fileURLToPath6(import.meta.url));
44136
- var pkgPath = existsSync16(join24(__dirname4, "..", "package.json")) ? join24(__dirname4, "..", "package.json") : join24(__dirname4, "..", "..", "package.json");
44137
- var pkg2 = JSON.parse(readFileSync20(pkgPath, "utf-8"));
45006
+ var __dirname4 = dirname24(fileURLToPath6(import.meta.url));
45007
+ var pkgPath = existsSync19(join31(__dirname4, "..", "package.json")) ? join31(__dirname4, "..", "package.json") : join31(__dirname4, "..", "..", "package.json");
45008
+ var pkg2 = JSON.parse(readFileSync23(pkgPath, "utf-8"));
44138
45009
  var program3 = new Command;
44139
45010
  function resolveScope(options) {
44140
45011
  if (options.project)
@@ -44214,7 +45085,7 @@ async function openLocalStoreOrExit(json3) {
44214
45085
  function readToken(tokenFile) {
44215
45086
  if (tokenFile) {
44216
45087
  try {
44217
- return readFileSync20(tokenFile, "utf-8").trim();
45088
+ return readFileSync23(tokenFile, "utf-8").trim();
44218
45089
  } catch {
44219
45090
  return;
44220
45091
  }
@@ -44352,7 +45223,7 @@ program3.command("init").description("Register a new agent profile with a unique
44352
45223
  if (profile.name) {
44353
45224
  console.log(` ${chalk2.dim("Name:")} ${profile.name}`);
44354
45225
  }
44355
- console.log(` ${chalk2.dim("Profile:")} ${join24(getProfilesDir(), `${profile.agent_id}.json`)}`);
45226
+ console.log(` ${chalk2.dim("Profile:")} ${join31(getProfilesDir(), `${profile.agent_id}.json`)}`);
44356
45227
  console.log();
44357
45228
  console.log(chalk2.dim(" Install hooks with this profile:"));
44358
45229
  console.log(` hooks install gitguard --profile ${profile.agent_id}`);
@@ -44376,11 +45247,11 @@ program3.command("run").argument("<hook>", "Hook to run").option("--profile <id>
44376
45247
  process.exit(1);
44377
45248
  }
44378
45249
  const hookScript = resolveScriptPath2(hook);
44379
- if (!hookScript || !existsSync16(hookScript)) {
45250
+ if (!hookScript || !existsSync19(hookScript)) {
44380
45251
  console.error(JSON.stringify({ error: `Hook script not found: ${hookScript ?? hook}` }));
44381
45252
  process.exit(1);
44382
45253
  }
44383
- const content = readFileSync20(hookScript);
45254
+ const content = readFileSync23(hookScript);
44384
45255
  const sha4 = sha256Of2(content);
44385
45256
  const check2 = checkScriptHash2(hook, sha4);
44386
45257
  if (!check2.ok) {
@@ -44974,7 +45845,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
44974
45845
  });
44975
45846
  }
44976
45847
  const staleNames = new Set(stale.map((finding) => finding.hook));
44977
- const settingsExist = existsSync16(settingsPath);
45848
+ const settingsExist = existsSync19(settingsPath);
44978
45849
  if (!settingsExist) {
44979
45850
  issues.push({ hook: "(settings)", issue: `${settingsPath} not found`, severity: "warning" });
44980
45851
  }
@@ -44982,7 +45853,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
44982
45853
  let wiringCount = 0;
44983
45854
  if (settingsExist) {
44984
45855
  try {
44985
- const settings = JSON.parse(readFileSync20(settingsPath, "utf-8"));
45856
+ const settings = JSON.parse(readFileSync23(settingsPath, "utf-8"));
44986
45857
  wiringCount = countSettingsWiring(settings);
44987
45858
  } catch {}
44988
45859
  }
@@ -44993,7 +45864,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
44993
45864
  const meta3 = custom2 ? resolveHookMeta(name) : getHook(name);
44994
45865
  let hookHealthy = true;
44995
45866
  if (custom2) {
44996
- if (!existsSync16(custom2.scriptPath)) {
45867
+ if (!existsSync19(custom2.scriptPath)) {
44997
45868
  issues.push({ hook: name, issue: `Custom hook script missing: ${custom2.scriptPath}`, severity: "error" });
44998
45869
  hookHealthy = false;
44999
45870
  }
@@ -45004,15 +45875,15 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
45004
45875
  continue;
45005
45876
  }
45006
45877
  const hookDir = getHookPath(name);
45007
- const hookScript = join24(hookDir, "src", "hook.ts");
45008
- if (!existsSync16(hookScript)) {
45878
+ const hookScript = join31(hookDir, "src", "hook.ts");
45879
+ if (!existsSync19(hookScript)) {
45009
45880
  issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
45010
45881
  hookHealthy = false;
45011
45882
  }
45012
45883
  }
45013
45884
  if (meta3 && settingsExist) {
45014
45885
  try {
45015
- const settings = JSON.parse(readFileSync20(settingsPath, "utf-8"));
45886
+ const settings = JSON.parse(readFileSync23(settingsPath, "utf-8"));
45016
45887
  if (!hookRegisteredInSettings(settings, name, meta3.event, meta3.matcher)) {
45017
45888
  const eventName = meta3.event.split(":")[0];
45018
45889
  issues.push({ hook: name, issue: `Not registered under correct event (${eventName})`, severity: "error" });
@@ -45162,18 +46033,18 @@ program3.command("update").argument("[hooks...]", "Hooks to update (defaults to
45162
46033
  const result = installHook(arg, { scope, overwrite: true });
45163
46034
  const resolved = resolveHook2(arg);
45164
46035
  if (result.success && resolved) {
45165
- const hash = await sha256File2(resolved.scriptPath);
45166
- setPinnedHook2(resolved.name, { version: resolved.version, sha256: hash, source: resolved.source });
46036
+ const hash4 = await sha256File2(resolved.scriptPath);
46037
+ setPinnedHook2(resolved.name, { version: resolved.version, sha256: hash4, source: resolved.source });
45167
46038
  if (!isLocalStoreRefused2()) {
45168
46039
  upsertHookRecord2(getDb2(), {
45169
46040
  name: resolved.name,
45170
46041
  version: resolved.version,
45171
- sha256: hash,
46042
+ sha256: hash4,
45172
46043
  source_type: resolved.source,
45173
46044
  last_verified_at: new Date().toISOString()
45174
46045
  });
45175
46046
  }
45176
- results2.push({ ...result, pinned: { version: resolved.version, sha256: hash } });
46047
+ results2.push({ ...result, pinned: { version: resolved.version, sha256: hash4 } });
45177
46048
  continue;
45178
46049
  }
45179
46050
  results2.push(result);
@@ -45215,10 +46086,10 @@ program3.command("docs").argument("[hook]", "Hook name (shows general docs if om
45215
46086
  return;
45216
46087
  }
45217
46088
  const hookPath = getHookPath(hook);
45218
- const readmePath = join24(hookPath, "README.md");
46089
+ const readmePath = join31(hookPath, "README.md");
45219
46090
  let readme = "";
45220
- if (existsSync16(readmePath)) {
45221
- readme = readFileSync20(readmePath, "utf-8");
46091
+ if (existsSync19(readmePath)) {
46092
+ readme = readFileSync23(readmePath, "utf-8");
45222
46093
  }
45223
46094
  if (options.json) {
45224
46095
  console.log(JSON.stringify({ ...meta3, readme }));
@@ -45846,7 +46717,38 @@ program3.command("mcp").option("-s, --stdio", "Use stdio transport (one process
45846
46717
  }
45847
46718
  });
45848
46719
  registerEventsCommands(program3, { source: "hooks" });
45849
- program3.command("safety").description("Register bundled native deletion guards without a registry credential").command("install <guard>").option("--target <target>", "codex or claude", "codex").option("--scope <scope>", "global or project", "global").option("--overwrite", "Replace this guard in place; native trust is still required").action((guard, options) => {
46720
+ var safety = program3.command("safety").description("Inspect and register bundled native deletion guards without a registry credential");
46721
+ safety.command("inspect").description("Check the installed Trash guard identity and filesystem safety without app credentials").action(() => {
46722
+ const result = inspectTrashBinary();
46723
+ console.log(JSON.stringify({ guard: "trash-guard", ...result }));
46724
+ if (!result.ok)
46725
+ process.exitCode = 1;
46726
+ });
46727
+ safety.command("install <guard>").option("--target <target>", "codex, claude or sumi", "codex").option("--scope <scope>", "global or project", "global").option("--overwrite", "Replace this guard in place; native trust is still required").option("--expected-binding-sha256 <sha256>", "Exact existing Sumi binding digest required for an upgrade").action(async (guard, options) => {
46728
+ if (options.target === "sumi") {
46729
+ try {
46730
+ if (guard !== "trash-guard" || options.scope !== "global" || options.overwrite)
46731
+ throw new NativeSafetyError("input_invalid");
46732
+ const command = installedNativeSafetyCommand("trash-guard");
46733
+ const binding = nativeSafetyCommandBinding(command);
46734
+ const installed = inspectTrashBinary({ PATH: binding.path });
46735
+ if (!installed.ok) {
46736
+ console.log(JSON.stringify({ ok: false, target: "sumi", code: installed.code }));
46737
+ process.exitCode = 1;
46738
+ return;
46739
+ }
46740
+ await verifyNativeSafetyCommand(command);
46741
+ const registered = registerNativeSafety({ command, expectedSHA256: options.expectedBindingSha256 });
46742
+ const verified = await verifyNativeSafetyRegistration();
46743
+ if (verified.sha256 !== registered.sha256)
46744
+ throw new NativeSafetyError("binding_changed");
46745
+ console.log(JSON.stringify({ target: "sumi", ...registered }));
46746
+ } catch (error61) {
46747
+ console.log(JSON.stringify({ ok: false, target: "sumi", code: error61 instanceof NativeSafetyError ? error61.code : "binding_invalid", ...error61 instanceof NativeSafetyError && error61.reason ? { reason: error61.reason } : {} }));
46748
+ process.exitCode = 1;
46749
+ }
46750
+ return;
46751
+ }
45850
46752
  if (!isNativeSafetyName(guard) || !["codex", "claude"].includes(options.target) || !["global", "project"].includes(options.scope)) {
45851
46753
  console.error("Unsupported bundled safety registration");
45852
46754
  process.exitCode = 1;
@@ -45857,6 +46759,17 @@ program3.command("safety").description("Register bundled native deletion guards
45857
46759
  if (!result.success)
45858
46760
  process.exitCode = 1;
45859
46761
  });
46762
+ safety.command("verify").requiredOption("--target <target>", "sumi").description("Verify a required native binding and its supervisor without running a file operation").action(async (options) => {
46763
+ try {
46764
+ if (options.target !== "sumi")
46765
+ throw new NativeSafetyError("input_invalid");
46766
+ const current2 = await verifyNativeSafetyRegistration();
46767
+ console.log(JSON.stringify({ ok: true, target: "sumi", sha256: current2.sha256, guardVerified: true, nativeAdoptionVerified: false }));
46768
+ } catch (error61) {
46769
+ console.log(JSON.stringify({ ok: false, target: "sumi", code: error61 instanceof NativeSafetyError ? error61.code : "guard_failed", ...error61 instanceof NativeSafetyError && error61.reason ? { reason: error61.reason } : {} }));
46770
+ process.exitCode = 1;
46771
+ }
46772
+ });
45860
46773
  var API_INDEPENDENT_COMMANDS = new Set([
45861
46774
  "safety",
45862
46775
  "serve",