@hasna/hooks 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/hooks-mcp.js +2 -2
- package/bin/index.js +733 -262
- package/bin/native-safety-entry.js +115 -23
- package/bin/serve.js +9 -9
- package/dist/index.js +12 -12
- package/dist/sdk/index.js +1 -1
- package/hooks/hook-workspace-repos-guard/README.md +30 -8
- package/hooks/hook-workspace-repos-guard/src/hook.ts +181 -42
- package/package.json +1 -1
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
1890
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1891
1891
|
import { homedir as homedir2 } from "os";
|
|
1892
|
-
import { join as
|
|
1893
|
-
import { homedir as
|
|
1894
|
-
import { join as
|
|
1895
|
-
function
|
|
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 (!
|
|
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
|
|
1904
|
-
if (!Object.keys(
|
|
1905
|
-
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(
|
|
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
|
|
1909
|
-
|
|
1908
|
+
function pathsResolverBaseDir2(kind, options) {
|
|
1909
|
+
pathsResolverAssertKind2(kind);
|
|
1910
1910
|
const env = options.env ?? process.env;
|
|
1911
|
-
const override = env[
|
|
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 ??
|
|
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
|
|
1920
|
+
return pathsResolverJoin2(home, "Library", "Application Support", "Hasna");
|
|
1921
1921
|
case "cache":
|
|
1922
|
-
return
|
|
1922
|
+
return pathsResolverJoin2(home, "Library", "Caches", "Hasna");
|
|
1923
1923
|
case "state":
|
|
1924
|
-
return
|
|
1924
|
+
return pathsResolverJoin2(home, "Library", "Logs", "Hasna");
|
|
1925
1925
|
}
|
|
1926
1926
|
}
|
|
1927
1927
|
switch (kind) {
|
|
1928
1928
|
case "config":
|
|
1929
|
-
return
|
|
1929
|
+
return pathsResolverJoin2(home, ".config", "hasna");
|
|
1930
1930
|
case "data":
|
|
1931
|
-
return
|
|
1931
|
+
return pathsResolverJoin2(home, ".local", "share", "hasna");
|
|
1932
1932
|
case "state":
|
|
1933
|
-
return
|
|
1933
|
+
return pathsResolverJoin2(home, ".local", "state", "hasna");
|
|
1934
1934
|
case "cache":
|
|
1935
|
-
return
|
|
1935
|
+
return pathsResolverJoin2(home, ".cache", "hasna");
|
|
1936
1936
|
}
|
|
1937
1937
|
}
|
|
1938
|
-
function
|
|
1939
|
-
|
|
1940
|
-
const appSegment = options.internal === true ?
|
|
1941
|
-
return
|
|
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
|
|
1944
|
-
return
|
|
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
|
|
1950
|
+
return dataDir2({ app: "hooks", home: getHomeDir(env), env });
|
|
1951
1951
|
}
|
|
1952
1952
|
function getLegacyDataRoot(env = process.env) {
|
|
1953
|
-
return
|
|
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
|
|
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
|
|
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) ?
|
|
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
|
|
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
|
|
1995
|
+
var PATHS_RESOLVER_KIND_ENV2, PATHS_RESOLVER_APP_SLUG_RE2, STORE_MARKER = "hooks.db";
|
|
1996
1996
|
var init_app_home = __esm(() => {
|
|
1997
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
4215
|
+
import { join as join5 } from "path";
|
|
4216
4216
|
function getHooksDataDir() {
|
|
4217
4217
|
return getEffectiveDataRoot();
|
|
4218
4218
|
}
|
|
4219
4219
|
function getCustomHooksDir() {
|
|
4220
|
-
return
|
|
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
|
|
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
|
|
4257
|
-
import { basename, dirname, isAbsolute, join as
|
|
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 =
|
|
4274
|
-
const rootLexical =
|
|
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 (!
|
|
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
|
|
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(
|
|
4324
|
-
if (!
|
|
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
|
|
4330
|
+
return join6(getCustomHooksDir(), shortManifestName(name));
|
|
4331
4331
|
}
|
|
4332
4332
|
function readCustomManifest(name) {
|
|
4333
4333
|
const dir = customHookDir(name);
|
|
4334
|
-
const manifestPath =
|
|
4335
|
-
if (!
|
|
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:
|
|
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 (!
|
|
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("/") ?
|
|
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(
|
|
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
|
|
4418
|
-
import { existsSync as
|
|
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 =
|
|
4422
|
-
if (
|
|
4421
|
+
const sourceLayout = join7(moduleDir, "..", "..", "hooks");
|
|
4422
|
+
if (existsSync6(join7(sourceLayout, "hook-gitguard")))
|
|
4423
4423
|
return sourceLayout;
|
|
4424
|
-
return
|
|
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 =
|
|
4436
|
-
if (
|
|
4435
|
+
const direct = join7(bundledBase, short);
|
|
4436
|
+
if (existsSync6(direct))
|
|
4437
4437
|
return direct;
|
|
4438
|
-
const prefixed =
|
|
4439
|
-
return
|
|
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 =
|
|
4449
|
-
return
|
|
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
|
|
4507
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
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";
|
|
@@ -4558,12 +4558,12 @@ function pinEligibleFile(file, maximum, executable = false) {
|
|
|
4558
4558
|
function installedNativeSafetyCommand(name) {
|
|
4559
4559
|
const home = realpathSync2(homedir3());
|
|
4560
4560
|
const runtime = realpathSync2(process.execPath);
|
|
4561
|
-
const candidates = [
|
|
4562
|
-
const worker = candidates.find(
|
|
4561
|
+
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")];
|
|
4562
|
+
const worker = candidates.find(existsSync7);
|
|
4563
4563
|
if (!worker)
|
|
4564
4564
|
throw new Error("Bundled native safety runner is missing; build or reinstall @hasna/hooks before installing its guards.");
|
|
4565
4565
|
const canonicalWorker = realpathSync2(worker);
|
|
4566
|
-
return buildNativeSafetyCommand({ name, runtime, runtimeSHA256: pinEligibleFile(runtime, 200000000, true), worker: canonicalWorker, workerSHA256: pinEligibleFile(canonicalWorker, 256000), home, path: `${dirname3(runtime)}:${
|
|
4566
|
+
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
4567
|
}
|
|
4568
4568
|
var supervisorSource, quote = (value) => "'" + value.replaceAll("'", "'\\''") + "'", program2, shell, prefix;
|
|
4569
4569
|
var init_native_safety = __esm(() => {
|
|
@@ -5010,8 +5010,8 @@ var init_migrations = __esm(() => {
|
|
|
5010
5010
|
});
|
|
5011
5011
|
|
|
5012
5012
|
// src/db/legacy-import.ts
|
|
5013
|
-
import { existsSync as
|
|
5014
|
-
import { join as
|
|
5013
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
5014
|
+
import { join as join9 } from "path";
|
|
5015
5015
|
import { homedir as homedir4 } from "os";
|
|
5016
5016
|
function ensureMetaTable(db) {
|
|
5017
5017
|
db.exec(`
|
|
@@ -5091,20 +5091,20 @@ function runLegacyImport(db, homeDir = homedir4()) {
|
|
|
5091
5091
|
if (isAlreadyDone(db))
|
|
5092
5092
|
return;
|
|
5093
5093
|
let total = 0;
|
|
5094
|
-
const claudeProjectsDir =
|
|
5095
|
-
if (
|
|
5094
|
+
const claudeProjectsDir = join9(homeDir, ".claude", "projects");
|
|
5095
|
+
if (existsSync8(claudeProjectsDir)) {
|
|
5096
5096
|
try {
|
|
5097
5097
|
const projectDirs = readdirSync2(claudeProjectsDir);
|
|
5098
5098
|
for (const dir of projectDirs) {
|
|
5099
|
-
const projectDir =
|
|
5099
|
+
const projectDir = join9(claudeProjectsDir, dir);
|
|
5100
5100
|
try {
|
|
5101
5101
|
const files = readdirSync2(projectDir);
|
|
5102
5102
|
for (const file of files) {
|
|
5103
5103
|
if (file.match(/^session-log-\d{4}-\d{2}-\d{2}\.jsonl$/)) {
|
|
5104
|
-
total += importJsonlFile(db,
|
|
5104
|
+
total += importJsonlFile(db, join9(projectDir, file));
|
|
5105
5105
|
}
|
|
5106
5106
|
if (file === "errors.log") {
|
|
5107
|
-
total += importErrorsLog(db,
|
|
5107
|
+
total += importErrorsLog(db, join9(projectDir, file));
|
|
5108
5108
|
}
|
|
5109
5109
|
}
|
|
5110
5110
|
} catch {}
|
|
@@ -5151,8 +5151,8 @@ __export(exports_db, {
|
|
|
5151
5151
|
allowLocalStore: () => allowLocalStore
|
|
5152
5152
|
});
|
|
5153
5153
|
import { Database } from "bun:sqlite";
|
|
5154
|
-
import { existsSync as
|
|
5155
|
-
import { join as
|
|
5154
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync2, cpSync } from "fs";
|
|
5155
|
+
import { join as join10 } from "path";
|
|
5156
5156
|
function refuseLocalStore(message) {
|
|
5157
5157
|
localStoreRefusal = message;
|
|
5158
5158
|
}
|
|
@@ -5167,8 +5167,8 @@ function localStoreRefusalMessage() {
|
|
|
5167
5167
|
}
|
|
5168
5168
|
function resolveDataDir() {
|
|
5169
5169
|
const effective = getEffectiveDataRoot();
|
|
5170
|
-
const oldDir =
|
|
5171
|
-
if (!
|
|
5170
|
+
const oldDir = join10(getHomeDir(), ".hooks");
|
|
5171
|
+
if (!existsSync9(effective) && existsSync9(oldDir)) {
|
|
5172
5172
|
mkdirSync2(effective, { recursive: true });
|
|
5173
5173
|
cpSync(oldDir, effective, { recursive: true });
|
|
5174
5174
|
}
|
|
@@ -5178,12 +5178,12 @@ function getDbPath() {
|
|
|
5178
5178
|
const explicitDb = process.env.HASNA_HOOKS_DB_PATH ?? process.env.HOOKS_DB_PATH;
|
|
5179
5179
|
if (explicitDb)
|
|
5180
5180
|
return explicitDb;
|
|
5181
|
-
const
|
|
5182
|
-
return
|
|
5181
|
+
const dataDir3 = resolveDataDir();
|
|
5182
|
+
return join10(dataDir3, "hooks.db");
|
|
5183
5183
|
}
|
|
5184
5184
|
function ensureDir(dbPath) {
|
|
5185
5185
|
const dir = dbPath.substring(0, dbPath.lastIndexOf("/"));
|
|
5186
|
-
if (dir && !
|
|
5186
|
+
if (dir && !existsSync9(dir)) {
|
|
5187
5187
|
mkdirSync2(dir, { recursive: true });
|
|
5188
5188
|
}
|
|
5189
5189
|
}
|
|
@@ -5193,7 +5193,7 @@ function getDb() {
|
|
|
5193
5193
|
if (instance)
|
|
5194
5194
|
return instance;
|
|
5195
5195
|
const dbPath = getDbPath();
|
|
5196
|
-
const isNew = dbPath === ":memory:" || !
|
|
5196
|
+
const isNew = dbPath === ":memory:" || !existsSync9(dbPath);
|
|
5197
5197
|
ensureDir(dbPath);
|
|
5198
5198
|
instance = new Database(dbPath);
|
|
5199
5199
|
instance.exec("PRAGMA busy_timeout=5000");
|
|
@@ -5256,7 +5256,7 @@ __export(exports_store, {
|
|
|
5256
5256
|
LockFileError: () => LockFileError
|
|
5257
5257
|
});
|
|
5258
5258
|
import { createHash as createHash2 } from "crypto";
|
|
5259
|
-
import { existsSync as
|
|
5259
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync } from "fs";
|
|
5260
5260
|
import { readFile as readFile2 } from "fs/promises";
|
|
5261
5261
|
import { randomBytes } from "crypto";
|
|
5262
5262
|
function sha256Of(input) {
|
|
@@ -5321,7 +5321,7 @@ function assertLockShape(parsed, path) {
|
|
|
5321
5321
|
}
|
|
5322
5322
|
function readLock() {
|
|
5323
5323
|
const path = getLockPath();
|
|
5324
|
-
if (!
|
|
5324
|
+
if (!existsSync10(path))
|
|
5325
5325
|
return { hooks: {} };
|
|
5326
5326
|
let raw;
|
|
5327
5327
|
try {
|
|
@@ -5455,7 +5455,7 @@ var init_store = __esm(() => {
|
|
|
5455
5455
|
});
|
|
5456
5456
|
|
|
5457
5457
|
// src/lib/codex-settings.ts
|
|
5458
|
-
import { closeSync as closeSync2, existsSync as
|
|
5458
|
+
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
5459
|
import { dirname as dirname4 } from "path";
|
|
5460
5460
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
5461
5461
|
function current(path) {
|
|
@@ -5515,7 +5515,7 @@ function writeCodexSettings(path, settings) {
|
|
|
5515
5515
|
renameSync2(temp, path);
|
|
5516
5516
|
snapshots.set(settings, { path, raw: next });
|
|
5517
5517
|
} finally {
|
|
5518
|
-
if (
|
|
5518
|
+
if (existsSync11(temp))
|
|
5519
5519
|
unlinkSync(temp);
|
|
5520
5520
|
closeSync2(fd);
|
|
5521
5521
|
unlinkSync(lock);
|
|
@@ -5526,12 +5526,12 @@ var init_codex_settings = __esm(() => {
|
|
|
5526
5526
|
snapshots = new WeakMap;
|
|
5527
5527
|
});
|
|
5528
5528
|
|
|
5529
|
-
//
|
|
5530
|
-
import { existsSync as
|
|
5529
|
+
// ../../node_modules/.bun/@hasna+skills@0.9.14+a00d3064559565bb/node_modules/@hasna/skills/dist/index.js
|
|
5530
|
+
import { existsSync as existsSync12 } from "fs";
|
|
5531
5531
|
import { homedir as homedir5 } from "os";
|
|
5532
|
-
import { join as
|
|
5533
|
-
import { homedir as
|
|
5534
|
-
import { join as
|
|
5532
|
+
import { join as join11, resolve as resolve4 } from "path";
|
|
5533
|
+
import { homedir as pathsResolverHomedir3 } from "os";
|
|
5534
|
+
import { join as pathsResolverJoin3 } from "path";
|
|
5535
5535
|
import { createHash as createHash3 } from "crypto";
|
|
5536
5536
|
import { existsSync as existsSync52, readdirSync as readdirSync3, readFileSync as readFileSync42, statSync as statSync3 } from "fs";
|
|
5537
5537
|
import { join as join52, sep as sep2 } from "path";
|
|
@@ -5543,7 +5543,7 @@ import { dirname as dirname32, isAbsolute as isAbsolute3, join as join72, resolv
|
|
|
5543
5543
|
import { lstatSync as lstatSync3, readFileSync as readFileSync6, opendirSync } from "fs";
|
|
5544
5544
|
import { createHash as createHash22 } from "crypto";
|
|
5545
5545
|
import { lstatSync as lstatSync4, opendirSync as opendirSync2 } from "fs";
|
|
5546
|
-
import { dirname as dirname42, isAbsolute as isAbsolute4, join as join82, resolve as
|
|
5546
|
+
import { dirname as dirname42, isAbsolute as isAbsolute4, join as join82, resolve as resolve42 } from "path";
|
|
5547
5547
|
import { createHash as createHash32 } from "crypto";
|
|
5548
5548
|
import { closeSync as closeSync3, constants as constants2, fstatSync as fstatSync2, lstatSync as lstatSync5, openSync as openSync3, readSync } from "fs";
|
|
5549
5549
|
import { dirname as dirname5, isAbsolute as isAbsolute5, resolve as resolve5 } from "path";
|
|
@@ -5553,7 +5553,7 @@ import { dirname as dirname6, isAbsolute as isAbsolute6, join as join92, parse,
|
|
|
5553
5553
|
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
5554
|
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute12, join as join25, resolve as resolve12 } from "path";
|
|
5555
5555
|
import { isAbsolute as isAbsolute11, join as join23, resolve as resolve11 } from "path";
|
|
5556
|
-
import { createRequire } from "module";
|
|
5556
|
+
import { createRequire as createRequire2 } from "module";
|
|
5557
5557
|
import { createHash as createHash10, randomUUID as randomUUID22 } from "crypto";
|
|
5558
5558
|
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
5559
|
import { dirname as dirname10, join as join16, resolve as resolve9, relative as relative4, isAbsolute as isAbsolute9, sep as sep4 } from "path";
|
|
@@ -5581,11 +5581,11 @@ import { createHash as createHash20 } from "crypto";
|
|
|
5581
5581
|
function __exportSetter2(name, newValue) {
|
|
5582
5582
|
this[name] = __returnValue2.bind(null, newValue);
|
|
5583
5583
|
}
|
|
5584
|
-
function
|
|
5584
|
+
function pathsResolverAssertApp3(app) {
|
|
5585
5585
|
if (typeof app !== "string" || app.length === 0) {
|
|
5586
5586
|
throw new TypeError("paths: app must be a non-empty string");
|
|
5587
5587
|
}
|
|
5588
|
-
if (!
|
|
5588
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE3.test(app)) {
|
|
5589
5589
|
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
5590
5590
|
}
|
|
5591
5591
|
}
|
|
@@ -5594,35 +5594,35 @@ function pathsResolverDataBaseDir(options) {
|
|
|
5594
5594
|
const override = env[PATHS_RESOLVER_DATA_ENV];
|
|
5595
5595
|
if (typeof override === "string" && override.length > 0)
|
|
5596
5596
|
return override;
|
|
5597
|
-
const home = options.home ??
|
|
5597
|
+
const home = options.home ?? pathsResolverHomedir3();
|
|
5598
5598
|
const platform = options.platform ?? process.platform;
|
|
5599
|
-
return platform === "darwin" ?
|
|
5599
|
+
return platform === "darwin" ? pathsResolverJoin3(home, "Library", "Application Support", "Hasna") : pathsResolverJoin3(home, ".local", "share", "hasna");
|
|
5600
5600
|
}
|
|
5601
|
-
function
|
|
5602
|
-
|
|
5603
|
-
const appSegment = options.internal === true ?
|
|
5604
|
-
return
|
|
5601
|
+
function dataDir3(options) {
|
|
5602
|
+
pathsResolverAssertApp3(options.app);
|
|
5603
|
+
const appSegment = options.internal === true ? pathsResolverJoin3("internal", options.app) : options.app;
|
|
5604
|
+
return pathsResolverJoin3(pathsResolverDataBaseDir(options), appSegment);
|
|
5605
5605
|
}
|
|
5606
|
-
function
|
|
5606
|
+
function effectiveHome2() {
|
|
5607
5607
|
return process.env["HOME"] || process.env["USERPROFILE"] || homedir5() || "/tmp";
|
|
5608
5608
|
}
|
|
5609
5609
|
function legacyDataRoot() {
|
|
5610
|
-
return
|
|
5610
|
+
return join11(effectiveHome2(), ".hasna", "skills");
|
|
5611
5611
|
}
|
|
5612
|
-
function resolverDataRoot(home =
|
|
5613
|
-
return
|
|
5612
|
+
function resolverDataRoot(home = effectiveHome2(), env) {
|
|
5613
|
+
return dataDir3({ app: "skills", home, env });
|
|
5614
5614
|
}
|
|
5615
5615
|
function adoptResolverDataRoot2(resolved, env = process.env) {
|
|
5616
5616
|
const dataOverride = env.HASNA_DATA_HOME;
|
|
5617
5617
|
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
5618
5618
|
return true;
|
|
5619
|
-
return
|
|
5619
|
+
return existsSync12(join11(resolved, DEFAULT_SQLITE_FILENAME)) || existsSync12(join11(resolved, GLOBAL_CONFIG_FILENAME));
|
|
5620
5620
|
}
|
|
5621
5621
|
function exactDataRoot() {
|
|
5622
5622
|
for (const key of [DATA_DIR_ENV, HASNA_SKILLS_HOME_ENV, SKILLS_HOME_ENV]) {
|
|
5623
5623
|
const dir = process.env[key]?.trim();
|
|
5624
5624
|
if (dir)
|
|
5625
|
-
return
|
|
5625
|
+
return resolve4(dir);
|
|
5626
5626
|
}
|
|
5627
5627
|
return;
|
|
5628
5628
|
}
|
|
@@ -5631,7 +5631,7 @@ function getDataRoot() {
|
|
|
5631
5631
|
if (exact)
|
|
5632
5632
|
return exact;
|
|
5633
5633
|
const resolved = resolverDataRoot();
|
|
5634
|
-
return adoptResolverDataRoot2(resolved) ?
|
|
5634
|
+
return adoptResolverDataRoot2(resolved) ? resolve4(resolved) : resolve4(legacyDataRoot());
|
|
5635
5635
|
}
|
|
5636
5636
|
function getDataDirReadOnly() {
|
|
5637
5637
|
return getDataRoot();
|
|
@@ -6253,7 +6253,7 @@ function need(value, message) {
|
|
|
6253
6253
|
throw new Error(message);
|
|
6254
6254
|
}
|
|
6255
6255
|
function safe(path) {
|
|
6256
|
-
need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute4(path) &&
|
|
6256
|
+
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
6257
|
for (let cursor = path;; cursor = dirname42(cursor)) {
|
|
6258
6258
|
need(!lstatSync4(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
|
|
6259
6259
|
if (dirname42(cursor) === cursor)
|
|
@@ -15487,7 +15487,7 @@ var __defProp2, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {}
|
|
|
15487
15487
|
configurable: true,
|
|
15488
15488
|
set: __exportSetter2.bind(all, name)
|
|
15489
15489
|
});
|
|
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",
|
|
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_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
15491
|
name: skills-cli
|
|
15492
15492
|
description: Discover, load, author, and run versioned skills through the Skills CLI when a task needs reusable instructions or an executable skill.
|
|
15493
15493
|
---
|
|
@@ -29705,7 +29705,7 @@ ${end.comment}` : end.comment;
|
|
|
29705
29705
|
mode: "Deployment modes were removed: a Skills client either resolves a credential " + "or it does not, and that is the whole of it.",
|
|
29706
29706
|
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
29707
|
};
|
|
29708
|
-
|
|
29708
|
+
PATHS_RESOLVER_APP_SLUG_RE3 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
29709
29709
|
SKILLS = [];
|
|
29710
29710
|
HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
29711
29711
|
HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
|
|
@@ -30032,14 +30032,14 @@ ${end.comment}` : end.comment;
|
|
|
30032
30032
|
url: "https://github.com/hasna/apps/issues"
|
|
30033
30033
|
}
|
|
30034
30034
|
};
|
|
30035
|
-
|
|
30036
|
-
|
|
30037
|
-
|
|
30038
|
-
|
|
30039
|
-
|
|
30040
|
-
|
|
30041
|
-
|
|
30042
|
-
|
|
30035
|
+
MAX_PACKAGE_BYTES2 = 1024 * 1024;
|
|
30036
|
+
MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
|
|
30037
|
+
INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
|
|
30038
|
+
CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
|
|
30039
|
+
AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
30040
|
+
requireSecretsSdk2 = createRequire2(import.meta.url);
|
|
30041
|
+
IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
30042
|
+
AUTHORITY_OVERRIDE_HEADERS2 = new Set([
|
|
30043
30043
|
"host",
|
|
30044
30044
|
":authority",
|
|
30045
30045
|
"forwarded",
|
|
@@ -36495,8 +36495,8 @@ __export(exports_installer, {
|
|
|
36495
36495
|
detectRewriteConflict: () => detectRewriteConflict,
|
|
36496
36496
|
buildCodewithTomlFragment: () => buildCodewithTomlFragment
|
|
36497
36497
|
});
|
|
36498
|
-
import { existsSync as
|
|
36499
|
-
import { join as
|
|
36498
|
+
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";
|
|
36499
|
+
import { join as join12, dirname as dirname7, basename as basename3, resolve as resolve7 } from "path";
|
|
36500
36500
|
import { homedir as homedir6 } from "os";
|
|
36501
36501
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
36502
36502
|
function normalizeHookName(name) {
|
|
@@ -36544,28 +36544,28 @@ function getSettingsPath(scope = "global", target = "claude", codewithConfigPath
|
|
|
36544
36544
|
return globalOverride;
|
|
36545
36545
|
const dir = getTargetSettingsDir(target);
|
|
36546
36546
|
if (target === "codex")
|
|
36547
|
-
return
|
|
36547
|
+
return join12(scope === "project" ? process.cwd() : homedir6(), dir, "hooks.json");
|
|
36548
36548
|
if (scope === "project") {
|
|
36549
|
-
return target === "codewith" ?
|
|
36549
|
+
return target === "codewith" ? join12(process.cwd(), dir, "config.toml") : join12(process.cwd(), dir, "settings.json");
|
|
36550
36550
|
}
|
|
36551
|
-
return target === "codewith" ?
|
|
36551
|
+
return target === "codewith" ? join12(homedir6(), dir, "config.toml") : join12(homedir6(), dir, "settings.json");
|
|
36552
36552
|
}
|
|
36553
36553
|
function getHookPath(name) {
|
|
36554
36554
|
const shortName = shortHookName(name);
|
|
36555
36555
|
const resolved = resolveHookDir(shortName);
|
|
36556
36556
|
if (resolved)
|
|
36557
36557
|
return resolved;
|
|
36558
|
-
return
|
|
36558
|
+
return join12(HOOKS_DIR, normalizeHookName(shortName));
|
|
36559
36559
|
}
|
|
36560
36560
|
function hookExists(name) {
|
|
36561
|
-
return
|
|
36561
|
+
return existsSync13(getHookPath(name));
|
|
36562
36562
|
}
|
|
36563
36563
|
function readSettings2(scope = "global", target = "claude") {
|
|
36564
36564
|
const path = getSettingsPath(scope, target);
|
|
36565
36565
|
if (target === "codex")
|
|
36566
36566
|
return readCodexSettings(path);
|
|
36567
36567
|
try {
|
|
36568
|
-
if (
|
|
36568
|
+
if (existsSync13(path)) {
|
|
36569
36569
|
const text3 = readFileSync7(path, "utf-8"), value = JSON.parse(text3);
|
|
36570
36570
|
settingsPreimages.set(value, { path, text: text3 });
|
|
36571
36571
|
return value;
|
|
@@ -36574,24 +36574,24 @@ function readSettings2(scope = "global", target = "claude") {
|
|
|
36574
36574
|
console.warn(`[hooks] Failed to read settings at ${path}: ${error61 instanceof Error ? error61.message : String(error61)}`);
|
|
36575
36575
|
}
|
|
36576
36576
|
const empty = {};
|
|
36577
|
-
if (!
|
|
36577
|
+
if (!existsSync13(path))
|
|
36578
36578
|
settingsPreimages.set(empty, { path, text: null });
|
|
36579
36579
|
return empty;
|
|
36580
36580
|
}
|
|
36581
36581
|
function settingsIdentity(path) {
|
|
36582
|
-
if (
|
|
36582
|
+
if (existsSync13(path))
|
|
36583
36583
|
return realpathSync5(path);
|
|
36584
|
-
return
|
|
36584
|
+
return existsSync13(dirname7(path)) ? join12(realpathSync5(dirname7(path)), basename3(path)) : resolve7(path);
|
|
36585
36585
|
}
|
|
36586
36586
|
function writeSettings(settings, scope = "global", target = "claude") {
|
|
36587
36587
|
const path = getSettingsPath(scope, target);
|
|
36588
36588
|
if (target === "codex")
|
|
36589
36589
|
return writeCodexSettings(path, settings);
|
|
36590
|
-
if (target === "claude" && settingsIdentity(path) === settingsIdentity(
|
|
36590
|
+
if (target === "claude" && settingsIdentity(path) === settingsIdentity(join12(homedir6(), ".claude/settings.json"))) {
|
|
36591
36591
|
const before = settingsPreimages.get(settings);
|
|
36592
36592
|
if (!before || before.path !== path)
|
|
36593
36593
|
throw new Error("Claude settings require a valid captured preimage before installation.");
|
|
36594
|
-
const current2 =
|
|
36594
|
+
const current2 = existsSync13(path) ? readFileSync7(path, "utf8") : null;
|
|
36595
36595
|
if (current2 !== before.text)
|
|
36596
36596
|
throw new Error("Claude settings changed during installation; no settings were written.");
|
|
36597
36597
|
if (coordinateClaudeSettings(before.text, JSON.stringify(settings, null, 2) + `
|
|
@@ -36599,7 +36599,7 @@ function writeSettings(settings, scope = "global", target = "claude") {
|
|
|
36599
36599
|
return;
|
|
36600
36600
|
}
|
|
36601
36601
|
const dir = dirname7(path);
|
|
36602
|
-
if (!
|
|
36602
|
+
if (!existsSync13(dir)) {
|
|
36603
36603
|
mkdirSync6(dir, { recursive: true });
|
|
36604
36604
|
}
|
|
36605
36605
|
writeFileSync5(path, JSON.stringify(settings, null, 2) + `
|
|
@@ -36698,7 +36698,7 @@ function buildCodewithTomlFragment(name, profile, mementos) {
|
|
|
36698
36698
|
function readCodewithConfig(scope, configPath) {
|
|
36699
36699
|
const path = getSettingsPath(scope, "codewith", configPath);
|
|
36700
36700
|
try {
|
|
36701
|
-
return
|
|
36701
|
+
return existsSync13(path) ? readFileSync7(path, "utf-8") : "";
|
|
36702
36702
|
} catch {
|
|
36703
36703
|
return "";
|
|
36704
36704
|
}
|
|
@@ -36706,9 +36706,9 @@ function readCodewithConfig(scope, configPath) {
|
|
|
36706
36706
|
function appendCodewithFragment(fragment, scope, configPath) {
|
|
36707
36707
|
const path = getSettingsPath(scope, "codewith", configPath);
|
|
36708
36708
|
const dir = dirname7(path);
|
|
36709
|
-
if (!
|
|
36709
|
+
if (!existsSync13(dir))
|
|
36710
36710
|
mkdirSync6(dir, { recursive: true });
|
|
36711
|
-
const existing =
|
|
36711
|
+
const existing = existsSync13(path) ? readFileSync7(path, "utf-8") : "";
|
|
36712
36712
|
const sep3 = existing.trim() ? `
|
|
36713
36713
|
|
|
36714
36714
|
` : "";
|
|
@@ -37046,7 +37046,7 @@ function removeHookForTarget(name, scope, target) {
|
|
|
37046
37046
|
}
|
|
37047
37047
|
function readSettingsAt(path) {
|
|
37048
37048
|
try {
|
|
37049
|
-
if (!
|
|
37049
|
+
if (!existsSync13(path))
|
|
37050
37050
|
return;
|
|
37051
37051
|
const raw = readFileSync7(path, "utf-8");
|
|
37052
37052
|
const settings = JSON.parse(raw);
|
|
@@ -37172,7 +37172,7 @@ function codewithHasHookEntryInText(configText, name) {
|
|
|
37172
37172
|
}
|
|
37173
37173
|
function codewithHasHookEntry(name, scope = "global") {
|
|
37174
37174
|
const path = getSettingsPath(scope, "codewith");
|
|
37175
|
-
if (!
|
|
37175
|
+
if (!existsSync13(path))
|
|
37176
37176
|
return false;
|
|
37177
37177
|
try {
|
|
37178
37178
|
return codewithHasHookEntryInText(readFileSync7(path, "utf-8"), name);
|
|
@@ -37184,12 +37184,12 @@ function removeStoreDirFailClosed(dir) {
|
|
|
37184
37184
|
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
37185
37185
|
for (const entry of entries) {
|
|
37186
37186
|
if (entry.isDirectory()) {
|
|
37187
|
-
removeStoreDirFailClosed(
|
|
37187
|
+
removeStoreDirFailClosed(join12(dir, entry.name));
|
|
37188
37188
|
}
|
|
37189
37189
|
}
|
|
37190
37190
|
for (const entry of entries) {
|
|
37191
37191
|
if (!entry.isDirectory()) {
|
|
37192
|
-
unlinkSync2(
|
|
37192
|
+
unlinkSync2(join12(dir, entry.name));
|
|
37193
37193
|
}
|
|
37194
37194
|
}
|
|
37195
37195
|
rmdirSync(dir);
|
|
@@ -37220,7 +37220,7 @@ function uninstallHook(name, scope = "global", target = "claude") {
|
|
|
37220
37220
|
const registrationsRemaining = [];
|
|
37221
37221
|
if (target === "codewith" || target === "all") {
|
|
37222
37222
|
const codewithPath = getSettingsPath(scope, "codewith");
|
|
37223
|
-
if (
|
|
37223
|
+
if (existsSync13(codewithPath)) {
|
|
37224
37224
|
const before = readFileSync7(codewithPath, "utf-8");
|
|
37225
37225
|
const after = removeCodewithHookEntry(before, shortName);
|
|
37226
37226
|
if (after.removed) {
|
|
@@ -37271,7 +37271,7 @@ var init_installer = __esm(() => {
|
|
|
37271
37271
|
init_native_safety();
|
|
37272
37272
|
init_claude_skills_coordination();
|
|
37273
37273
|
__dirname2 = dirname7(fileURLToPath2(import.meta.url));
|
|
37274
|
-
HOOKS_DIR =
|
|
37274
|
+
HOOKS_DIR = existsSync13(join12(__dirname2, "..", "..", "hooks", "hook-gitguard")) ? join12(__dirname2, "..", "..", "hooks") : join12(__dirname2, "..", "hooks");
|
|
37275
37275
|
EVENT_MAP = {
|
|
37276
37276
|
claude: {
|
|
37277
37277
|
PreToolUse: "PreToolUse",
|
|
@@ -37385,12 +37385,12 @@ var init_redact = __esm(() => {
|
|
|
37385
37385
|
});
|
|
37386
37386
|
|
|
37387
37387
|
// src/lib/profiles.ts
|
|
37388
|
-
import { existsSync as
|
|
37389
|
-
import { join as
|
|
37388
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync8, readdirSync as readdirSync8, rmSync, cpSync as cpSync2 } from "fs";
|
|
37389
|
+
import { join as join13 } from "path";
|
|
37390
37390
|
function getProfilesDir() {
|
|
37391
|
-
const newDir =
|
|
37392
|
-
const oldDir =
|
|
37393
|
-
if (!
|
|
37391
|
+
const newDir = join13(getEffectiveDataRoot(), "profiles");
|
|
37392
|
+
const oldDir = join13(getHomeDir(), ".hooks", "profiles");
|
|
37393
|
+
if (!existsSync14(newDir) && existsSync14(oldDir)) {
|
|
37394
37394
|
mkdirSync9(newDir, { recursive: true });
|
|
37395
37395
|
cpSync2(oldDir, newDir, { recursive: true });
|
|
37396
37396
|
}
|
|
@@ -37398,12 +37398,12 @@ function getProfilesDir() {
|
|
|
37398
37398
|
}
|
|
37399
37399
|
function ensureProfilesDir() {
|
|
37400
37400
|
const dir = getProfilesDir();
|
|
37401
|
-
if (!
|
|
37401
|
+
if (!existsSync14(dir)) {
|
|
37402
37402
|
mkdirSync9(dir, { recursive: true });
|
|
37403
37403
|
}
|
|
37404
37404
|
}
|
|
37405
37405
|
function profilePath(id) {
|
|
37406
|
-
return
|
|
37406
|
+
return join13(getProfilesDir(), `${id}.json`);
|
|
37407
37407
|
}
|
|
37408
37408
|
function shortUuid() {
|
|
37409
37409
|
return crypto.randomUUID().slice(0, 8);
|
|
@@ -37429,7 +37429,7 @@ function createProfile(input2) {
|
|
|
37429
37429
|
function getProfile(id) {
|
|
37430
37430
|
const path = profilePath(id);
|
|
37431
37431
|
try {
|
|
37432
|
-
if (!
|
|
37432
|
+
if (!existsSync14(path))
|
|
37433
37433
|
return null;
|
|
37434
37434
|
return JSON.parse(readFileSync9(path, "utf-8"));
|
|
37435
37435
|
} catch {
|
|
@@ -37438,14 +37438,14 @@ function getProfile(id) {
|
|
|
37438
37438
|
}
|
|
37439
37439
|
function listProfiles() {
|
|
37440
37440
|
const dir = getProfilesDir();
|
|
37441
|
-
if (!
|
|
37441
|
+
if (!existsSync14(dir))
|
|
37442
37442
|
return [];
|
|
37443
37443
|
try {
|
|
37444
37444
|
const files = readdirSync8(dir).filter((f) => f.endsWith(".json"));
|
|
37445
37445
|
const profiles = [];
|
|
37446
37446
|
for (const file2 of files) {
|
|
37447
37447
|
try {
|
|
37448
|
-
const content = readFileSync9(
|
|
37448
|
+
const content = readFileSync9(join13(dir, file2), "utf-8");
|
|
37449
37449
|
profiles.push(JSON.parse(content));
|
|
37450
37450
|
} catch {}
|
|
37451
37451
|
}
|
|
@@ -37475,7 +37475,7 @@ function importProfiles(profiles) {
|
|
|
37475
37475
|
continue;
|
|
37476
37476
|
}
|
|
37477
37477
|
const path = profilePath(profile.agent_id);
|
|
37478
|
-
if (
|
|
37478
|
+
if (existsSync14(path)) {
|
|
37479
37479
|
skipped++;
|
|
37480
37480
|
continue;
|
|
37481
37481
|
}
|
|
@@ -37489,18 +37489,18 @@ var init_profiles = __esm(() => {
|
|
|
37489
37489
|
init_app_home();
|
|
37490
37490
|
});
|
|
37491
37491
|
|
|
37492
|
-
//
|
|
37493
|
-
import { isIP } from "net";
|
|
37492
|
+
// ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
|
|
37493
|
+
import { isIP as isIP2 } from "net";
|
|
37494
37494
|
import { spawnSync } from "child_process";
|
|
37495
37495
|
import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
|
|
37496
37496
|
import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
|
|
37497
37497
|
import { hostname as osHostname } from "os";
|
|
37498
37498
|
import { isAbsolute as isAbsolute7, join as join22 } from "path";
|
|
37499
|
-
import { createRequire as
|
|
37499
|
+
import { createRequire as createRequire3 } from "module";
|
|
37500
37500
|
import { fileURLToPath as fileURLToPath22 } from "url";
|
|
37501
37501
|
import { closeSync as closeSync4, fstatSync as fstatSync3, lstatSync as lstatSync7, openSync as openSync4, readFileSync as readFileSync12, realpathSync as realpathSync7, statSync } from "fs";
|
|
37502
37502
|
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
37503
|
-
import { basename as basename5, dirname as dirname11, join as
|
|
37503
|
+
import { basename as basename5, dirname as dirname11, join as join17, relative, sep as sep3 } from "path";
|
|
37504
37504
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
37505
37505
|
function envToken2(name) {
|
|
37506
37506
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -37575,11 +37575,11 @@ function o(e2, r2, t2) {
|
|
|
37575
37575
|
}
|
|
37576
37576
|
function entryPoint(directory2) {
|
|
37577
37577
|
const root = realpathSync7(directory2);
|
|
37578
|
-
const fd = openSync4(
|
|
37578
|
+
const fd = openSync4(join17(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
|
|
37579
37579
|
let pkg;
|
|
37580
37580
|
try {
|
|
37581
37581
|
const stat2 = fstatSync3(fd);
|
|
37582
|
-
if (!stat2.isFile() || stat2.size >
|
|
37582
|
+
if (!stat2.isFile() || stat2.size > MAX_PACKAGE_BYTES3)
|
|
37583
37583
|
throw new Error("Invalid Secrets package metadata");
|
|
37584
37584
|
pkg = JSON.parse(readFileSync12(fd, "utf8"));
|
|
37585
37585
|
} finally {
|
|
@@ -37595,7 +37595,7 @@ function entryPoint(directory2) {
|
|
|
37595
37595
|
if (/[\\%?#\0]/.test(target) || parts.some((part) => !part || part === "." || part === ".." || part === "node_modules")) {
|
|
37596
37596
|
throw new Error("Invalid Secrets import export");
|
|
37597
37597
|
}
|
|
37598
|
-
const file2 = realpathSync7(
|
|
37598
|
+
const file2 = realpathSync7(join17(root, ...parts));
|
|
37599
37599
|
const within = relative(root, file2);
|
|
37600
37600
|
if (!within || within === ".." || within.startsWith(`..${sep3}`) || !statSync(file2).isFile()) {
|
|
37601
37601
|
throw new Error("Secrets import export escapes its package or is not a file");
|
|
@@ -37606,7 +37606,7 @@ function resolveInstalledSecrets(parentUrl) {
|
|
|
37606
37606
|
let directory2 = dirname11(fileURLToPath3(parentUrl));
|
|
37607
37607
|
for (;; ) {
|
|
37608
37608
|
if (basename5(directory2) !== "node_modules") {
|
|
37609
|
-
const candidate =
|
|
37609
|
+
const candidate = join17(directory2, "node_modules", PACKAGE);
|
|
37610
37610
|
let absent = false;
|
|
37611
37611
|
try {
|
|
37612
37612
|
lstatSync7(candidate);
|
|
@@ -37726,7 +37726,7 @@ function readAppConfigFile(path) {
|
|
|
37726
37726
|
const uid2 = process.getuid?.() ?? process.geteuid?.();
|
|
37727
37727
|
if (uid2 !== undefined && before.uid !== uid2)
|
|
37728
37728
|
unsafe("the file is not owned by the current user");
|
|
37729
|
-
if (before.size >
|
|
37729
|
+
if (before.size > MAX_CREDENTIAL_FILE_BYTES3)
|
|
37730
37730
|
unsafe("the file exceeds the size limit");
|
|
37731
37731
|
const bytes = readFileSync22(fd);
|
|
37732
37732
|
const after = fstatSync22(fd);
|
|
@@ -37818,13 +37818,13 @@ function sealCredential(fields) {
|
|
|
37818
37818
|
configurable: false
|
|
37819
37819
|
});
|
|
37820
37820
|
}
|
|
37821
|
-
Object.defineProperty(sealed,
|
|
37821
|
+
Object.defineProperty(sealed, INSPECT_CUSTOM3, {
|
|
37822
37822
|
value: () => ({ ...visible, apiKey: "[redacted]" }),
|
|
37823
37823
|
enumerable: false,
|
|
37824
37824
|
writable: false,
|
|
37825
37825
|
configurable: false
|
|
37826
37826
|
});
|
|
37827
|
-
Object.defineProperty(sealed,
|
|
37827
|
+
Object.defineProperty(sealed, CREDENTIAL_SEAL3, {
|
|
37828
37828
|
value: true,
|
|
37829
37829
|
enumerable: false,
|
|
37830
37830
|
writable: false,
|
|
@@ -37855,7 +37855,7 @@ function firstEnvValue(env, keys) {
|
|
|
37855
37855
|
return null;
|
|
37856
37856
|
}
|
|
37857
37857
|
function isAmbientEnvironment(env) {
|
|
37858
|
-
return env === process.env || env[
|
|
37858
|
+
return env === process.env || env[AMBIENT_ENVIRONMENT3] === true;
|
|
37859
37859
|
}
|
|
37860
37860
|
function defaultKeychainRunner(argv) {
|
|
37861
37861
|
const result = spawnSync(KEYCHAIN_SECURITY_BIN, [...argv], {
|
|
@@ -37949,7 +37949,7 @@ function snapshotClientEnvironment(name, env) {
|
|
|
37949
37949
|
snapshot2[key] = descriptor.value;
|
|
37950
37950
|
}
|
|
37951
37951
|
if (ambient) {
|
|
37952
|
-
Object.defineProperty(snapshot2,
|
|
37952
|
+
Object.defineProperty(snapshot2, AMBIENT_ENVIRONMENT3, {
|
|
37953
37953
|
value: true,
|
|
37954
37954
|
enumerable: false,
|
|
37955
37955
|
writable: false,
|
|
@@ -38122,7 +38122,7 @@ async function completePointerCredential(name, pointerResolution, env = process.
|
|
|
38122
38122
|
let secretsSdk;
|
|
38123
38123
|
try {
|
|
38124
38124
|
const sdkUrl = resolveInstalledSecrets(import.meta.url);
|
|
38125
|
-
secretsSdk =
|
|
38125
|
+
secretsSdk = requireSecretsSdk3(fileURLToPath22(sdkUrl));
|
|
38126
38126
|
} catch {
|
|
38127
38127
|
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
38128
|
}
|
|
@@ -38206,7 +38206,7 @@ function canonicalAuthorityHostname(authority) {
|
|
|
38206
38206
|
}
|
|
38207
38207
|
assertCanonicalPort(portSuffix.slice(1));
|
|
38208
38208
|
}
|
|
38209
|
-
if (
|
|
38209
|
+
if (isIP2(rawHostname.slice(1, -1)) !== 6) {
|
|
38210
38210
|
throw new Error("API URL authority must contain a canonical IPv6 literal.");
|
|
38211
38211
|
}
|
|
38212
38212
|
} else {
|
|
@@ -38222,7 +38222,7 @@ function canonicalAuthorityHostname(authority) {
|
|
|
38222
38222
|
} else {
|
|
38223
38223
|
rawHostname = authority;
|
|
38224
38224
|
}
|
|
38225
|
-
const ipVersion =
|
|
38225
|
+
const ipVersion = isIP2(rawHostname);
|
|
38226
38226
|
const numericAddressParts = rawHostname.split(".");
|
|
38227
38227
|
const looksLikeNonCanonicalIpv4 = numericAddressParts.every((part) => /^(?:0x[0-9a-f]+|[0-9]+)$/i.test(part));
|
|
38228
38228
|
if (ipVersion !== 4 && looksLikeNonCanonicalIpv4 || ipVersion !== 4 && !isValidDnsDomain(rawHostname.toLowerCase())) {
|
|
@@ -38358,9 +38358,9 @@ function credentialDiskSourcesForMessage(name, env) {
|
|
|
38358
38358
|
const paths = credentialDiskSources(name, env);
|
|
38359
38359
|
return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
|
|
38360
38360
|
}
|
|
38361
|
-
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets",
|
|
38361
|
+
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
38362
|
var init_transport = __esm(() => {
|
|
38363
|
-
|
|
38363
|
+
MAX_PACKAGE_BYTES3 = 1024 * 1024;
|
|
38364
38364
|
CredentialResolutionError = class CredentialResolutionError extends Error {
|
|
38365
38365
|
appName;
|
|
38366
38366
|
attempted;
|
|
@@ -38379,16 +38379,16 @@ var init_transport = __esm(() => {
|
|
|
38379
38379
|
this.path = path;
|
|
38380
38380
|
}
|
|
38381
38381
|
};
|
|
38382
|
-
|
|
38382
|
+
MAX_CREDENTIAL_FILE_BYTES3 = 64 * 1024;
|
|
38383
38383
|
SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
38384
38384
|
SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
38385
38385
|
ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
38386
38386
|
VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
38387
38387
|
CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
|
|
38388
|
-
|
|
38389
|
-
|
|
38390
|
-
|
|
38391
|
-
|
|
38388
|
+
INSPECT_CUSTOM3 = Symbol.for("nodejs.util.inspect.custom");
|
|
38389
|
+
CREDENTIAL_SEAL3 = Symbol.for("hasna:contracts:sealedCredential");
|
|
38390
|
+
AMBIENT_ENVIRONMENT3 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
38391
|
+
requireSecretsSdk3 = createRequire3(import.meta.url);
|
|
38392
38392
|
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
38393
38393
|
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
38394
38394
|
ClientTransportConfigurationError = class ClientTransportConfigurationError extends Error {
|
|
@@ -38401,8 +38401,8 @@ var init_transport = __esm(() => {
|
|
|
38401
38401
|
this.sources = Object.freeze([...sources]);
|
|
38402
38402
|
}
|
|
38403
38403
|
};
|
|
38404
|
-
|
|
38405
|
-
|
|
38404
|
+
IDEMPOTENT_METHODS3 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
38405
|
+
AUTHORITY_OVERRIDE_HEADERS3 = new Set([
|
|
38406
38406
|
"host",
|
|
38407
38407
|
":authority",
|
|
38408
38408
|
"forwarded",
|
|
@@ -38738,7 +38738,7 @@ var init_db_writer = __esm(() => {
|
|
|
38738
38738
|
|
|
38739
38739
|
// src/lib/hook-env.ts
|
|
38740
38740
|
import { dirname as dirname17, isAbsolute as isAbsolute15 } from "path";
|
|
38741
|
-
import { existsSync as
|
|
38741
|
+
import { existsSync as existsSync15, realpathSync as realpathSync8, statSync as statSync2 } from "fs";
|
|
38742
38742
|
import { tmpdir } from "os";
|
|
38743
38743
|
function isDeniedEnvName(name) {
|
|
38744
38744
|
const upper = name.toUpperCase();
|
|
@@ -38786,7 +38786,7 @@ function isUnsafePathEntry(entry, home) {
|
|
|
38786
38786
|
}
|
|
38787
38787
|
function sanitizeHookPath(pathValue, home) {
|
|
38788
38788
|
const baseline = PATH_BASELINE.slice();
|
|
38789
|
-
if (process.platform === "darwin" &&
|
|
38789
|
+
if (process.platform === "darwin" && existsSync15("/opt/homebrew/bin"))
|
|
38790
38790
|
baseline.push("/opt/homebrew/bin");
|
|
38791
38791
|
const bunDir = dirname17(process.execPath);
|
|
38792
38792
|
const seen = new Set;
|
|
@@ -38913,7 +38913,7 @@ __export(exports_run, {
|
|
|
38913
38913
|
});
|
|
38914
38914
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
38915
38915
|
import { rmSync as rmSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
38916
|
-
import { basename as basename9, dirname as dirname19, isAbsolute as isAbsolute17, join as
|
|
38916
|
+
import { basename as basename9, dirname as dirname19, isAbsolute as isAbsolute17, join as join19 } from "path";
|
|
38917
38917
|
function extensionOf(scriptPath) {
|
|
38918
38918
|
const base = basename9(scriptPath);
|
|
38919
38919
|
const dot = base.lastIndexOf(".");
|
|
@@ -38984,7 +38984,7 @@ async function readPipeWithDeadline(stream, deadlineMs) {
|
|
|
38984
38984
|
async function executeVerifiedScript(options) {
|
|
38985
38985
|
const scriptDir = dirname19(options.scriptPath);
|
|
38986
38986
|
const interpreter = interpreterFor(options.name, options.scriptPath, options.content);
|
|
38987
|
-
const tempPath =
|
|
38987
|
+
const tempPath = join19(scriptDir, `.hooks-verified-${randomBytes2(12).toString("hex")}.${interpreter.tempExt}`);
|
|
38988
38988
|
let proc = null;
|
|
38989
38989
|
let timedOut = false;
|
|
38990
38990
|
const timeoutTimer = options.timeout ? setTimeout(() => {
|
|
@@ -39075,12 +39075,12 @@ __export(exports_custom_install, {
|
|
|
39075
39075
|
installCustomSource: () => installCustomSource,
|
|
39076
39076
|
ensureCustomDir: () => ensureCustomDir
|
|
39077
39077
|
});
|
|
39078
|
-
import { existsSync as
|
|
39079
|
-
import { join as
|
|
39078
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync11, mkdtempSync, readFileSync as readFileSync14, rmSync as rmSync4 } from "fs";
|
|
39079
|
+
import { join as join20 } from "path";
|
|
39080
39080
|
import { tmpdir as tmpdir2 } from "os";
|
|
39081
39081
|
function manifestAt(dir) {
|
|
39082
|
-
const path =
|
|
39083
|
-
if (!
|
|
39082
|
+
const path = join20(dir, "manifest.json");
|
|
39083
|
+
if (!existsSync16(path))
|
|
39084
39084
|
return;
|
|
39085
39085
|
try {
|
|
39086
39086
|
return parseManifest(readFileSync14(path, "utf-8"));
|
|
@@ -39102,8 +39102,8 @@ function writeFromManifest(manifest, srcDir, source, kind) {
|
|
|
39102
39102
|
return { name, version: manifest.version, kind, source, dir, scriptPath };
|
|
39103
39103
|
}
|
|
39104
39104
|
async function cloneToTemp(gitUrl) {
|
|
39105
|
-
const tmp = mkdtempSync(
|
|
39106
|
-
const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl,
|
|
39105
|
+
const tmp = mkdtempSync(join20(tmpdir2(), "hooks-install-"));
|
|
39106
|
+
const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl, join20(tmp, "repo")], {
|
|
39107
39107
|
stdout: "pipe",
|
|
39108
39108
|
stderr: "pipe"
|
|
39109
39109
|
});
|
|
@@ -39116,7 +39116,7 @@ async function cloneToTemp(gitUrl) {
|
|
|
39116
39116
|
rmSync4(tmp, { recursive: true, force: true });
|
|
39117
39117
|
throw new Error(`git clone failed (${exitCode}): ${stderr.trim()}`);
|
|
39118
39118
|
}
|
|
39119
|
-
return
|
|
39119
|
+
return join20(tmp, "repo");
|
|
39120
39120
|
}
|
|
39121
39121
|
function isGitUrl(value) {
|
|
39122
39122
|
return value.startsWith("git@") || value.startsWith("ssh://") || value.startsWith("file://") || value.endsWith(".git");
|
|
@@ -39126,7 +39126,7 @@ function isCustomSource(value) {
|
|
|
39126
39126
|
return true;
|
|
39127
39127
|
if (value.startsWith("http://") || value.startsWith("https://"))
|
|
39128
39128
|
return true;
|
|
39129
|
-
return
|
|
39129
|
+
return existsSync16(value);
|
|
39130
39130
|
}
|
|
39131
39131
|
async function installCustomSource(source) {
|
|
39132
39132
|
if (isGitUrl(source)) {
|
|
@@ -39140,7 +39140,7 @@ async function installCustomSource(source) {
|
|
|
39140
39140
|
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
39141
39141
|
return installManifestUrl(source);
|
|
39142
39142
|
}
|
|
39143
|
-
if (!
|
|
39143
|
+
if (!existsSync16(source)) {
|
|
39144
39144
|
throw new Error(`No such local path: ${source}`);
|
|
39145
39145
|
}
|
|
39146
39146
|
if (source.endsWith("manifest.json")) {
|
|
@@ -40355,11 +40355,11 @@ __export(exports_serve, {
|
|
|
40355
40355
|
DEFAULT_SERVE_PORT: () => DEFAULT_SERVE_PORT
|
|
40356
40356
|
});
|
|
40357
40357
|
import { readFileSync as readFileSync17 } from "fs";
|
|
40358
|
-
import { dirname as dirname20, join as
|
|
40358
|
+
import { dirname as dirname20, join as join24 } from "path";
|
|
40359
40359
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
40360
40360
|
function packageVersion() {
|
|
40361
40361
|
try {
|
|
40362
|
-
const pkgPath =
|
|
40362
|
+
const pkgPath = join24(dirname20(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
40363
40363
|
return JSON.parse(readFileSync17(pkgPath, "utf-8")).version || "0.0.0";
|
|
40364
40364
|
} catch {
|
|
40365
40365
|
return "0.0.0";
|
|
@@ -40660,14 +40660,14 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
|
40660
40660
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
40661
40661
|
import { z as z3 } from "zod";
|
|
40662
40662
|
import { createServer } from "http";
|
|
40663
|
-
import { existsSync as
|
|
40664
|
-
import { join as
|
|
40663
|
+
import { existsSync as existsSync17, readFileSync as readFileSync19 } from "fs";
|
|
40664
|
+
import { join as join27, dirname as dirname21 } from "path";
|
|
40665
40665
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
40666
40666
|
async function runVerifiedHook(name, stdin, timeoutMs) {
|
|
40667
40667
|
const { resolveHook: resolveHook2, resolveScriptPath: resolveScriptPath2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
|
|
40668
40668
|
const resolved = resolveHook2(name);
|
|
40669
40669
|
const hookScript = resolveScriptPath2(name);
|
|
40670
|
-
if (!resolved || !hookScript || !
|
|
40670
|
+
if (!resolved || !hookScript || !existsSync17(hookScript)) {
|
|
40671
40671
|
throw new Error(`Hook '${name}' not found`);
|
|
40672
40672
|
}
|
|
40673
40673
|
const content = readFileSync19(hookScript);
|
|
@@ -40875,7 +40875,7 @@ function createHooksServer() {
|
|
|
40875
40875
|
const settingsPath = getSettingsPath(scope);
|
|
40876
40876
|
const issues = [];
|
|
40877
40877
|
const healthy = [];
|
|
40878
|
-
const settingsExist =
|
|
40878
|
+
const settingsExist = existsSync17(settingsPath);
|
|
40879
40879
|
if (!settingsExist) {
|
|
40880
40880
|
issues.push({ hook: "(settings)", issue: `${settingsPath} not found`, severity: "warning" });
|
|
40881
40881
|
}
|
|
@@ -40885,7 +40885,7 @@ function createHooksServer() {
|
|
|
40885
40885
|
const meta3 = custom2 ? resolveHookMeta(name) : getHook(name);
|
|
40886
40886
|
let hookHealthy = true;
|
|
40887
40887
|
if (custom2) {
|
|
40888
|
-
if (!
|
|
40888
|
+
if (!existsSync17(custom2.scriptPath)) {
|
|
40889
40889
|
issues.push({ hook: name, issue: `Custom hook script missing: ${custom2.scriptPath}`, severity: "error" });
|
|
40890
40890
|
hookHealthy = false;
|
|
40891
40891
|
}
|
|
@@ -40895,7 +40895,7 @@ function createHooksServer() {
|
|
|
40895
40895
|
continue;
|
|
40896
40896
|
}
|
|
40897
40897
|
const hookDir = getHookPath(name);
|
|
40898
|
-
if (!
|
|
40898
|
+
if (!existsSync17(join27(hookDir, "src", "hook.ts"))) {
|
|
40899
40899
|
issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
|
|
40900
40900
|
hookHealthy = false;
|
|
40901
40901
|
}
|
|
@@ -40939,9 +40939,9 @@ function createHooksServer() {
|
|
|
40939
40939
|
return { content: [{ type: "text", text: JSON.stringify({ error: `Hook '${name}' not found` }) }] };
|
|
40940
40940
|
}
|
|
40941
40941
|
const hookPath = getHookPath(name);
|
|
40942
|
-
const readmePath =
|
|
40942
|
+
const readmePath = join27(hookPath, "README.md");
|
|
40943
40943
|
let readme = "";
|
|
40944
|
-
if (
|
|
40944
|
+
if (existsSync17(readmePath)) {
|
|
40945
40945
|
readme = readFileSync19(readmePath, "utf-8");
|
|
40946
40946
|
}
|
|
40947
40947
|
if (verbose) {
|
|
@@ -41125,7 +41125,7 @@ function createHooksServer() {
|
|
|
41125
41125
|
const ctx = {
|
|
41126
41126
|
scope,
|
|
41127
41127
|
settings_path: settingsPath,
|
|
41128
|
-
settings_exists:
|
|
41128
|
+
settings_exists: existsSync17(settingsPath),
|
|
41129
41129
|
registered_hooks: hooks,
|
|
41130
41130
|
hook_count: hooks.length,
|
|
41131
41131
|
healthy,
|
|
@@ -41271,7 +41271,7 @@ function createHooksServer() {
|
|
|
41271
41271
|
const settingsPath = getSettingsPath(scope);
|
|
41272
41272
|
let settings = {};
|
|
41273
41273
|
try {
|
|
41274
|
-
if (
|
|
41274
|
+
if (existsSync17(settingsPath))
|
|
41275
41275
|
settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
|
|
41276
41276
|
} catch {}
|
|
41277
41277
|
if (!settings.hooks)
|
|
@@ -41294,7 +41294,7 @@ function createHooksServer() {
|
|
|
41294
41294
|
const settingsPath = getSettingsPath(scope);
|
|
41295
41295
|
let settings = {};
|
|
41296
41296
|
try {
|
|
41297
|
-
if (
|
|
41297
|
+
if (existsSync17(settingsPath))
|
|
41298
41298
|
settings = JSON.parse(readFileSync19(settingsPath, "utf-8"));
|
|
41299
41299
|
} catch {}
|
|
41300
41300
|
if (settings.hooks?.__disabled) {
|
|
@@ -41669,8 +41669,8 @@ var init_server = __esm(() => {
|
|
|
41669
41669
|
pkg = { name: "@hasna/hooks", version: "0.0.0" };
|
|
41670
41670
|
try {
|
|
41671
41671
|
for (const rel of ["../../package.json", "../package.json", "../../../package.json"]) {
|
|
41672
|
-
const p =
|
|
41673
|
-
if (
|
|
41672
|
+
const p = join27(__dirname3, rel);
|
|
41673
|
+
if (existsSync17(p)) {
|
|
41674
41674
|
pkg = JSON.parse(readFileSync19(p, "utf-8"));
|
|
41675
41675
|
break;
|
|
41676
41676
|
}
|
|
@@ -41739,16 +41739,25 @@ function startMcpHttpServer(options) {
|
|
|
41739
41739
|
var DEFAULT_MCP_HTTP_PORT = 8847, MCP_HTTP_HOST = "127.0.0.1", MCP_SERVICE_NAME = "hooks";
|
|
41740
41740
|
var init_http = () => {};
|
|
41741
41741
|
|
|
41742
|
-
// ../
|
|
41742
|
+
// ../events/dist/commander.js
|
|
41743
41743
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
41744
41744
|
import { Buffer as Buffer2 } from "buffer";
|
|
41745
|
+
import { existsSync as existsSync2 } from "fs";
|
|
41746
|
+
import { join as join2 } from "path";
|
|
41745
41747
|
import { existsSync } from "fs";
|
|
41746
41748
|
import { homedir } from "os";
|
|
41747
|
-
import { join } from "path";
|
|
41749
|
+
import { join, resolve } from "path";
|
|
41750
|
+
import { homedir as pathsResolverHomedir } from "os";
|
|
41751
|
+
import { join as pathsResolverJoin } from "path";
|
|
41748
41752
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
41753
|
+
import { lookup as dnsLookup } from "dns/promises";
|
|
41754
|
+
import { isIP } from "net";
|
|
41749
41755
|
import { randomUUID } from "crypto";
|
|
41750
41756
|
import { spawn } from "child_process";
|
|
41757
|
+
import { request as nodeHttpRequest } from "http";
|
|
41758
|
+
import { request as nodeHttpsRequest } from "https";
|
|
41751
41759
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
41760
|
+
import { createRequire } from "module";
|
|
41752
41761
|
function getPathValue(input, path) {
|
|
41753
41762
|
return path.split(".").reduce((value, part) => {
|
|
41754
41763
|
if (value && typeof value === "object" && part in value) {
|
|
@@ -41844,13 +41853,103 @@ function channelMatchesEvent(channel, event) {
|
|
|
41844
41853
|
return true;
|
|
41845
41854
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
41846
41855
|
}
|
|
41856
|
+
var PATHS_RESOLVER_KIND_ENV = {
|
|
41857
|
+
config: "HASNA_CONFIG_HOME",
|
|
41858
|
+
data: "HASNA_DATA_HOME",
|
|
41859
|
+
state: "HASNA_STATE_HOME",
|
|
41860
|
+
cache: "HASNA_CACHE_HOME"
|
|
41861
|
+
};
|
|
41862
|
+
var PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
41863
|
+
function pathsResolverAssertApp(app) {
|
|
41864
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
41865
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
41866
|
+
}
|
|
41867
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
|
|
41868
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
41869
|
+
}
|
|
41870
|
+
}
|
|
41871
|
+
function pathsResolverAssertKind(kind) {
|
|
41872
|
+
if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
|
|
41873
|
+
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
|
|
41874
|
+
}
|
|
41875
|
+
}
|
|
41876
|
+
function pathsResolverBaseDir(kind, options) {
|
|
41877
|
+
pathsResolverAssertKind(kind);
|
|
41878
|
+
const env = options.env ?? process.env;
|
|
41879
|
+
const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
|
|
41880
|
+
if (typeof override === "string" && override.length > 0)
|
|
41881
|
+
return override;
|
|
41882
|
+
const home = options.home ?? pathsResolverHomedir();
|
|
41883
|
+
const platform = options.platform ?? process.platform;
|
|
41884
|
+
if (platform === "darwin") {
|
|
41885
|
+
switch (kind) {
|
|
41886
|
+
case "config":
|
|
41887
|
+
case "data":
|
|
41888
|
+
return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
|
|
41889
|
+
case "cache":
|
|
41890
|
+
return pathsResolverJoin(home, "Library", "Caches", "Hasna");
|
|
41891
|
+
case "state":
|
|
41892
|
+
return pathsResolverJoin(home, "Library", "Logs", "Hasna");
|
|
41893
|
+
}
|
|
41894
|
+
}
|
|
41895
|
+
switch (kind) {
|
|
41896
|
+
case "config":
|
|
41897
|
+
return pathsResolverJoin(home, ".config", "hasna");
|
|
41898
|
+
case "data":
|
|
41899
|
+
return pathsResolverJoin(home, ".local", "share", "hasna");
|
|
41900
|
+
case "state":
|
|
41901
|
+
return pathsResolverJoin(home, ".local", "state", "hasna");
|
|
41902
|
+
case "cache":
|
|
41903
|
+
return pathsResolverJoin(home, ".cache", "hasna");
|
|
41904
|
+
}
|
|
41905
|
+
}
|
|
41906
|
+
function pathsResolverResolve(kind, options) {
|
|
41907
|
+
pathsResolverAssertApp(options.app);
|
|
41908
|
+
const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
|
|
41909
|
+
return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
|
|
41910
|
+
}
|
|
41911
|
+
function dataDir(options) {
|
|
41912
|
+
return pathsResolverResolve("data", options);
|
|
41913
|
+
}
|
|
41847
41914
|
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
|
|
41848
41915
|
var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
41916
|
+
var EVENTS_STORE_SENTINEL_FILE = "events.json";
|
|
41917
|
+
function effectiveHome() {
|
|
41918
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
41919
|
+
}
|
|
41920
|
+
function legacyHomeDir() {
|
|
41921
|
+
return join(effectiveHome(), ".hasna", "events");
|
|
41922
|
+
}
|
|
41923
|
+
function resolverHome() {
|
|
41924
|
+
return dataDir({ app: "events", home: effectiveHome() || undefined });
|
|
41925
|
+
}
|
|
41926
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
41927
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
41928
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
41929
|
+
return true;
|
|
41930
|
+
return existsSync(join(resolved, EVENTS_STORE_SENTINEL_FILE));
|
|
41931
|
+
}
|
|
41932
|
+
function exactEventsHome() {
|
|
41933
|
+
const dir = process.env[HASNA_EVENTS_DIR_ENV];
|
|
41934
|
+
if (dir && dir.trim())
|
|
41935
|
+
return dir.trim();
|
|
41936
|
+
const home = process.env[HASNA_EVENTS_HOME_ENV];
|
|
41937
|
+
if (home && home.trim())
|
|
41938
|
+
return home.trim();
|
|
41939
|
+
return;
|
|
41940
|
+
}
|
|
41941
|
+
function getEventsHome() {
|
|
41942
|
+
const exact = exactEventsHome();
|
|
41943
|
+
if (exact)
|
|
41944
|
+
return resolve(exact);
|
|
41945
|
+
const resolved = resolverHome();
|
|
41946
|
+
return adoptResolverHome(resolved) ? resolve(resolved) : resolve(legacyHomeDir());
|
|
41947
|
+
}
|
|
41849
41948
|
var LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:";
|
|
41850
41949
|
var DEFAULT_EVENT_PAGE_LIMIT = 100;
|
|
41851
41950
|
var MAX_EVENT_PAGE_LIMIT = 1000;
|
|
41852
41951
|
function getEventsDataDir(override) {
|
|
41853
|
-
return override ||
|
|
41952
|
+
return override || getEventsHome();
|
|
41854
41953
|
}
|
|
41855
41954
|
function getActiveEventsDirEnv() {
|
|
41856
41955
|
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
@@ -41866,12 +41965,12 @@ class JsonEventsStore {
|
|
|
41866
41965
|
channelsPath;
|
|
41867
41966
|
eventsPath;
|
|
41868
41967
|
deliveriesPath;
|
|
41869
|
-
constructor(
|
|
41870
|
-
this.dataDir =
|
|
41871
|
-
this.runtime = localJsonRuntime(
|
|
41872
|
-
this.channelsPath =
|
|
41873
|
-
this.eventsPath =
|
|
41874
|
-
this.deliveriesPath =
|
|
41968
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
41969
|
+
this.dataDir = dataDir2;
|
|
41970
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
41971
|
+
this.channelsPath = join2(dataDir2, "channels.json");
|
|
41972
|
+
this.eventsPath = join2(dataDir2, "events.json");
|
|
41973
|
+
this.deliveriesPath = join2(dataDir2, "deliveries.json");
|
|
41875
41974
|
}
|
|
41876
41975
|
async init() {
|
|
41877
41976
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -41988,7 +42087,7 @@ class JsonEventsStore {
|
|
|
41988
42087
|
};
|
|
41989
42088
|
}
|
|
41990
42089
|
async ensureArrayFile(path) {
|
|
41991
|
-
if (!
|
|
42090
|
+
if (!existsSync2(path)) {
|
|
41992
42091
|
await writeFile(path, `[]
|
|
41993
42092
|
`, { encoding: "utf-8", mode: 384 });
|
|
41994
42093
|
}
|
|
@@ -42018,7 +42117,7 @@ class JsonEventsStore {
|
|
|
42018
42117
|
});
|
|
42019
42118
|
}
|
|
42020
42119
|
}
|
|
42021
|
-
function localJsonRuntime(
|
|
42120
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
42022
42121
|
return {
|
|
42023
42122
|
mode: "local-files",
|
|
42024
42123
|
name: "json-events-store",
|
|
@@ -42031,7 +42130,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
42031
42130
|
durable: true,
|
|
42032
42131
|
idempotency: "best-effort-local",
|
|
42033
42132
|
replayCursors: true,
|
|
42034
|
-
description: `Local JSON files in ${
|
|
42133
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
42035
42134
|
};
|
|
42036
42135
|
}
|
|
42037
42136
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -42095,8 +42194,8 @@ function assertCursorFilter(name, cursorValue, optionValue) {
|
|
|
42095
42194
|
function findEventByIdentity(events, identity) {
|
|
42096
42195
|
return events.find((event) => identity.id !== undefined && event.id === identity.id || identity.dedupeKey !== undefined && event.dedupeKey === identity.dedupeKey);
|
|
42097
42196
|
}
|
|
42098
|
-
async function getEventsStatus(
|
|
42099
|
-
const store = new JsonEventsStore(
|
|
42197
|
+
async function getEventsStatus(dataDir2) {
|
|
42198
|
+
const store = new JsonEventsStore(dataDir2);
|
|
42100
42199
|
await store.init();
|
|
42101
42200
|
const [channels, events, deliveries] = await Promise.all([
|
|
42102
42201
|
store.listChannels(),
|
|
@@ -42138,9 +42237,9 @@ async function getEventsStatus(dataDir) {
|
|
|
42138
42237
|
}
|
|
42139
42238
|
};
|
|
42140
42239
|
}
|
|
42141
|
-
function statusFile(
|
|
42142
|
-
const path =
|
|
42143
|
-
return { path, exists:
|
|
42240
|
+
function statusFile(dataDir2, fileName, records) {
|
|
42241
|
+
const path = join2(dataDir2, fileName);
|
|
42242
|
+
return { path, exists: existsSync2(path), records };
|
|
42144
42243
|
}
|
|
42145
42244
|
var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
42146
42245
|
function buildSignatureBase(timestamp, body) {
|
|
@@ -42150,6 +42249,214 @@ function signPayload(secret, timestamp, body) {
|
|
|
42150
42249
|
const digest = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
|
|
42151
42250
|
return `sha256=${digest}`;
|
|
42152
42251
|
}
|
|
42252
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
42253
|
+
var IPV4_PRIVATE_RANGES = [
|
|
42254
|
+
[0, 16777215],
|
|
42255
|
+
[167772160, 184549375],
|
|
42256
|
+
[1681915904, 1686110207],
|
|
42257
|
+
[2130706432, 2147483647],
|
|
42258
|
+
[2851995648, 2852061183],
|
|
42259
|
+
[2886729728, 2887778303],
|
|
42260
|
+
[3221225472, 3221225727],
|
|
42261
|
+
[3221225984, 3221226239],
|
|
42262
|
+
[3227017984, 3227018239],
|
|
42263
|
+
[3232235520, 3232301055],
|
|
42264
|
+
[3323068416, 3323199487],
|
|
42265
|
+
[3325256704, 3325256959],
|
|
42266
|
+
[3405803776, 3405804031],
|
|
42267
|
+
[3758096384, 4294967295]
|
|
42268
|
+
];
|
|
42269
|
+
var IPV6_SPECIAL_PREFIXES = [
|
|
42270
|
+
{ groups: [0, 0, 0, 0, 0, 0, 0, 0], bits: 128 },
|
|
42271
|
+
{ groups: [0, 0, 0, 0, 0, 0, 0, 1], bits: 128 },
|
|
42272
|
+
{ groups: [0, 0, 0, 0, 0, 65535, 0, 0], bits: 96 },
|
|
42273
|
+
{ groups: [100, 65435, 0, 0, 0, 0, 0, 0], bits: 96 },
|
|
42274
|
+
{ groups: [256, 0, 0, 0, 0, 0, 0, 0], bits: 64 },
|
|
42275
|
+
{ groups: [8193, 0, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
42276
|
+
{ groups: [8193, 2, 0, 0, 0, 0, 0, 0], bits: 48 },
|
|
42277
|
+
{ groups: [8193, 16, 0, 0, 0, 0, 0, 0], bits: 28 },
|
|
42278
|
+
{ groups: [8193, 3512, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
42279
|
+
{ groups: [8194, 0, 0, 0, 0, 0, 0, 0], bits: 16 },
|
|
42280
|
+
{ groups: [16383, 0, 0, 0, 0, 0, 0, 0], bits: 20 },
|
|
42281
|
+
{ groups: [64512, 0, 0, 0, 0, 0, 0, 0], bits: 7 },
|
|
42282
|
+
{ groups: [65152, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
42283
|
+
{ groups: [65216, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
42284
|
+
{ groups: [65280, 0, 0, 0, 0, 0, 0, 0], bits: 8 }
|
|
42285
|
+
];
|
|
42286
|
+
function isPrivateAddress(address) {
|
|
42287
|
+
const normalized = stripZoneId(address);
|
|
42288
|
+
const version = isIP(normalized);
|
|
42289
|
+
if (version === 4) {
|
|
42290
|
+
const integer = ipv4ToInt(normalized);
|
|
42291
|
+
if (integer === undefined)
|
|
42292
|
+
return true;
|
|
42293
|
+
return IPV4_PRIVATE_RANGES.some(([low, high]) => integer >= low && integer <= high);
|
|
42294
|
+
}
|
|
42295
|
+
if (version === 6) {
|
|
42296
|
+
const groups = ipv6Groups(normalized);
|
|
42297
|
+
if (!groups)
|
|
42298
|
+
return true;
|
|
42299
|
+
for (const prefix of IPV6_SPECIAL_PREFIXES) {
|
|
42300
|
+
if (!ipv6MatchesPrefix(groups, prefix.groups, prefix.bits))
|
|
42301
|
+
continue;
|
|
42302
|
+
if (prefix.bits === 96 && groups[5] === 65535) {
|
|
42303
|
+
return isPrivateAddress(ipv4IntToString(groups[6] << 16 | groups[7]));
|
|
42304
|
+
}
|
|
42305
|
+
if (prefix.bits === 16 && groups[0] === 8194) {
|
|
42306
|
+
return isPrivateAddress(ipv4IntToString(groups[1] << 16 | groups[2]));
|
|
42307
|
+
}
|
|
42308
|
+
return true;
|
|
42309
|
+
}
|
|
42310
|
+
return false;
|
|
42311
|
+
}
|
|
42312
|
+
return true;
|
|
42313
|
+
}
|
|
42314
|
+
async function resolveWebhookTarget(url, policy = {}) {
|
|
42315
|
+
const hostname = normalizeHostname(url.hostname);
|
|
42316
|
+
const allowlist = (policy.allowPrivateHosts ?? []).map((entry) => normalizeHostname(entry.toLowerCase()));
|
|
42317
|
+
if (allowlist.includes(hostname)) {
|
|
42318
|
+
const version2 = isIP(hostname);
|
|
42319
|
+
if (version2 === 4 || version2 === 6) {
|
|
42320
|
+
return { hostname, addresses: [hostname] };
|
|
42321
|
+
}
|
|
42322
|
+
const lookup2 = policy.lookup ?? defaultTargetLookup;
|
|
42323
|
+
let resolved2;
|
|
42324
|
+
try {
|
|
42325
|
+
resolved2 = await lookup2(hostname);
|
|
42326
|
+
} catch {
|
|
42327
|
+
throw new Error(`Webhook target ${hostname} could not be resolved`);
|
|
42328
|
+
}
|
|
42329
|
+
if (!Array.isArray(resolved2) || resolved2.length === 0) {
|
|
42330
|
+
throw new Error(`Webhook target ${hostname} resolved to no addresses`);
|
|
42331
|
+
}
|
|
42332
|
+
const addresses = resolved2.map((entry) => normalizeHostname(entry.address));
|
|
42333
|
+
return { hostname, addresses };
|
|
42334
|
+
}
|
|
42335
|
+
const version = isIP(hostname);
|
|
42336
|
+
if (version === 4 || version === 6) {
|
|
42337
|
+
if (isPrivateAddress(hostname)) {
|
|
42338
|
+
throw new Error(`Webhook target ${hostname} is a private or special-use address`);
|
|
42339
|
+
}
|
|
42340
|
+
return { hostname, addresses: [hostname] };
|
|
42341
|
+
}
|
|
42342
|
+
const lookup = policy.lookup ?? defaultTargetLookup;
|
|
42343
|
+
let resolved;
|
|
42344
|
+
try {
|
|
42345
|
+
resolved = await lookup(hostname);
|
|
42346
|
+
} catch {
|
|
42347
|
+
throw new Error(`Webhook target ${hostname} could not be resolved`);
|
|
42348
|
+
}
|
|
42349
|
+
if (!Array.isArray(resolved) || resolved.length === 0) {
|
|
42350
|
+
throw new Error(`Webhook target ${hostname} resolved to no addresses`);
|
|
42351
|
+
}
|
|
42352
|
+
const allowed = [];
|
|
42353
|
+
for (const entry of resolved) {
|
|
42354
|
+
const address = normalizeHostname(entry.address);
|
|
42355
|
+
if (isPrivateAddress(address)) {
|
|
42356
|
+
if (allowlist.includes(address)) {
|
|
42357
|
+
allowed.push(address);
|
|
42358
|
+
continue;
|
|
42359
|
+
}
|
|
42360
|
+
throw new Error(`Webhook target ${hostname} resolves to private or special-use address ${address}`);
|
|
42361
|
+
}
|
|
42362
|
+
allowed.push(address);
|
|
42363
|
+
}
|
|
42364
|
+
if (allowed.length === 0) {
|
|
42365
|
+
throw new Error(`Webhook target ${hostname} resolved to no public addresses`);
|
|
42366
|
+
}
|
|
42367
|
+
return { hostname, addresses: allowed };
|
|
42368
|
+
}
|
|
42369
|
+
function normalizeMaxRedirects(value) {
|
|
42370
|
+
if (value === undefined)
|
|
42371
|
+
return DEFAULT_MAX_REDIRECTS;
|
|
42372
|
+
if (!Number.isInteger(value) || value < 0)
|
|
42373
|
+
throw new Error("webhookTargetPolicy.maxRedirects must be a non-negative integer");
|
|
42374
|
+
return value;
|
|
42375
|
+
}
|
|
42376
|
+
var defaultTargetLookup = async (hostname) => {
|
|
42377
|
+
return dnsLookup(hostname, { all: true, verbatim: false });
|
|
42378
|
+
};
|
|
42379
|
+
function normalizeHostname(hostname) {
|
|
42380
|
+
const lower = hostname.toLowerCase();
|
|
42381
|
+
if (lower.startsWith("[") && lower.endsWith("]"))
|
|
42382
|
+
return lower.slice(1, -1);
|
|
42383
|
+
return lower;
|
|
42384
|
+
}
|
|
42385
|
+
function stripZoneId(address) {
|
|
42386
|
+
const percent = address.indexOf("%");
|
|
42387
|
+
return percent === -1 ? address : address.slice(0, percent);
|
|
42388
|
+
}
|
|
42389
|
+
function ipv4ToInt(address) {
|
|
42390
|
+
const parts = address.split(".");
|
|
42391
|
+
if (parts.length !== 4)
|
|
42392
|
+
return;
|
|
42393
|
+
let value = 0;
|
|
42394
|
+
for (const part of parts) {
|
|
42395
|
+
if (!/^\d{1,3}$/.test(part))
|
|
42396
|
+
return;
|
|
42397
|
+
const octet = Number(part);
|
|
42398
|
+
if (octet > 255)
|
|
42399
|
+
return;
|
|
42400
|
+
value = value << 8 | octet;
|
|
42401
|
+
}
|
|
42402
|
+
return value >>> 0;
|
|
42403
|
+
}
|
|
42404
|
+
function ipv4IntToString(integer) {
|
|
42405
|
+
return [
|
|
42406
|
+
integer >>> 24 & 255,
|
|
42407
|
+
integer >>> 16 & 255,
|
|
42408
|
+
integer >>> 8 & 255,
|
|
42409
|
+
integer & 255
|
|
42410
|
+
].join(".");
|
|
42411
|
+
}
|
|
42412
|
+
function ipv6Groups(address) {
|
|
42413
|
+
const raw = stripZoneId(address);
|
|
42414
|
+
const doubleColon = raw.indexOf("::");
|
|
42415
|
+
const headText = doubleColon === -1 ? raw : raw.slice(0, doubleColon);
|
|
42416
|
+
const tailText = doubleColon === -1 ? "" : raw.slice(doubleColon + 2);
|
|
42417
|
+
const parseGroups = (text) => {
|
|
42418
|
+
if (text === "")
|
|
42419
|
+
return [];
|
|
42420
|
+
const out = [];
|
|
42421
|
+
for (const part of text.split(":")) {
|
|
42422
|
+
if (part.includes(".")) {
|
|
42423
|
+
const v4 = ipv4ToInt(part);
|
|
42424
|
+
if (v4 === undefined)
|
|
42425
|
+
return;
|
|
42426
|
+
out.push(v4 >>> 16 & 65535, v4 & 65535);
|
|
42427
|
+
} else {
|
|
42428
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(part))
|
|
42429
|
+
return;
|
|
42430
|
+
out.push(parseInt(part, 16));
|
|
42431
|
+
}
|
|
42432
|
+
}
|
|
42433
|
+
return out;
|
|
42434
|
+
};
|
|
42435
|
+
const head = parseGroups(headText);
|
|
42436
|
+
if (!head)
|
|
42437
|
+
return;
|
|
42438
|
+
const tail = parseGroups(tailText);
|
|
42439
|
+
if (!tail)
|
|
42440
|
+
return;
|
|
42441
|
+
const total = head.length + tail.length;
|
|
42442
|
+
if (doubleColon === -1) {
|
|
42443
|
+
return total === 8 ? head : undefined;
|
|
42444
|
+
}
|
|
42445
|
+
if (total >= 8)
|
|
42446
|
+
return;
|
|
42447
|
+
return [...head, ...new Array(8 - total).fill(0), ...tail];
|
|
42448
|
+
}
|
|
42449
|
+
function ipv6MatchesPrefix(groups, prefixGroups, prefixBits) {
|
|
42450
|
+
let remaining = prefixBits;
|
|
42451
|
+
for (let index = 0;index < prefixGroups.length && remaining > 0; index += 1) {
|
|
42452
|
+
const take = Math.min(16, remaining);
|
|
42453
|
+
const mask = 65535 << 16 - take & 65535;
|
|
42454
|
+
if ((groups[index] & mask) !== (prefixGroups[index] & mask))
|
|
42455
|
+
return false;
|
|
42456
|
+
remaining -= take;
|
|
42457
|
+
}
|
|
42458
|
+
return true;
|
|
42459
|
+
}
|
|
42153
42460
|
function now() {
|
|
42154
42461
|
return new Date().toISOString();
|
|
42155
42462
|
}
|
|
@@ -42180,9 +42487,18 @@ function buildWebhookRequest(event, channel, options = {}) {
|
|
|
42180
42487
|
}
|
|
42181
42488
|
return { body, headers };
|
|
42182
42489
|
}
|
|
42490
|
+
function normalizeWebhookUrl(raw) {
|
|
42491
|
+
const url = new URL(raw);
|
|
42492
|
+
if (url.username !== "" || url.password !== "") {
|
|
42493
|
+
url.username = "";
|
|
42494
|
+
url.password = "";
|
|
42495
|
+
}
|
|
42496
|
+
return url.toString();
|
|
42497
|
+
}
|
|
42183
42498
|
async function dispatchWebhook(event, channel, options = {}) {
|
|
42184
42499
|
if (!channel.webhook)
|
|
42185
42500
|
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
42501
|
+
const webhookUrl = normalizeWebhookUrl(channel.webhook.url);
|
|
42186
42502
|
const startedAt = now();
|
|
42187
42503
|
let secret = channel.webhook.secret;
|
|
42188
42504
|
if (channel.webhook.secretRef) {
|
|
@@ -42199,10 +42515,14 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
42199
42515
|
}
|
|
42200
42516
|
const timestamp = (options.now?.() ?? new Date).toISOString();
|
|
42201
42517
|
const { body, headers } = buildWebhookRequest(event, channel, { secret, timestamp });
|
|
42518
|
+
const validateTargets = options.webhookTargetPolicy !== undefined || options.fetchImpl === undefined;
|
|
42519
|
+
if (validateTargets) {
|
|
42520
|
+
return dispatchValidatedWebhook(event, channel, { body, headers, startedAt, options });
|
|
42521
|
+
}
|
|
42202
42522
|
const controller = new AbortController;
|
|
42203
42523
|
const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
|
|
42204
42524
|
try {
|
|
42205
|
-
const response = await (options.fetchImpl ?? fetch)(
|
|
42525
|
+
const response = await (options.fetchImpl ?? fetch)(webhookUrl, {
|
|
42206
42526
|
method: "POST",
|
|
42207
42527
|
headers,
|
|
42208
42528
|
body,
|
|
@@ -42230,6 +42550,130 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
42230
42550
|
clearTimeout(timeout);
|
|
42231
42551
|
}
|
|
42232
42552
|
}
|
|
42553
|
+
function isRedirectStatus(status) {
|
|
42554
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
42555
|
+
}
|
|
42556
|
+
function redirectKeepsBody(status) {
|
|
42557
|
+
return status === 307 || status === 308;
|
|
42558
|
+
}
|
|
42559
|
+
async function pinnedNativeRequest(target, addresses, method, headers, body, signal, tls) {
|
|
42560
|
+
const isHttps = target.protocol === "https:";
|
|
42561
|
+
if (!isHttps && target.protocol !== "http:") {
|
|
42562
|
+
throw new Error(`Webhook target uses unsupported protocol ${target.protocol}`);
|
|
42563
|
+
}
|
|
42564
|
+
const defaultPort = isHttps ? 443 : 80;
|
|
42565
|
+
const port = target.port ? Number(target.port) : defaultPort;
|
|
42566
|
+
const requestOptions = {
|
|
42567
|
+
hostname: target.hostname,
|
|
42568
|
+
port,
|
|
42569
|
+
path: `${target.pathname}${target.search}`,
|
|
42570
|
+
method,
|
|
42571
|
+
headers,
|
|
42572
|
+
...tls?.ca ? { ca: tls.ca } : {},
|
|
42573
|
+
lookup: (hostname, _options, callback) => {
|
|
42574
|
+
const entries = addresses.map((address) => ({
|
|
42575
|
+
address,
|
|
42576
|
+
family: address.includes(":") ? 6 : 4
|
|
42577
|
+
}));
|
|
42578
|
+
callback(null, entries);
|
|
42579
|
+
}
|
|
42580
|
+
};
|
|
42581
|
+
return new Promise((resolve2, reject) => {
|
|
42582
|
+
const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
|
|
42583
|
+
const onAbort = () => {
|
|
42584
|
+
const error = new Error("The operation was aborted.");
|
|
42585
|
+
error.name = "AbortError";
|
|
42586
|
+
request.destroy(error);
|
|
42587
|
+
};
|
|
42588
|
+
if (signal.aborted)
|
|
42589
|
+
onAbort();
|
|
42590
|
+
else
|
|
42591
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
42592
|
+
request.on("error", reject);
|
|
42593
|
+
if (body !== undefined)
|
|
42594
|
+
request.write(body);
|
|
42595
|
+
request.end();
|
|
42596
|
+
function onResponse(response) {
|
|
42597
|
+
const chunks = [];
|
|
42598
|
+
response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
42599
|
+
response.on("error", reject);
|
|
42600
|
+
response.on("end", () => {
|
|
42601
|
+
const headersRecord = {};
|
|
42602
|
+
for (const [name, value] of Object.entries(response.headers)) {
|
|
42603
|
+
if (typeof value === "string")
|
|
42604
|
+
headersRecord[name] = value;
|
|
42605
|
+
else if (Array.isArray(value))
|
|
42606
|
+
headersRecord[name] = value.join(", ");
|
|
42607
|
+
}
|
|
42608
|
+
resolve2(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
|
|
42609
|
+
});
|
|
42610
|
+
}
|
|
42611
|
+
});
|
|
42612
|
+
}
|
|
42613
|
+
async function dispatchValidatedWebhook(event, channel, input) {
|
|
42614
|
+
const { body, headers, startedAt, options } = input;
|
|
42615
|
+
const webhook = channel.webhook;
|
|
42616
|
+
if (!webhook)
|
|
42617
|
+
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
42618
|
+
const policy = options.webhookTargetPolicy ?? {};
|
|
42619
|
+
const maxRedirects = normalizeMaxRedirects(policy.maxRedirects);
|
|
42620
|
+
const controller = new AbortController;
|
|
42621
|
+
const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs ?? 15000);
|
|
42622
|
+
try {
|
|
42623
|
+
let target = new URL(normalizeWebhookUrl(webhook.url));
|
|
42624
|
+
let requestHeaders = headers;
|
|
42625
|
+
let method = "POST";
|
|
42626
|
+
let requestBody = body;
|
|
42627
|
+
let redirectsFollowed = 0;
|
|
42628
|
+
for (;; ) {
|
|
42629
|
+
const resolved = await resolveWebhookTarget(target, policy).catch((error) => {
|
|
42630
|
+
throw new Error(`Webhook target rejected by SSRF guard: ${error.message}`);
|
|
42631
|
+
});
|
|
42632
|
+
const response = options.fetchImpl ? await options.fetchImpl(target, {
|
|
42633
|
+
method,
|
|
42634
|
+
headers: requestHeaders,
|
|
42635
|
+
body: requestBody,
|
|
42636
|
+
signal: controller.signal,
|
|
42637
|
+
redirect: "manual"
|
|
42638
|
+
}) : await pinnedNativeRequest(target, resolved.addresses, method, requestHeaders, requestBody, controller.signal, options.tls);
|
|
42639
|
+
const location = response.headers.get("location");
|
|
42640
|
+
if (isRedirectStatus(response.status) && location) {
|
|
42641
|
+
if (redirectsFollowed >= maxRedirects) {
|
|
42642
|
+
return failedAttempt(startedAt, `Webhook target exceeded ${maxRedirects} redirects`);
|
|
42643
|
+
}
|
|
42644
|
+
redirectsFollowed += 1;
|
|
42645
|
+
const next = new URL(location, target);
|
|
42646
|
+
target = next;
|
|
42647
|
+
if (!redirectKeepsBody(response.status)) {
|
|
42648
|
+
method = "GET";
|
|
42649
|
+
requestBody = undefined;
|
|
42650
|
+
requestHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => name.toLowerCase() !== "content-type" && name.toLowerCase() !== "content-length"));
|
|
42651
|
+
}
|
|
42652
|
+
continue;
|
|
42653
|
+
}
|
|
42654
|
+
const responseBody = truncate(await response.text());
|
|
42655
|
+
return {
|
|
42656
|
+
attempt: 1,
|
|
42657
|
+
status: response.ok ? "success" : "failed",
|
|
42658
|
+
startedAt,
|
|
42659
|
+
completedAt: now(),
|
|
42660
|
+
responseStatus: response.status,
|
|
42661
|
+
responseBody,
|
|
42662
|
+
error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
|
|
42663
|
+
};
|
|
42664
|
+
}
|
|
42665
|
+
} catch (error) {
|
|
42666
|
+
return {
|
|
42667
|
+
attempt: 1,
|
|
42668
|
+
status: "failed",
|
|
42669
|
+
startedAt,
|
|
42670
|
+
completedAt: now(),
|
|
42671
|
+
error: error instanceof Error ? error.message : String(error)
|
|
42672
|
+
};
|
|
42673
|
+
} finally {
|
|
42674
|
+
clearTimeout(timeout);
|
|
42675
|
+
}
|
|
42676
|
+
}
|
|
42233
42677
|
function failedAttempt(startedAt, error) {
|
|
42234
42678
|
return {
|
|
42235
42679
|
attempt: 1,
|
|
@@ -42258,7 +42702,7 @@ async function dispatchCommand(event, channel) {
|
|
|
42258
42702
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
42259
42703
|
HASNA_EVENT_JSON: eventJson
|
|
42260
42704
|
};
|
|
42261
|
-
return new Promise((
|
|
42705
|
+
return new Promise((resolve2) => {
|
|
42262
42706
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
42263
42707
|
cwd: channel.command.cwd,
|
|
42264
42708
|
env,
|
|
@@ -42276,7 +42720,7 @@ async function dispatchCommand(event, channel) {
|
|
|
42276
42720
|
});
|
|
42277
42721
|
child.on("error", (error) => {
|
|
42278
42722
|
clearTimeout(timeout);
|
|
42279
|
-
|
|
42723
|
+
resolve2({
|
|
42280
42724
|
attempt: 1,
|
|
42281
42725
|
status: "failed",
|
|
42282
42726
|
startedAt,
|
|
@@ -42289,7 +42733,7 @@ async function dispatchCommand(event, channel) {
|
|
|
42289
42733
|
child.on("close", (code, signal) => {
|
|
42290
42734
|
clearTimeout(timeout);
|
|
42291
42735
|
const success = code === 0;
|
|
42292
|
-
|
|
42736
|
+
resolve2({
|
|
42293
42737
|
attempt: 1,
|
|
42294
42738
|
status: success ? "success" : "failed",
|
|
42295
42739
|
startedAt,
|
|
@@ -42411,6 +42855,22 @@ function setPath(input, path, replacement) {
|
|
|
42411
42855
|
if (last && last in cursor)
|
|
42412
42856
|
cursor[last] = replacement;
|
|
42413
42857
|
}
|
|
42858
|
+
var MAX_PACKAGE_BYTES = 1024 * 1024;
|
|
42859
|
+
var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
|
|
42860
|
+
var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
42861
|
+
var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
42862
|
+
var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
42863
|
+
var requireSecretsSdk = createRequire(import.meta.url);
|
|
42864
|
+
var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
42865
|
+
var AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
42866
|
+
"host",
|
|
42867
|
+
":authority",
|
|
42868
|
+
"forwarded",
|
|
42869
|
+
"x-forwarded-host",
|
|
42870
|
+
"x-original-host"
|
|
42871
|
+
]);
|
|
42872
|
+
var MAX_ENVELOPE_BYTES = 256 * 1024;
|
|
42873
|
+
var MAX_REQUEST_BYTES = MAX_ENVELOPE_BYTES * 2 + 8192;
|
|
42414
42874
|
function createEvent(input) {
|
|
42415
42875
|
return {
|
|
42416
42876
|
id: input.id ?? randomUUID2(),
|
|
@@ -42439,7 +42899,9 @@ class EventsClient {
|
|
|
42439
42899
|
this.transportOptions = {
|
|
42440
42900
|
fetchImpl: options.fetchImpl,
|
|
42441
42901
|
secretResolver: options.secretResolver,
|
|
42442
|
-
now: options.now
|
|
42902
|
+
now: options.now,
|
|
42903
|
+
tls: options.tls,
|
|
42904
|
+
webhookTargetPolicy: options.webhookTargetPolicy
|
|
42443
42905
|
};
|
|
42444
42906
|
this.catalog = options.catalog ?? defaultEventTypeCatalog;
|
|
42445
42907
|
this.validateCatalogTypes = options.validateCatalogTypes ?? false;
|
|
@@ -42726,6 +43188,13 @@ function parseMatcherExpression(value, label) {
|
|
|
42726
43188
|
negated: false
|
|
42727
43189
|
};
|
|
42728
43190
|
}
|
|
43191
|
+
function webhookTargetPolicyFromEnv() {
|
|
43192
|
+
const value = process.env.HASNA_EVENTS_ALLOW_PRIVATE_WEBHOOK_TARGETS;
|
|
43193
|
+
if (!value)
|
|
43194
|
+
return;
|
|
43195
|
+
const hosts = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
43196
|
+
return hosts.length > 0 ? { allowPrivateHosts: hosts } : undefined;
|
|
43197
|
+
}
|
|
42729
43198
|
var DEFAULT_EVENT_LIST_LIMIT = 100;
|
|
42730
43199
|
function parseJsonObject(value, fallback) {
|
|
42731
43200
|
if (!value)
|
|
@@ -42751,7 +43220,7 @@ function parseHeaders(values) {
|
|
|
42751
43220
|
function createClient(options) {
|
|
42752
43221
|
if (options.createClient)
|
|
42753
43222
|
return options.createClient();
|
|
42754
|
-
return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
|
|
43223
|
+
return new EventsClient({ store: new JsonEventsStore(options.dataDir), webhookTargetPolicy: webhookTargetPolicyFromEnv() });
|
|
42755
43224
|
}
|
|
42756
43225
|
function print(value, json, text) {
|
|
42757
43226
|
if (json)
|
|
@@ -42832,6 +43301,8 @@ function registerChannelCommands(program, options) {
|
|
|
42832
43301
|
metadata: parseJsonObject(actionOptions.metadata, {})
|
|
42833
43302
|
}, { honorFilters: actionOptions.honorFilters });
|
|
42834
43303
|
print(result, json, `${result.status}: ${result.channelId}`);
|
|
43304
|
+
if (result.status === "failed")
|
|
43305
|
+
process.exitCode = 1;
|
|
42835
43306
|
} catch (error) {
|
|
42836
43307
|
fail(error, json);
|
|
42837
43308
|
}
|
|
@@ -42924,7 +43395,7 @@ function replaySummary(events, deliveries, nextCursor) {
|
|
|
42924
43395
|
// src/cli/index.tsx
|
|
42925
43396
|
import { render } from "ink";
|
|
42926
43397
|
|
|
42927
|
-
//
|
|
43398
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
|
|
42928
43399
|
var import__ = __toESM(require_commander(), 1);
|
|
42929
43400
|
var {
|
|
42930
43401
|
program,
|
|
@@ -42942,19 +43413,19 @@ var {
|
|
|
42942
43413
|
|
|
42943
43414
|
// src/cli/index.tsx
|
|
42944
43415
|
import chalk2 from "chalk";
|
|
42945
|
-
import { existsSync as
|
|
42946
|
-
import { join as
|
|
43416
|
+
import { existsSync as existsSync18, readFileSync as readFileSync20, rmSync as rmSync6 } from "fs";
|
|
43417
|
+
import { join as join29, dirname as dirname22 } from "path";
|
|
42947
43418
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
42948
43419
|
|
|
42949
43420
|
// src/cli/components/App.tsx
|
|
42950
43421
|
import { useState as useState7 } from "react";
|
|
42951
43422
|
import { Box as Box8, Text as Text10, useApp, useInput as useInput5 } from "ink";
|
|
42952
43423
|
|
|
42953
|
-
//
|
|
43424
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
|
|
42954
43425
|
import React from "react";
|
|
42955
43426
|
import { Box, Text } from "ink";
|
|
42956
43427
|
|
|
42957
|
-
//
|
|
43428
|
+
// ../../node_modules/.bun/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
|
|
42958
43429
|
import process2 from "process";
|
|
42959
43430
|
function isUnicodeSupported() {
|
|
42960
43431
|
const { env } = process2;
|
|
@@ -42965,7 +43436,7 @@ function isUnicodeSupported() {
|
|
|
42965
43436
|
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
43437
|
}
|
|
42967
43438
|
|
|
42968
|
-
//
|
|
43439
|
+
// ../../node_modules/.bun/figures@6.1.0/node_modules/figures/index.js
|
|
42969
43440
|
var common = {
|
|
42970
43441
|
circleQuestionMark: "(?)",
|
|
42971
43442
|
questionMarkPrefix: "(?)",
|
|
@@ -43241,23 +43712,23 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
|
|
|
43241
43712
|
var figures_default = figures;
|
|
43242
43713
|
var replacements = Object.entries(specialMainSymbols);
|
|
43243
43714
|
|
|
43244
|
-
//
|
|
43715
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
|
|
43245
43716
|
function Indicator({ isSelected = false }) {
|
|
43246
43717
|
return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures_default.pointer) : React.createElement(Text, null, " "));
|
|
43247
43718
|
}
|
|
43248
43719
|
var Indicator_default = Indicator;
|
|
43249
|
-
//
|
|
43720
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Item.js
|
|
43250
43721
|
import * as React2 from "react";
|
|
43251
43722
|
import { Text as Text2 } from "ink";
|
|
43252
43723
|
function Item({ isSelected = false, label }) {
|
|
43253
43724
|
return React2.createElement(Text2, { color: isSelected ? "blue" : undefined }, label);
|
|
43254
43725
|
}
|
|
43255
43726
|
var Item_default = Item;
|
|
43256
|
-
//
|
|
43727
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
|
|
43257
43728
|
import { isDeepStrictEqual } from "util";
|
|
43258
43729
|
import React3, { useState, useEffect, useRef, useCallback } from "react";
|
|
43259
43730
|
|
|
43260
|
-
//
|
|
43731
|
+
// ../../node_modules/.bun/to-rotated@1.0.0/node_modules/to-rotated/index.js
|
|
43261
43732
|
function toRotated(array, steps) {
|
|
43262
43733
|
if (!Array.isArray(array)) {
|
|
43263
43734
|
throw new TypeError(`Expected an array, got \`${typeof array}\`.`);
|
|
@@ -43279,7 +43750,7 @@ function toRotated(array, steps) {
|
|
|
43279
43750
|
];
|
|
43280
43751
|
}
|
|
43281
43752
|
|
|
43282
|
-
//
|
|
43753
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
|
|
43283
43754
|
import { Box as Box2, useInput } from "ink";
|
|
43284
43755
|
function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator_default, itemComponent = Item_default, limit: customLimit, onSelect, onHighlight }) {
|
|
43285
43756
|
const hasLimit = typeof customLimit === "number" && items.length > customLimit;
|
|
@@ -43575,7 +44046,7 @@ function HookSelect({
|
|
|
43575
44046
|
import { useState as useState4, useEffect as useEffect3 } from "react";
|
|
43576
44047
|
import { Box as Box6, Text as Text7, useInput as useInput4 } from "ink";
|
|
43577
44048
|
|
|
43578
|
-
//
|
|
44049
|
+
// ../../node_modules/.bun/ink-text-input@6.0.0+fa875fef9f949ebd/node_modules/ink-text-input/build/index.js
|
|
43579
44050
|
import React5, { useState as useState3, useEffect as useEffect2 } from "react";
|
|
43580
44051
|
import { Text as Text6, useInput as useInput3 } from "ink";
|
|
43581
44052
|
import chalk from "chalk";
|
|
@@ -43753,7 +44224,7 @@ function SearchView({
|
|
|
43753
44224
|
import { useState as useState6, useEffect as useEffect5 } from "react";
|
|
43754
44225
|
import { Box as Box7, Text as Text9 } from "ink";
|
|
43755
44226
|
|
|
43756
|
-
//
|
|
44227
|
+
// ../../node_modules/.bun/ink-spinner@5.0.0+fa875fef9f949ebd/node_modules/ink-spinner/build/index.js
|
|
43757
44228
|
var import_cli_spinners = __toESM(require_cli_spinners(), 1);
|
|
43758
44229
|
import React7, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
43759
44230
|
import { Text as Text8 } from "ink";
|
|
@@ -44133,7 +44604,7 @@ init_transport2();
|
|
|
44133
44604
|
init_db();
|
|
44134
44605
|
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
44135
44606
|
var __dirname4 = dirname22(fileURLToPath6(import.meta.url));
|
|
44136
|
-
var pkgPath =
|
|
44607
|
+
var pkgPath = existsSync18(join29(__dirname4, "..", "package.json")) ? join29(__dirname4, "..", "package.json") : join29(__dirname4, "..", "..", "package.json");
|
|
44137
44608
|
var pkg2 = JSON.parse(readFileSync20(pkgPath, "utf-8"));
|
|
44138
44609
|
var program3 = new Command;
|
|
44139
44610
|
function resolveScope(options) {
|
|
@@ -44352,7 +44823,7 @@ program3.command("init").description("Register a new agent profile with a unique
|
|
|
44352
44823
|
if (profile.name) {
|
|
44353
44824
|
console.log(` ${chalk2.dim("Name:")} ${profile.name}`);
|
|
44354
44825
|
}
|
|
44355
|
-
console.log(` ${chalk2.dim("Profile:")} ${
|
|
44826
|
+
console.log(` ${chalk2.dim("Profile:")} ${join29(getProfilesDir(), `${profile.agent_id}.json`)}`);
|
|
44356
44827
|
console.log();
|
|
44357
44828
|
console.log(chalk2.dim(" Install hooks with this profile:"));
|
|
44358
44829
|
console.log(` hooks install gitguard --profile ${profile.agent_id}`);
|
|
@@ -44376,7 +44847,7 @@ program3.command("run").argument("<hook>", "Hook to run").option("--profile <id>
|
|
|
44376
44847
|
process.exit(1);
|
|
44377
44848
|
}
|
|
44378
44849
|
const hookScript = resolveScriptPath2(hook);
|
|
44379
|
-
if (!hookScript || !
|
|
44850
|
+
if (!hookScript || !existsSync18(hookScript)) {
|
|
44380
44851
|
console.error(JSON.stringify({ error: `Hook script not found: ${hookScript ?? hook}` }));
|
|
44381
44852
|
process.exit(1);
|
|
44382
44853
|
}
|
|
@@ -44974,7 +45445,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
|
|
|
44974
45445
|
});
|
|
44975
45446
|
}
|
|
44976
45447
|
const staleNames = new Set(stale.map((finding) => finding.hook));
|
|
44977
|
-
const settingsExist =
|
|
45448
|
+
const settingsExist = existsSync18(settingsPath);
|
|
44978
45449
|
if (!settingsExist) {
|
|
44979
45450
|
issues.push({ hook: "(settings)", issue: `${settingsPath} not found`, severity: "warning" });
|
|
44980
45451
|
}
|
|
@@ -44993,7 +45464,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
|
|
|
44993
45464
|
const meta3 = custom2 ? resolveHookMeta(name) : getHook(name);
|
|
44994
45465
|
let hookHealthy = true;
|
|
44995
45466
|
if (custom2) {
|
|
44996
|
-
if (!
|
|
45467
|
+
if (!existsSync18(custom2.scriptPath)) {
|
|
44997
45468
|
issues.push({ hook: name, issue: `Custom hook script missing: ${custom2.scriptPath}`, severity: "error" });
|
|
44998
45469
|
hookHealthy = false;
|
|
44999
45470
|
}
|
|
@@ -45004,8 +45475,8 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
|
|
|
45004
45475
|
continue;
|
|
45005
45476
|
}
|
|
45006
45477
|
const hookDir = getHookPath(name);
|
|
45007
|
-
const hookScript =
|
|
45008
|
-
if (!
|
|
45478
|
+
const hookScript = join29(hookDir, "src", "hook.ts");
|
|
45479
|
+
if (!existsSync18(hookScript)) {
|
|
45009
45480
|
issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
|
|
45010
45481
|
hookHealthy = false;
|
|
45011
45482
|
}
|
|
@@ -45215,9 +45686,9 @@ program3.command("docs").argument("[hook]", "Hook name (shows general docs if om
|
|
|
45215
45686
|
return;
|
|
45216
45687
|
}
|
|
45217
45688
|
const hookPath = getHookPath(hook);
|
|
45218
|
-
const readmePath =
|
|
45689
|
+
const readmePath = join29(hookPath, "README.md");
|
|
45219
45690
|
let readme = "";
|
|
45220
|
-
if (
|
|
45691
|
+
if (existsSync18(readmePath)) {
|
|
45221
45692
|
readme = readFileSync20(readmePath, "utf-8");
|
|
45222
45693
|
}
|
|
45223
45694
|
if (options.json) {
|