@hasna/hooks 0.11.5 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/bin/hooks-mcp.js +2 -2
- package/bin/index.js +114 -585
- package/bin/serve.js +9 -9
- package/dist/index.js +13 -13
- package/dist/sdk/index.js +1 -1
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -2520,7 +2520,7 @@ var init_codex_settings = __esm(() => {
|
|
|
2520
2520
|
snapshots = new WeakMap;
|
|
2521
2521
|
});
|
|
2522
2522
|
|
|
2523
|
-
//
|
|
2523
|
+
// ../../../../validation/build/apps/hooks/node_modules/@hasna/skills/dist/index.js
|
|
2524
2524
|
import { existsSync as existsSync10 } from "fs";
|
|
2525
2525
|
import { homedir as homedir6 } from "os";
|
|
2526
2526
|
import { join as join10, resolve as resolve4 } from "path";
|
|
@@ -35254,7 +35254,7 @@ var init_codex_safety_check = __esm(() => {
|
|
|
35254
35254
|
init_native_readiness_command();
|
|
35255
35255
|
init_native_safety2();
|
|
35256
35256
|
init_native_readiness();
|
|
35257
|
-
versions = new Set(["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.154.0-alpha.6.1", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1"]);
|
|
35257
|
+
versions = new Set(["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.154.0-alpha.6.1", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0"]);
|
|
35258
35258
|
CodexSafetyError = class CodexSafetyError extends Error {
|
|
35259
35259
|
code;
|
|
35260
35260
|
constructor(code2) {
|
|
@@ -35495,7 +35495,7 @@ var init_codex_safety_trust = __esm(() => {
|
|
|
35495
35495
|
};
|
|
35496
35496
|
});
|
|
35497
35497
|
|
|
35498
|
-
//
|
|
35498
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/lib/error.js
|
|
35499
35499
|
var require_error = __commonJS((exports) => {
|
|
35500
35500
|
class CommanderError extends Error {
|
|
35501
35501
|
constructor(exitCode, code2, message) {
|
|
@@ -35519,7 +35519,7 @@ var require_error = __commonJS((exports) => {
|
|
|
35519
35519
|
exports.InvalidArgumentError = InvalidArgumentError;
|
|
35520
35520
|
});
|
|
35521
35521
|
|
|
35522
|
-
//
|
|
35522
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/lib/argument.js
|
|
35523
35523
|
var require_argument = __commonJS((exports) => {
|
|
35524
35524
|
var { InvalidArgumentError } = require_error();
|
|
35525
35525
|
|
|
@@ -35598,7 +35598,7 @@ var require_argument = __commonJS((exports) => {
|
|
|
35598
35598
|
exports.humanReadableArgName = humanReadableArgName;
|
|
35599
35599
|
});
|
|
35600
35600
|
|
|
35601
|
-
//
|
|
35601
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/lib/help.js
|
|
35602
35602
|
var require_help = __commonJS((exports) => {
|
|
35603
35603
|
var { humanReadableArgName } = require_argument();
|
|
35604
35604
|
|
|
@@ -35847,7 +35847,7 @@ var require_help = __commonJS((exports) => {
|
|
|
35847
35847
|
exports.Help = Help;
|
|
35848
35848
|
});
|
|
35849
35849
|
|
|
35850
|
-
//
|
|
35850
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/lib/option.js
|
|
35851
35851
|
var require_option = __commonJS((exports) => {
|
|
35852
35852
|
var { InvalidArgumentError } = require_error();
|
|
35853
35853
|
|
|
@@ -35998,7 +35998,7 @@ var require_option = __commonJS((exports) => {
|
|
|
35998
35998
|
exports.DualOptions = DualOptions;
|
|
35999
35999
|
});
|
|
36000
36000
|
|
|
36001
|
-
//
|
|
36001
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/lib/suggestSimilar.js
|
|
36002
36002
|
var require_suggestSimilar = __commonJS((exports) => {
|
|
36003
36003
|
var maxDistance = 3;
|
|
36004
36004
|
function editDistance(a, b) {
|
|
@@ -36071,7 +36071,7 @@ var require_suggestSimilar = __commonJS((exports) => {
|
|
|
36071
36071
|
exports.suggestSimilar = suggestSimilar;
|
|
36072
36072
|
});
|
|
36073
36073
|
|
|
36074
|
-
//
|
|
36074
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/lib/command.js
|
|
36075
36075
|
var require_command = __commonJS((exports) => {
|
|
36076
36076
|
var EventEmitter = __require("events").EventEmitter;
|
|
36077
36077
|
var childProcess = __require("child_process");
|
|
@@ -37314,7 +37314,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
37314
37314
|
exports.Command = Command;
|
|
37315
37315
|
});
|
|
37316
37316
|
|
|
37317
|
-
//
|
|
37317
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/index.js
|
|
37318
37318
|
var require_commander = __commonJS((exports) => {
|
|
37319
37319
|
var { Argument } = require_argument();
|
|
37320
37320
|
var { Command } = require_command();
|
|
@@ -37334,7 +37334,7 @@ var require_commander = __commonJS((exports) => {
|
|
|
37334
37334
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
37335
37335
|
});
|
|
37336
37336
|
|
|
37337
|
-
//
|
|
37337
|
+
// ../../../../validation/build/apps/hooks/node_modules/cli-spinners/spinners.json
|
|
37338
37338
|
var require_spinners = __commonJS((exports, module) => {
|
|
37339
37339
|
module.exports = {
|
|
37340
37340
|
dots: {
|
|
@@ -38960,7 +38960,7 @@ var require_spinners = __commonJS((exports, module) => {
|
|
|
38960
38960
|
};
|
|
38961
38961
|
});
|
|
38962
38962
|
|
|
38963
|
-
//
|
|
38963
|
+
// ../../../../validation/build/apps/hooks/node_modules/cli-spinners/index.js
|
|
38964
38964
|
var require_cli_spinners = __commonJS((exports, module) => {
|
|
38965
38965
|
var spinners = Object.assign({}, require_spinners());
|
|
38966
38966
|
var spinnersList = Object.keys(spinners);
|
|
@@ -39041,10 +39041,10 @@ var init_redact = __esm(() => {
|
|
|
39041
39041
|
|
|
39042
39042
|
// src/lib/profiles.ts
|
|
39043
39043
|
import { existsSync as existsSync14, mkdirSync as mkdirSync13, readFileSync as readFileSync19, writeFileSync as writeFileSync12, readdirSync as readdirSync8, rmSync, cpSync as cpSync2 } from "fs";
|
|
39044
|
-
import { join as
|
|
39044
|
+
import { join as join27 } from "path";
|
|
39045
39045
|
function getProfilesDir() {
|
|
39046
|
-
const newDir =
|
|
39047
|
-
const oldDir =
|
|
39046
|
+
const newDir = join27(getEffectiveDataRoot(), "profiles");
|
|
39047
|
+
const oldDir = join27(getHomeDir(), ".hooks", "profiles");
|
|
39048
39048
|
if (!existsSync14(newDir) && existsSync14(oldDir)) {
|
|
39049
39049
|
mkdirSync13(newDir, { recursive: true });
|
|
39050
39050
|
cpSync2(oldDir, newDir, { recursive: true });
|
|
@@ -39058,7 +39058,7 @@ function ensureProfilesDir() {
|
|
|
39058
39058
|
}
|
|
39059
39059
|
}
|
|
39060
39060
|
function profilePath(id) {
|
|
39061
|
-
return
|
|
39061
|
+
return join27(getProfilesDir(), `${id}.json`);
|
|
39062
39062
|
}
|
|
39063
39063
|
function shortUuid() {
|
|
39064
39064
|
return crypto.randomUUID().slice(0, 8);
|
|
@@ -39100,7 +39100,7 @@ function listProfiles() {
|
|
|
39100
39100
|
const profiles = [];
|
|
39101
39101
|
for (const file2 of files) {
|
|
39102
39102
|
try {
|
|
39103
|
-
const content = readFileSync19(
|
|
39103
|
+
const content = readFileSync19(join27(dir, file2), "utf-8");
|
|
39104
39104
|
profiles.push(JSON.parse(content));
|
|
39105
39105
|
} catch {}
|
|
39106
39106
|
}
|
|
@@ -39144,18 +39144,18 @@ var init_profiles = __esm(() => {
|
|
|
39144
39144
|
init_app_home();
|
|
39145
39145
|
});
|
|
39146
39146
|
|
|
39147
|
-
//
|
|
39148
|
-
import { isIP
|
|
39147
|
+
// ../../../../validation/build/apps/hooks/node_modules/@hasna/contracts/dist/client/transport.js
|
|
39148
|
+
import { isIP } from "net";
|
|
39149
39149
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
39150
39150
|
import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
|
|
39151
39151
|
import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
|
|
39152
39152
|
import { hostname as osHostname } from "os";
|
|
39153
39153
|
import { isAbsolute as isAbsolute21, join as join28 } from "path";
|
|
39154
|
-
import { createRequire as
|
|
39154
|
+
import { createRequire as createRequire2 } from "module";
|
|
39155
39155
|
import { fileURLToPath as fileURLToPath22 } from "url";
|
|
39156
39156
|
import { closeSync as closeSync20, fstatSync as fstatSync19, lstatSync as lstatSync24, openSync as openSync20, readFileSync as readFileSync20, realpathSync as realpathSync12, statSync as statSync2 } from "fs";
|
|
39157
39157
|
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
39158
|
-
import { basename as basename9, dirname as dirname22, join as
|
|
39158
|
+
import { basename as basename9, dirname as dirname22, join as join29, relative as relative5, sep as sep6 } from "path";
|
|
39159
39159
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
39160
39160
|
function envToken2(name) {
|
|
39161
39161
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -39230,11 +39230,11 @@ function o(e2, r2, t2) {
|
|
|
39230
39230
|
}
|
|
39231
39231
|
function entryPoint(directory2) {
|
|
39232
39232
|
const root = realpathSync12(directory2);
|
|
39233
|
-
const fd = openSync20(
|
|
39233
|
+
const fd = openSync20(join29(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
|
|
39234
39234
|
let pkg;
|
|
39235
39235
|
try {
|
|
39236
39236
|
const stat2 = fstatSync19(fd);
|
|
39237
|
-
if (!stat2.isFile() || stat2.size >
|
|
39237
|
+
if (!stat2.isFile() || stat2.size > MAX_PACKAGE_BYTES2)
|
|
39238
39238
|
throw new Error("Invalid Secrets package metadata");
|
|
39239
39239
|
pkg = JSON.parse(readFileSync20(fd, "utf8"));
|
|
39240
39240
|
} finally {
|
|
@@ -39250,7 +39250,7 @@ function entryPoint(directory2) {
|
|
|
39250
39250
|
if (/[\\%?#\0]/.test(target) || parts.some((part) => !part || part === "." || part === ".." || part === "node_modules")) {
|
|
39251
39251
|
throw new Error("Invalid Secrets import export");
|
|
39252
39252
|
}
|
|
39253
|
-
const file2 = realpathSync12(
|
|
39253
|
+
const file2 = realpathSync12(join29(root, ...parts));
|
|
39254
39254
|
const within = relative5(root, file2);
|
|
39255
39255
|
if (!within || within === ".." || within.startsWith(`..${sep6}`) || !statSync2(file2).isFile()) {
|
|
39256
39256
|
throw new Error("Secrets import export escapes its package or is not a file");
|
|
@@ -39261,7 +39261,7 @@ function resolveInstalledSecrets(parentUrl) {
|
|
|
39261
39261
|
let directory2 = dirname22(fileURLToPath3(parentUrl));
|
|
39262
39262
|
for (;; ) {
|
|
39263
39263
|
if (basename9(directory2) !== "node_modules") {
|
|
39264
|
-
const candidate =
|
|
39264
|
+
const candidate = join29(directory2, "node_modules", PACKAGE);
|
|
39265
39265
|
let absent = false;
|
|
39266
39266
|
try {
|
|
39267
39267
|
lstatSync24(candidate);
|
|
@@ -39381,7 +39381,7 @@ function readAppConfigFile(path) {
|
|
|
39381
39381
|
const uid2 = process.getuid?.() ?? process.geteuid?.();
|
|
39382
39382
|
if (uid2 !== undefined && before.uid !== uid2)
|
|
39383
39383
|
unsafe("the file is not owned by the current user");
|
|
39384
|
-
if (before.size >
|
|
39384
|
+
if (before.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
39385
39385
|
unsafe("the file exceeds the size limit");
|
|
39386
39386
|
const bytes = readFileSync22(fd);
|
|
39387
39387
|
const after = fstatSync22(fd);
|
|
@@ -39473,13 +39473,13 @@ function sealCredential(fields) {
|
|
|
39473
39473
|
configurable: false
|
|
39474
39474
|
});
|
|
39475
39475
|
}
|
|
39476
|
-
Object.defineProperty(sealed,
|
|
39476
|
+
Object.defineProperty(sealed, INSPECT_CUSTOM2, {
|
|
39477
39477
|
value: () => ({ ...visible, apiKey: "[redacted]" }),
|
|
39478
39478
|
enumerable: false,
|
|
39479
39479
|
writable: false,
|
|
39480
39480
|
configurable: false
|
|
39481
39481
|
});
|
|
39482
|
-
Object.defineProperty(sealed,
|
|
39482
|
+
Object.defineProperty(sealed, CREDENTIAL_SEAL2, {
|
|
39483
39483
|
value: true,
|
|
39484
39484
|
enumerable: false,
|
|
39485
39485
|
writable: false,
|
|
@@ -39510,7 +39510,7 @@ function firstEnvValue(env, keys2) {
|
|
|
39510
39510
|
return null;
|
|
39511
39511
|
}
|
|
39512
39512
|
function isAmbientEnvironment(env) {
|
|
39513
|
-
return env === process.env || env[
|
|
39513
|
+
return env === process.env || env[AMBIENT_ENVIRONMENT2] === true;
|
|
39514
39514
|
}
|
|
39515
39515
|
function defaultKeychainRunner(argv) {
|
|
39516
39516
|
const result = spawnSync2(KEYCHAIN_SECURITY_BIN, [...argv], {
|
|
@@ -39604,7 +39604,7 @@ function snapshotClientEnvironment(name, env) {
|
|
|
39604
39604
|
snapshot2[key] = descriptor.value;
|
|
39605
39605
|
}
|
|
39606
39606
|
if (ambient) {
|
|
39607
|
-
Object.defineProperty(snapshot2,
|
|
39607
|
+
Object.defineProperty(snapshot2, AMBIENT_ENVIRONMENT2, {
|
|
39608
39608
|
value: true,
|
|
39609
39609
|
enumerable: false,
|
|
39610
39610
|
writable: false,
|
|
@@ -39777,7 +39777,7 @@ async function completePointerCredential(name, pointerResolution, env = process.
|
|
|
39777
39777
|
let secretsSdk;
|
|
39778
39778
|
try {
|
|
39779
39779
|
const sdkUrl = resolveInstalledSecrets(import.meta.url);
|
|
39780
|
-
secretsSdk =
|
|
39780
|
+
secretsSdk = requireSecretsSdk2(fileURLToPath22(sdkUrl));
|
|
39781
39781
|
} catch {
|
|
39782
39782
|
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]);
|
|
39783
39783
|
}
|
|
@@ -39861,7 +39861,7 @@ function canonicalAuthorityHostname(authority) {
|
|
|
39861
39861
|
}
|
|
39862
39862
|
assertCanonicalPort(portSuffix.slice(1));
|
|
39863
39863
|
}
|
|
39864
|
-
if (
|
|
39864
|
+
if (isIP(rawHostname.slice(1, -1)) !== 6) {
|
|
39865
39865
|
throw new Error("API URL authority must contain a canonical IPv6 literal.");
|
|
39866
39866
|
}
|
|
39867
39867
|
} else {
|
|
@@ -39877,7 +39877,7 @@ function canonicalAuthorityHostname(authority) {
|
|
|
39877
39877
|
} else {
|
|
39878
39878
|
rawHostname = authority;
|
|
39879
39879
|
}
|
|
39880
|
-
const ipVersion =
|
|
39880
|
+
const ipVersion = isIP(rawHostname);
|
|
39881
39881
|
const numericAddressParts = rawHostname.split(".");
|
|
39882
39882
|
const looksLikeNonCanonicalIpv4 = numericAddressParts.every((part) => /^(?:0x[0-9a-f]+|[0-9]+)$/i.test(part));
|
|
39883
39883
|
if (ipVersion !== 4 && looksLikeNonCanonicalIpv4 || ipVersion !== 4 && !isValidDnsDomain(rawHostname.toLowerCase())) {
|
|
@@ -40013,9 +40013,9 @@ function credentialDiskSourcesForMessage(name, env) {
|
|
|
40013
40013
|
const paths = credentialDiskSources(name, env);
|
|
40014
40014
|
return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
|
|
40015
40015
|
}
|
|
40016
|
-
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets",
|
|
40016
|
+
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets", MAX_PACKAGE_BYTES2, CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, AMBIENT_ENVIRONMENT2, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, ClientTransportConfigurationError, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2;
|
|
40017
40017
|
var init_transport = __esm(() => {
|
|
40018
|
-
|
|
40018
|
+
MAX_PACKAGE_BYTES2 = 1024 * 1024;
|
|
40019
40019
|
CredentialResolutionError = class CredentialResolutionError extends Error {
|
|
40020
40020
|
appName;
|
|
40021
40021
|
attempted;
|
|
@@ -40034,16 +40034,16 @@ var init_transport = __esm(() => {
|
|
|
40034
40034
|
this.path = path;
|
|
40035
40035
|
}
|
|
40036
40036
|
};
|
|
40037
|
-
|
|
40037
|
+
MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
|
|
40038
40038
|
SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
40039
40039
|
SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
40040
40040
|
ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
40041
40041
|
VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
40042
40042
|
CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
|
|
40043
|
-
|
|
40044
|
-
|
|
40045
|
-
|
|
40046
|
-
|
|
40043
|
+
INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
|
|
40044
|
+
CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
|
|
40045
|
+
AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
40046
|
+
requireSecretsSdk2 = createRequire2(import.meta.url);
|
|
40047
40047
|
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
40048
40048
|
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
40049
40049
|
ClientTransportConfigurationError = class ClientTransportConfigurationError extends Error {
|
|
@@ -40056,8 +40056,8 @@ var init_transport = __esm(() => {
|
|
|
40056
40056
|
this.sources = Object.freeze([...sources]);
|
|
40057
40057
|
}
|
|
40058
40058
|
};
|
|
40059
|
-
|
|
40060
|
-
|
|
40059
|
+
IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
40060
|
+
AUTHORITY_OVERRIDE_HEADERS2 = new Set([
|
|
40061
40061
|
"host",
|
|
40062
40062
|
":authority",
|
|
40063
40063
|
"forwarded",
|
|
@@ -40568,7 +40568,7 @@ __export(exports_run, {
|
|
|
40568
40568
|
});
|
|
40569
40569
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
40570
40570
|
import { rmSync as rmSync2, writeFileSync as writeFileSync13 } from "fs";
|
|
40571
|
-
import { basename as basename11, dirname as dirname24, isAbsolute as isAbsolute25, join as
|
|
40571
|
+
import { basename as basename11, dirname as dirname24, isAbsolute as isAbsolute25, join as join30 } from "path";
|
|
40572
40572
|
function extensionOf(scriptPath) {
|
|
40573
40573
|
const base = basename11(scriptPath);
|
|
40574
40574
|
const dot = base.lastIndexOf(".");
|
|
@@ -40639,7 +40639,7 @@ async function readPipeWithDeadline(stream, deadlineMs) {
|
|
|
40639
40639
|
async function executeVerifiedScript(options) {
|
|
40640
40640
|
const scriptDir = dirname24(options.scriptPath);
|
|
40641
40641
|
const interpreter = interpreterFor(options.name, options.scriptPath, options.content);
|
|
40642
|
-
const tempPath =
|
|
40642
|
+
const tempPath = join30(scriptDir, `.hooks-verified-${randomBytes2(12).toString("hex")}.${interpreter.tempExt}`);
|
|
40643
40643
|
let proc = null;
|
|
40644
40644
|
let timedOut = false;
|
|
40645
40645
|
const timeoutTimer = options.timeout ? setTimeout(() => {
|
|
@@ -40731,10 +40731,10 @@ __export(exports_custom_install, {
|
|
|
40731
40731
|
ensureCustomDir: () => ensureCustomDir
|
|
40732
40732
|
});
|
|
40733
40733
|
import { existsSync as existsSync16, mkdirSync as mkdirSync14, mkdtempSync, readFileSync as readFileSync21, rmSync as rmSync4 } from "fs";
|
|
40734
|
-
import { join as
|
|
40734
|
+
import { join as join31 } from "path";
|
|
40735
40735
|
import { tmpdir as tmpdir2 } from "os";
|
|
40736
40736
|
function manifestAt(dir) {
|
|
40737
|
-
const path =
|
|
40737
|
+
const path = join31(dir, "manifest.json");
|
|
40738
40738
|
if (!existsSync16(path))
|
|
40739
40739
|
return;
|
|
40740
40740
|
try {
|
|
@@ -40757,8 +40757,8 @@ function writeFromManifest(manifest, srcDir, source, kind) {
|
|
|
40757
40757
|
return { name, version: manifest.version, kind, source, dir, scriptPath };
|
|
40758
40758
|
}
|
|
40759
40759
|
async function cloneToTemp(gitUrl) {
|
|
40760
|
-
const tmp = mkdtempSync(
|
|
40761
|
-
const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl,
|
|
40760
|
+
const tmp = mkdtempSync(join31(tmpdir2(), "hooks-install-"));
|
|
40761
|
+
const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl, join31(tmp, "repo")], {
|
|
40762
40762
|
stdout: "pipe",
|
|
40763
40763
|
stderr: "pipe"
|
|
40764
40764
|
});
|
|
@@ -40771,7 +40771,7 @@ async function cloneToTemp(gitUrl) {
|
|
|
40771
40771
|
rmSync4(tmp, { recursive: true, force: true });
|
|
40772
40772
|
throw new Error(`git clone failed (${exitCode}): ${stderr.trim()}`);
|
|
40773
40773
|
}
|
|
40774
|
-
return
|
|
40774
|
+
return join31(tmp, "repo");
|
|
40775
40775
|
}
|
|
40776
40776
|
function isGitUrl(value) {
|
|
40777
40777
|
return value.startsWith("git@") || value.startsWith("ssh://") || value.startsWith("file://") || value.endsWith(".git");
|
|
@@ -42010,11 +42010,11 @@ __export(exports_serve, {
|
|
|
42010
42010
|
DEFAULT_SERVE_PORT: () => DEFAULT_SERVE_PORT
|
|
42011
42011
|
});
|
|
42012
42012
|
import { readFileSync as readFileSync25 } from "fs";
|
|
42013
|
-
import { dirname as dirname25, join as
|
|
42013
|
+
import { dirname as dirname25, join as join32 } from "path";
|
|
42014
42014
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
42015
42015
|
function packageVersion() {
|
|
42016
42016
|
try {
|
|
42017
|
-
const pkgPath =
|
|
42017
|
+
const pkgPath = join32(dirname25(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
42018
42018
|
return JSON.parse(readFileSync25(pkgPath, "utf-8")).version || "0.0.0";
|
|
42019
42019
|
} catch {
|
|
42020
42020
|
return "0.0.0";
|
|
@@ -42316,7 +42316,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
42316
42316
|
import { z as z3 } from "zod";
|
|
42317
42317
|
import { createServer } from "http";
|
|
42318
42318
|
import { existsSync as existsSync17, readFileSync as readFileSync26 } from "fs";
|
|
42319
|
-
import { join as
|
|
42319
|
+
import { join as join33, dirname as dirname26 } from "path";
|
|
42320
42320
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
42321
42321
|
async function runVerifiedHook(name, stdin, timeoutMs) {
|
|
42322
42322
|
const { resolveHook: resolveHook2, resolveScriptPath: resolveScriptPath2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
|
|
@@ -42550,7 +42550,7 @@ function createHooksServer() {
|
|
|
42550
42550
|
continue;
|
|
42551
42551
|
}
|
|
42552
42552
|
const hookDir = getHookPath(name);
|
|
42553
|
-
if (!existsSync17(
|
|
42553
|
+
if (!existsSync17(join33(hookDir, "src", "hook.ts"))) {
|
|
42554
42554
|
issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
|
|
42555
42555
|
hookHealthy = false;
|
|
42556
42556
|
}
|
|
@@ -42594,7 +42594,7 @@ function createHooksServer() {
|
|
|
42594
42594
|
return { content: [{ type: "text", text: JSON.stringify({ error: `Hook '${name}' not found` }) }] };
|
|
42595
42595
|
}
|
|
42596
42596
|
const hookPath = getHookPath(name);
|
|
42597
|
-
const readmePath =
|
|
42597
|
+
const readmePath = join33(hookPath, "README.md");
|
|
42598
42598
|
let readme = "";
|
|
42599
42599
|
if (existsSync17(readmePath)) {
|
|
42600
42600
|
readme = readFileSync26(readmePath, "utf-8");
|
|
@@ -43324,7 +43324,7 @@ var init_server = __esm(() => {
|
|
|
43324
43324
|
pkg = { name: "@hasna/hooks", version: "0.0.0" };
|
|
43325
43325
|
try {
|
|
43326
43326
|
for (const rel of ["../../package.json", "../package.json", "../../../package.json"]) {
|
|
43327
|
-
const p =
|
|
43327
|
+
const p = join33(__dirname3, rel);
|
|
43328
43328
|
if (existsSync17(p)) {
|
|
43329
43329
|
pkg = JSON.parse(readFileSync26(p, "utf-8"));
|
|
43330
43330
|
break;
|
|
@@ -43403,7 +43403,7 @@ __export(exports_native_readiness_binding, {
|
|
|
43403
43403
|
import { createHash as createHash25, randomUUID as randomUUID8 } from "crypto";
|
|
43404
43404
|
import { closeSync as closeSync21, constants as constants19, fsyncSync as fsyncSync8, lstatSync as lstatSync25, mkdirSync as mkdirSync15, openSync as openSync21, realpathSync as realpathSync14, writeFileSync as writeFileSync14 } from "fs";
|
|
43405
43405
|
import { homedir as homedir15 } from "os";
|
|
43406
|
-
import { dirname as dirname27, join as
|
|
43406
|
+
import { dirname as dirname27, join as join34 } from "path";
|
|
43407
43407
|
function need10(value, code2) {
|
|
43408
43408
|
if (!value)
|
|
43409
43409
|
throw new ReadinessBindingError(code2);
|
|
@@ -43461,7 +43461,7 @@ async function registerTrashReadinessBinding(input2, expectedSHA256) {
|
|
|
43461
43461
|
const operationId = randomUUID8();
|
|
43462
43462
|
let directory2 = home;
|
|
43463
43463
|
for (const part of [".hasna", "hooks", "native", "trash-readiness"]) {
|
|
43464
|
-
directory2 =
|
|
43464
|
+
directory2 = join34(directory2, part);
|
|
43465
43465
|
try {
|
|
43466
43466
|
mkdirSync15(directory2, { mode: 448 });
|
|
43467
43467
|
syncDirectory4(dirname27(directory2));
|
|
@@ -43471,12 +43471,12 @@ async function registerTrashReadinessBinding(input2, expectedSHA256) {
|
|
|
43471
43471
|
}
|
|
43472
43472
|
safeDirectory4(directory2);
|
|
43473
43473
|
}
|
|
43474
|
-
const operation =
|
|
43474
|
+
const operation = join34(directory2, operationId);
|
|
43475
43475
|
mkdirSync15(operation, { mode: 448 });
|
|
43476
43476
|
syncDirectory4(directory2);
|
|
43477
43477
|
if (before)
|
|
43478
|
-
exclusive3(
|
|
43479
|
-
exclusive3(
|
|
43478
|
+
exclusive3(join34(operation, "binding.before"), before.raw);
|
|
43479
|
+
exclusive3(join34(operation, "intent.json"), JSON.stringify({ operationId, target, expectedSHA256, desiredSHA256: digest4 }) + `
|
|
43480
43480
|
`);
|
|
43481
43481
|
try {
|
|
43482
43482
|
need10((read4()?.sha256 ?? "absent") === expectedSHA256, "binding_changed");
|
|
@@ -43490,7 +43490,7 @@ async function registerTrashReadinessBinding(input2, expectedSHA256) {
|
|
|
43490
43490
|
syncDirectory4(directory2);
|
|
43491
43491
|
need10(read4()?.sha256 === digest4, "binding_changed");
|
|
43492
43492
|
const receipt = { ok: true, changed: true, operationId, path: target, sha256: digest4, configurationReady: true, nativeAdoptionVerified: false };
|
|
43493
|
-
exclusive3(
|
|
43493
|
+
exclusive3(join34(operation, "receipt.json"), JSON.stringify(receipt) + `
|
|
43494
43494
|
`);
|
|
43495
43495
|
return receipt;
|
|
43496
43496
|
} catch {
|
|
@@ -43514,7 +43514,7 @@ var init_native_readiness_binding = __esm(() => {
|
|
|
43514
43514
|
|
|
43515
43515
|
// src/cli/index.tsx
|
|
43516
43516
|
init_native_safety_registration();
|
|
43517
|
-
import { resolve as
|
|
43517
|
+
import { resolve as resolve21 } from "path";
|
|
43518
43518
|
|
|
43519
43519
|
// src/lib/claude-safety-check.ts
|
|
43520
43520
|
init_native_safety();
|
|
@@ -43633,25 +43633,16 @@ async function verifyClaudeSafetyConfiguration(options = {}, dependencies = {})
|
|
|
43633
43633
|
// src/cli/index.tsx
|
|
43634
43634
|
init_codex_safety_trust();
|
|
43635
43635
|
|
|
43636
|
-
//
|
|
43636
|
+
// ../../../../validation/build/apps/hooks/node_modules/@hasna/events/dist/commander.js
|
|
43637
43637
|
import { chmod, mkdir, readFile as readFile2, rename, writeFile } from "fs/promises";
|
|
43638
43638
|
import { Buffer as Buffer2 } from "buffer";
|
|
43639
|
-
import { existsSync as existsSync22 } from "fs";
|
|
43640
|
-
import { join as join22 } from "path";
|
|
43641
43639
|
import { existsSync as existsSync13 } from "fs";
|
|
43642
43640
|
import { homedir as homedir13 } from "os";
|
|
43643
|
-
import { join as join20
|
|
43644
|
-
import { homedir as pathsResolverHomedir3 } from "os";
|
|
43645
|
-
import { join as pathsResolverJoin3 } from "path";
|
|
43641
|
+
import { join as join20 } from "path";
|
|
43646
43642
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
43647
|
-
import { lookup as dnsLookup } from "dns/promises";
|
|
43648
|
-
import { isIP } from "net";
|
|
43649
43643
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
43650
43644
|
import { spawn as spawn3 } from "child_process";
|
|
43651
|
-
import { request as nodeHttpRequest } from "http";
|
|
43652
|
-
import { request as nodeHttpsRequest } from "https";
|
|
43653
43645
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
43654
|
-
import { createRequire as createRequire2 } from "module";
|
|
43655
43646
|
function getPathValue(input2, path) {
|
|
43656
43647
|
return path.split(".").reduce((value, part) => {
|
|
43657
43648
|
if (value && typeof value === "object" && part in value) {
|
|
@@ -43747,103 +43738,13 @@ function channelMatchesEvent(channel, event) {
|
|
|
43747
43738
|
return true;
|
|
43748
43739
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
43749
43740
|
}
|
|
43750
|
-
var PATHS_RESOLVER_KIND_ENV2 = {
|
|
43751
|
-
config: "HASNA_CONFIG_HOME",
|
|
43752
|
-
data: "HASNA_DATA_HOME",
|
|
43753
|
-
state: "HASNA_STATE_HOME",
|
|
43754
|
-
cache: "HASNA_CACHE_HOME"
|
|
43755
|
-
};
|
|
43756
|
-
var PATHS_RESOLVER_APP_SLUG_RE3 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
43757
|
-
function pathsResolverAssertApp3(app) {
|
|
43758
|
-
if (typeof app !== "string" || app.length === 0) {
|
|
43759
|
-
throw new TypeError("paths: app must be a non-empty string");
|
|
43760
|
-
}
|
|
43761
|
-
if (!PATHS_RESOLVER_APP_SLUG_RE3.test(app)) {
|
|
43762
|
-
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
43763
|
-
}
|
|
43764
|
-
}
|
|
43765
|
-
function pathsResolverAssertKind2(kind) {
|
|
43766
|
-
if (!Object.keys(PATHS_RESOLVER_KIND_ENV2).includes(kind)) {
|
|
43767
|
-
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV2).join(", ")}`);
|
|
43768
|
-
}
|
|
43769
|
-
}
|
|
43770
|
-
function pathsResolverBaseDir2(kind, options) {
|
|
43771
|
-
pathsResolverAssertKind2(kind);
|
|
43772
|
-
const env = options.env ?? process.env;
|
|
43773
|
-
const override = env[PATHS_RESOLVER_KIND_ENV2[kind]];
|
|
43774
|
-
if (typeof override === "string" && override.length > 0)
|
|
43775
|
-
return override;
|
|
43776
|
-
const home = options.home ?? pathsResolverHomedir3();
|
|
43777
|
-
const platform = options.platform ?? process.platform;
|
|
43778
|
-
if (platform === "darwin") {
|
|
43779
|
-
switch (kind) {
|
|
43780
|
-
case "config":
|
|
43781
|
-
case "data":
|
|
43782
|
-
return pathsResolverJoin3(home, "Library", "Application Support", "Hasna");
|
|
43783
|
-
case "cache":
|
|
43784
|
-
return pathsResolverJoin3(home, "Library", "Caches", "Hasna");
|
|
43785
|
-
case "state":
|
|
43786
|
-
return pathsResolverJoin3(home, "Library", "Logs", "Hasna");
|
|
43787
|
-
}
|
|
43788
|
-
}
|
|
43789
|
-
switch (kind) {
|
|
43790
|
-
case "config":
|
|
43791
|
-
return pathsResolverJoin3(home, ".config", "hasna");
|
|
43792
|
-
case "data":
|
|
43793
|
-
return pathsResolverJoin3(home, ".local", "share", "hasna");
|
|
43794
|
-
case "state":
|
|
43795
|
-
return pathsResolverJoin3(home, ".local", "state", "hasna");
|
|
43796
|
-
case "cache":
|
|
43797
|
-
return pathsResolverJoin3(home, ".cache", "hasna");
|
|
43798
|
-
}
|
|
43799
|
-
}
|
|
43800
|
-
function pathsResolverResolve2(kind, options) {
|
|
43801
|
-
pathsResolverAssertApp3(options.app);
|
|
43802
|
-
const appSegment = options.internal === true ? pathsResolverJoin3("internal", options.app) : options.app;
|
|
43803
|
-
return pathsResolverJoin3(pathsResolverBaseDir2(kind, options), appSegment);
|
|
43804
|
-
}
|
|
43805
|
-
function dataDir3(options) {
|
|
43806
|
-
return pathsResolverResolve2("data", options);
|
|
43807
|
-
}
|
|
43808
43741
|
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
|
|
43809
43742
|
var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
43810
|
-
var EVENTS_STORE_SENTINEL_FILE = "events.json";
|
|
43811
|
-
function effectiveHome2() {
|
|
43812
|
-
return process.env["HOME"] || process.env["USERPROFILE"] || homedir13();
|
|
43813
|
-
}
|
|
43814
|
-
function legacyHomeDir() {
|
|
43815
|
-
return join20(effectiveHome2(), ".hasna", "events");
|
|
43816
|
-
}
|
|
43817
|
-
function resolverHome() {
|
|
43818
|
-
return dataDir3({ app: "events", home: effectiveHome2() || undefined });
|
|
43819
|
-
}
|
|
43820
|
-
function adoptResolverHome(resolved, env = process.env) {
|
|
43821
|
-
const dataOverride = env.HASNA_DATA_HOME;
|
|
43822
|
-
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
43823
|
-
return true;
|
|
43824
|
-
return existsSync13(join20(resolved, EVENTS_STORE_SENTINEL_FILE));
|
|
43825
|
-
}
|
|
43826
|
-
function exactEventsHome() {
|
|
43827
|
-
const dir = process.env[HASNA_EVENTS_DIR_ENV];
|
|
43828
|
-
if (dir && dir.trim())
|
|
43829
|
-
return dir.trim();
|
|
43830
|
-
const home = process.env[HASNA_EVENTS_HOME_ENV];
|
|
43831
|
-
if (home && home.trim())
|
|
43832
|
-
return home.trim();
|
|
43833
|
-
return;
|
|
43834
|
-
}
|
|
43835
|
-
function getEventsHome() {
|
|
43836
|
-
const exact2 = exactEventsHome();
|
|
43837
|
-
if (exact2)
|
|
43838
|
-
return resolve20(exact2);
|
|
43839
|
-
const resolved = resolverHome();
|
|
43840
|
-
return adoptResolverHome(resolved) ? resolve20(resolved) : resolve20(legacyHomeDir());
|
|
43841
|
-
}
|
|
43842
43743
|
var LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:";
|
|
43843
43744
|
var DEFAULT_EVENT_PAGE_LIMIT = 100;
|
|
43844
43745
|
var MAX_EVENT_PAGE_LIMIT = 1000;
|
|
43845
43746
|
function getEventsDataDir(override) {
|
|
43846
|
-
return override ||
|
|
43747
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join20(homedir13(), ".hasna", "events");
|
|
43847
43748
|
}
|
|
43848
43749
|
function getActiveEventsDirEnv() {
|
|
43849
43750
|
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
@@ -43859,12 +43760,12 @@ class JsonEventsStore {
|
|
|
43859
43760
|
channelsPath;
|
|
43860
43761
|
eventsPath;
|
|
43861
43762
|
deliveriesPath;
|
|
43862
|
-
constructor(
|
|
43863
|
-
this.dataDir =
|
|
43864
|
-
this.runtime = localJsonRuntime(
|
|
43865
|
-
this.channelsPath =
|
|
43866
|
-
this.eventsPath =
|
|
43867
|
-
this.deliveriesPath =
|
|
43763
|
+
constructor(dataDir3 = getEventsDataDir()) {
|
|
43764
|
+
this.dataDir = dataDir3;
|
|
43765
|
+
this.runtime = localJsonRuntime(dataDir3);
|
|
43766
|
+
this.channelsPath = join20(dataDir3, "channels.json");
|
|
43767
|
+
this.eventsPath = join20(dataDir3, "events.json");
|
|
43768
|
+
this.deliveriesPath = join20(dataDir3, "deliveries.json");
|
|
43868
43769
|
}
|
|
43869
43770
|
async init() {
|
|
43870
43771
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -43981,7 +43882,7 @@ class JsonEventsStore {
|
|
|
43981
43882
|
};
|
|
43982
43883
|
}
|
|
43983
43884
|
async ensureArrayFile(path) {
|
|
43984
|
-
if (!
|
|
43885
|
+
if (!existsSync13(path)) {
|
|
43985
43886
|
await writeFile(path, `[]
|
|
43986
43887
|
`, { encoding: "utf-8", mode: 384 });
|
|
43987
43888
|
}
|
|
@@ -44011,7 +43912,7 @@ class JsonEventsStore {
|
|
|
44011
43912
|
});
|
|
44012
43913
|
}
|
|
44013
43914
|
}
|
|
44014
|
-
function localJsonRuntime(
|
|
43915
|
+
function localJsonRuntime(dataDir3 = getEventsDataDir()) {
|
|
44015
43916
|
return {
|
|
44016
43917
|
mode: "local-files",
|
|
44017
43918
|
name: "json-events-store",
|
|
@@ -44024,7 +43925,7 @@ function localJsonRuntime(dataDir22 = getEventsDataDir()) {
|
|
|
44024
43925
|
durable: true,
|
|
44025
43926
|
idempotency: "best-effort-local",
|
|
44026
43927
|
replayCursors: true,
|
|
44027
|
-
description: `Local JSON files in ${
|
|
43928
|
+
description: `Local JSON files in ${dataDir3}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
44028
43929
|
};
|
|
44029
43930
|
}
|
|
44030
43931
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -44088,8 +43989,8 @@ function assertCursorFilter(name, cursorValue, optionValue) {
|
|
|
44088
43989
|
function findEventByIdentity(events2, identity3) {
|
|
44089
43990
|
return events2.find((event) => identity3.id !== undefined && event.id === identity3.id || identity3.dedupeKey !== undefined && event.dedupeKey === identity3.dedupeKey);
|
|
44090
43991
|
}
|
|
44091
|
-
async function getEventsStatus(
|
|
44092
|
-
const store = new JsonEventsStore(
|
|
43992
|
+
async function getEventsStatus(dataDir3) {
|
|
43993
|
+
const store = new JsonEventsStore(dataDir3);
|
|
44093
43994
|
await store.init();
|
|
44094
43995
|
const [channels, events2, deliveries] = await Promise.all([
|
|
44095
43996
|
store.listChannels(),
|
|
@@ -44131,9 +44032,9 @@ async function getEventsStatus(dataDir22) {
|
|
|
44131
44032
|
}
|
|
44132
44033
|
};
|
|
44133
44034
|
}
|
|
44134
|
-
function statusFile(
|
|
44135
|
-
const path =
|
|
44136
|
-
return { path, exists:
|
|
44035
|
+
function statusFile(dataDir3, fileName, records) {
|
|
44036
|
+
const path = join20(dataDir3, fileName);
|
|
44037
|
+
return { path, exists: existsSync13(path), records };
|
|
44137
44038
|
}
|
|
44138
44039
|
var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
44139
44040
|
function buildSignatureBase(timestamp, body) {
|
|
@@ -44143,214 +44044,6 @@ function signPayload(secret, timestamp, body) {
|
|
|
44143
44044
|
const digest4 = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
|
|
44144
44045
|
return `sha256=${digest4}`;
|
|
44145
44046
|
}
|
|
44146
|
-
var DEFAULT_MAX_REDIRECTS = 5;
|
|
44147
|
-
var IPV4_PRIVATE_RANGES = [
|
|
44148
|
-
[0, 16777215],
|
|
44149
|
-
[167772160, 184549375],
|
|
44150
|
-
[1681915904, 1686110207],
|
|
44151
|
-
[2130706432, 2147483647],
|
|
44152
|
-
[2851995648, 2852061183],
|
|
44153
|
-
[2886729728, 2887778303],
|
|
44154
|
-
[3221225472, 3221225727],
|
|
44155
|
-
[3221225984, 3221226239],
|
|
44156
|
-
[3227017984, 3227018239],
|
|
44157
|
-
[3232235520, 3232301055],
|
|
44158
|
-
[3323068416, 3323199487],
|
|
44159
|
-
[3325256704, 3325256959],
|
|
44160
|
-
[3405803776, 3405804031],
|
|
44161
|
-
[3758096384, 4294967295]
|
|
44162
|
-
];
|
|
44163
|
-
var IPV6_SPECIAL_PREFIXES = [
|
|
44164
|
-
{ groups: [0, 0, 0, 0, 0, 0, 0, 0], bits: 128 },
|
|
44165
|
-
{ groups: [0, 0, 0, 0, 0, 0, 0, 1], bits: 128 },
|
|
44166
|
-
{ groups: [0, 0, 0, 0, 0, 65535, 0, 0], bits: 96 },
|
|
44167
|
-
{ groups: [100, 65435, 0, 0, 0, 0, 0, 0], bits: 96 },
|
|
44168
|
-
{ groups: [256, 0, 0, 0, 0, 0, 0, 0], bits: 64 },
|
|
44169
|
-
{ groups: [8193, 0, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
44170
|
-
{ groups: [8193, 2, 0, 0, 0, 0, 0, 0], bits: 48 },
|
|
44171
|
-
{ groups: [8193, 16, 0, 0, 0, 0, 0, 0], bits: 28 },
|
|
44172
|
-
{ groups: [8193, 3512, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
44173
|
-
{ groups: [8194, 0, 0, 0, 0, 0, 0, 0], bits: 16 },
|
|
44174
|
-
{ groups: [16383, 0, 0, 0, 0, 0, 0, 0], bits: 20 },
|
|
44175
|
-
{ groups: [64512, 0, 0, 0, 0, 0, 0, 0], bits: 7 },
|
|
44176
|
-
{ groups: [65152, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
44177
|
-
{ groups: [65216, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
44178
|
-
{ groups: [65280, 0, 0, 0, 0, 0, 0, 0], bits: 8 }
|
|
44179
|
-
];
|
|
44180
|
-
function isPrivateAddress(address) {
|
|
44181
|
-
const normalized = stripZoneId(address);
|
|
44182
|
-
const version2 = isIP(normalized);
|
|
44183
|
-
if (version2 === 4) {
|
|
44184
|
-
const integer3 = ipv4ToInt(normalized);
|
|
44185
|
-
if (integer3 === undefined)
|
|
44186
|
-
return true;
|
|
44187
|
-
return IPV4_PRIVATE_RANGES.some(([low, high]) => integer3 >= low && integer3 <= high);
|
|
44188
|
-
}
|
|
44189
|
-
if (version2 === 6) {
|
|
44190
|
-
const groups = ipv6Groups(normalized);
|
|
44191
|
-
if (!groups)
|
|
44192
|
-
return true;
|
|
44193
|
-
for (const prefix3 of IPV6_SPECIAL_PREFIXES) {
|
|
44194
|
-
if (!ipv6MatchesPrefix(groups, prefix3.groups, prefix3.bits))
|
|
44195
|
-
continue;
|
|
44196
|
-
if (prefix3.bits === 96 && groups[5] === 65535) {
|
|
44197
|
-
return isPrivateAddress(ipv4IntToString(groups[6] << 16 | groups[7]));
|
|
44198
|
-
}
|
|
44199
|
-
if (prefix3.bits === 16 && groups[0] === 8194) {
|
|
44200
|
-
return isPrivateAddress(ipv4IntToString(groups[1] << 16 | groups[2]));
|
|
44201
|
-
}
|
|
44202
|
-
return true;
|
|
44203
|
-
}
|
|
44204
|
-
return false;
|
|
44205
|
-
}
|
|
44206
|
-
return true;
|
|
44207
|
-
}
|
|
44208
|
-
async function resolveWebhookTarget(url2, policy = {}) {
|
|
44209
|
-
const hostname3 = normalizeHostname(url2.hostname);
|
|
44210
|
-
const allowlist = (policy.allowPrivateHosts ?? []).map((entry) => normalizeHostname(entry.toLowerCase()));
|
|
44211
|
-
if (allowlist.includes(hostname3)) {
|
|
44212
|
-
const version22 = isIP(hostname3);
|
|
44213
|
-
if (version22 === 4 || version22 === 6) {
|
|
44214
|
-
return { hostname: hostname3, addresses: [hostname3] };
|
|
44215
|
-
}
|
|
44216
|
-
const lookup2 = policy.lookup ?? defaultTargetLookup;
|
|
44217
|
-
let resolved2;
|
|
44218
|
-
try {
|
|
44219
|
-
resolved2 = await lookup2(hostname3);
|
|
44220
|
-
} catch {
|
|
44221
|
-
throw new Error(`Webhook target ${hostname3} could not be resolved`);
|
|
44222
|
-
}
|
|
44223
|
-
if (!Array.isArray(resolved2) || resolved2.length === 0) {
|
|
44224
|
-
throw new Error(`Webhook target ${hostname3} resolved to no addresses`);
|
|
44225
|
-
}
|
|
44226
|
-
const addresses = resolved2.map((entry) => normalizeHostname(entry.address));
|
|
44227
|
-
return { hostname: hostname3, addresses };
|
|
44228
|
-
}
|
|
44229
|
-
const version2 = isIP(hostname3);
|
|
44230
|
-
if (version2 === 4 || version2 === 6) {
|
|
44231
|
-
if (isPrivateAddress(hostname3)) {
|
|
44232
|
-
throw new Error(`Webhook target ${hostname3} is a private or special-use address`);
|
|
44233
|
-
}
|
|
44234
|
-
return { hostname: hostname3, addresses: [hostname3] };
|
|
44235
|
-
}
|
|
44236
|
-
const lookup = policy.lookup ?? defaultTargetLookup;
|
|
44237
|
-
let resolved;
|
|
44238
|
-
try {
|
|
44239
|
-
resolved = await lookup(hostname3);
|
|
44240
|
-
} catch {
|
|
44241
|
-
throw new Error(`Webhook target ${hostname3} could not be resolved`);
|
|
44242
|
-
}
|
|
44243
|
-
if (!Array.isArray(resolved) || resolved.length === 0) {
|
|
44244
|
-
throw new Error(`Webhook target ${hostname3} resolved to no addresses`);
|
|
44245
|
-
}
|
|
44246
|
-
const allowed = [];
|
|
44247
|
-
for (const entry of resolved) {
|
|
44248
|
-
const address = normalizeHostname(entry.address);
|
|
44249
|
-
if (isPrivateAddress(address)) {
|
|
44250
|
-
if (allowlist.includes(address)) {
|
|
44251
|
-
allowed.push(address);
|
|
44252
|
-
continue;
|
|
44253
|
-
}
|
|
44254
|
-
throw new Error(`Webhook target ${hostname3} resolves to private or special-use address ${address}`);
|
|
44255
|
-
}
|
|
44256
|
-
allowed.push(address);
|
|
44257
|
-
}
|
|
44258
|
-
if (allowed.length === 0) {
|
|
44259
|
-
throw new Error(`Webhook target ${hostname3} resolved to no public addresses`);
|
|
44260
|
-
}
|
|
44261
|
-
return { hostname: hostname3, addresses: allowed };
|
|
44262
|
-
}
|
|
44263
|
-
function normalizeMaxRedirects(value) {
|
|
44264
|
-
if (value === undefined)
|
|
44265
|
-
return DEFAULT_MAX_REDIRECTS;
|
|
44266
|
-
if (!Number.isInteger(value) || value < 0)
|
|
44267
|
-
throw new Error("webhookTargetPolicy.maxRedirects must be a non-negative integer");
|
|
44268
|
-
return value;
|
|
44269
|
-
}
|
|
44270
|
-
var defaultTargetLookup = async (hostname3) => {
|
|
44271
|
-
return dnsLookup(hostname3, { all: true, verbatim: false });
|
|
44272
|
-
};
|
|
44273
|
-
function normalizeHostname(hostname3) {
|
|
44274
|
-
const lower = hostname3.toLowerCase();
|
|
44275
|
-
if (lower.startsWith("[") && lower.endsWith("]"))
|
|
44276
|
-
return lower.slice(1, -1);
|
|
44277
|
-
return lower;
|
|
44278
|
-
}
|
|
44279
|
-
function stripZoneId(address) {
|
|
44280
|
-
const percent = address.indexOf("%");
|
|
44281
|
-
return percent === -1 ? address : address.slice(0, percent);
|
|
44282
|
-
}
|
|
44283
|
-
function ipv4ToInt(address) {
|
|
44284
|
-
const parts = address.split(".");
|
|
44285
|
-
if (parts.length !== 4)
|
|
44286
|
-
return;
|
|
44287
|
-
let value = 0;
|
|
44288
|
-
for (const part of parts) {
|
|
44289
|
-
if (!/^\d{1,3}$/.test(part))
|
|
44290
|
-
return;
|
|
44291
|
-
const octet = Number(part);
|
|
44292
|
-
if (octet > 255)
|
|
44293
|
-
return;
|
|
44294
|
-
value = value << 8 | octet;
|
|
44295
|
-
}
|
|
44296
|
-
return value >>> 0;
|
|
44297
|
-
}
|
|
44298
|
-
function ipv4IntToString(integer3) {
|
|
44299
|
-
return [
|
|
44300
|
-
integer3 >>> 24 & 255,
|
|
44301
|
-
integer3 >>> 16 & 255,
|
|
44302
|
-
integer3 >>> 8 & 255,
|
|
44303
|
-
integer3 & 255
|
|
44304
|
-
].join(".");
|
|
44305
|
-
}
|
|
44306
|
-
function ipv6Groups(address) {
|
|
44307
|
-
const raw = stripZoneId(address);
|
|
44308
|
-
const doubleColon = raw.indexOf("::");
|
|
44309
|
-
const headText = doubleColon === -1 ? raw : raw.slice(0, doubleColon);
|
|
44310
|
-
const tailText = doubleColon === -1 ? "" : raw.slice(doubleColon + 2);
|
|
44311
|
-
const parseGroups = (text3) => {
|
|
44312
|
-
if (text3 === "")
|
|
44313
|
-
return [];
|
|
44314
|
-
const out = [];
|
|
44315
|
-
for (const part of text3.split(":")) {
|
|
44316
|
-
if (part.includes(".")) {
|
|
44317
|
-
const v4 = ipv4ToInt(part);
|
|
44318
|
-
if (v4 === undefined)
|
|
44319
|
-
return;
|
|
44320
|
-
out.push(v4 >>> 16 & 65535, v4 & 65535);
|
|
44321
|
-
} else {
|
|
44322
|
-
if (!/^[0-9a-fA-F]{1,4}$/.test(part))
|
|
44323
|
-
return;
|
|
44324
|
-
out.push(parseInt(part, 16));
|
|
44325
|
-
}
|
|
44326
|
-
}
|
|
44327
|
-
return out;
|
|
44328
|
-
};
|
|
44329
|
-
const head = parseGroups(headText);
|
|
44330
|
-
if (!head)
|
|
44331
|
-
return;
|
|
44332
|
-
const tail = parseGroups(tailText);
|
|
44333
|
-
if (!tail)
|
|
44334
|
-
return;
|
|
44335
|
-
const total = head.length + tail.length;
|
|
44336
|
-
if (doubleColon === -1) {
|
|
44337
|
-
return total === 8 ? head : undefined;
|
|
44338
|
-
}
|
|
44339
|
-
if (total >= 8)
|
|
44340
|
-
return;
|
|
44341
|
-
return [...head, ...new Array(8 - total).fill(0), ...tail];
|
|
44342
|
-
}
|
|
44343
|
-
function ipv6MatchesPrefix(groups, prefixGroups, prefixBits) {
|
|
44344
|
-
let remaining = prefixBits;
|
|
44345
|
-
for (let index = 0;index < prefixGroups.length && remaining > 0; index += 1) {
|
|
44346
|
-
const take = Math.min(16, remaining);
|
|
44347
|
-
const mask = 65535 << 16 - take & 65535;
|
|
44348
|
-
if ((groups[index] & mask) !== (prefixGroups[index] & mask))
|
|
44349
|
-
return false;
|
|
44350
|
-
remaining -= take;
|
|
44351
|
-
}
|
|
44352
|
-
return true;
|
|
44353
|
-
}
|
|
44354
44047
|
function now() {
|
|
44355
44048
|
return new Date().toISOString();
|
|
44356
44049
|
}
|
|
@@ -44381,18 +44074,9 @@ function buildWebhookRequest(event, channel, options = {}) {
|
|
|
44381
44074
|
}
|
|
44382
44075
|
return { body, headers };
|
|
44383
44076
|
}
|
|
44384
|
-
function normalizeWebhookUrl(raw) {
|
|
44385
|
-
const url2 = new URL(raw);
|
|
44386
|
-
if (url2.username !== "" || url2.password !== "") {
|
|
44387
|
-
url2.username = "";
|
|
44388
|
-
url2.password = "";
|
|
44389
|
-
}
|
|
44390
|
-
return url2.toString();
|
|
44391
|
-
}
|
|
44392
44077
|
async function dispatchWebhook(event, channel, options = {}) {
|
|
44393
44078
|
if (!channel.webhook)
|
|
44394
44079
|
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
44395
|
-
const webhookUrl = normalizeWebhookUrl(channel.webhook.url);
|
|
44396
44080
|
const startedAt = now();
|
|
44397
44081
|
let secret = channel.webhook.secret;
|
|
44398
44082
|
if (channel.webhook.secretRef) {
|
|
@@ -44409,14 +44093,10 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
44409
44093
|
}
|
|
44410
44094
|
const timestamp = (options.now?.() ?? new Date).toISOString();
|
|
44411
44095
|
const { body, headers } = buildWebhookRequest(event, channel, { secret, timestamp });
|
|
44412
|
-
const validateTargets = options.webhookTargetPolicy !== undefined || options.fetchImpl === undefined;
|
|
44413
|
-
if (validateTargets) {
|
|
44414
|
-
return dispatchValidatedWebhook(event, channel, { body, headers, startedAt, options });
|
|
44415
|
-
}
|
|
44416
44096
|
const controller = new AbortController;
|
|
44417
44097
|
const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
|
|
44418
44098
|
try {
|
|
44419
|
-
const response = await (options.fetchImpl ?? fetch)(
|
|
44099
|
+
const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
|
|
44420
44100
|
method: "POST",
|
|
44421
44101
|
headers,
|
|
44422
44102
|
body,
|
|
@@ -44444,130 +44124,6 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
44444
44124
|
clearTimeout(timeout);
|
|
44445
44125
|
}
|
|
44446
44126
|
}
|
|
44447
|
-
function isRedirectStatus(status) {
|
|
44448
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
44449
|
-
}
|
|
44450
|
-
function redirectKeepsBody(status) {
|
|
44451
|
-
return status === 307 || status === 308;
|
|
44452
|
-
}
|
|
44453
|
-
async function pinnedNativeRequest(target, addresses, method, headers, body, signal, tls) {
|
|
44454
|
-
const isHttps = target.protocol === "https:";
|
|
44455
|
-
if (!isHttps && target.protocol !== "http:") {
|
|
44456
|
-
throw new Error(`Webhook target uses unsupported protocol ${target.protocol}`);
|
|
44457
|
-
}
|
|
44458
|
-
const defaultPort = isHttps ? 443 : 80;
|
|
44459
|
-
const port = target.port ? Number(target.port) : defaultPort;
|
|
44460
|
-
const requestOptions = {
|
|
44461
|
-
hostname: target.hostname,
|
|
44462
|
-
port,
|
|
44463
|
-
path: `${target.pathname}${target.search}`,
|
|
44464
|
-
method,
|
|
44465
|
-
headers,
|
|
44466
|
-
...tls?.ca ? { ca: tls.ca } : {},
|
|
44467
|
-
lookup: (hostname3, _options, callback) => {
|
|
44468
|
-
const entries = addresses.map((address) => ({
|
|
44469
|
-
address,
|
|
44470
|
-
family: address.includes(":") ? 6 : 4
|
|
44471
|
-
}));
|
|
44472
|
-
callback(null, entries);
|
|
44473
|
-
}
|
|
44474
|
-
};
|
|
44475
|
-
return new Promise((resolve23, reject) => {
|
|
44476
|
-
const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
|
|
44477
|
-
const onAbort = () => {
|
|
44478
|
-
const error61 = new Error("The operation was aborted.");
|
|
44479
|
-
error61.name = "AbortError";
|
|
44480
|
-
request.destroy(error61);
|
|
44481
|
-
};
|
|
44482
|
-
if (signal.aborted)
|
|
44483
|
-
onAbort();
|
|
44484
|
-
else
|
|
44485
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
44486
|
-
request.on("error", reject);
|
|
44487
|
-
if (body !== undefined)
|
|
44488
|
-
request.write(body);
|
|
44489
|
-
request.end();
|
|
44490
|
-
function onResponse(response) {
|
|
44491
|
-
const chunks = [];
|
|
44492
|
-
response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
44493
|
-
response.on("error", reject);
|
|
44494
|
-
response.on("end", () => {
|
|
44495
|
-
const headersRecord = {};
|
|
44496
|
-
for (const [name, value] of Object.entries(response.headers)) {
|
|
44497
|
-
if (typeof value === "string")
|
|
44498
|
-
headersRecord[name] = value;
|
|
44499
|
-
else if (Array.isArray(value))
|
|
44500
|
-
headersRecord[name] = value.join(", ");
|
|
44501
|
-
}
|
|
44502
|
-
resolve23(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
|
|
44503
|
-
});
|
|
44504
|
-
}
|
|
44505
|
-
});
|
|
44506
|
-
}
|
|
44507
|
-
async function dispatchValidatedWebhook(event, channel, input2) {
|
|
44508
|
-
const { body, headers, startedAt, options } = input2;
|
|
44509
|
-
const webhook = channel.webhook;
|
|
44510
|
-
if (!webhook)
|
|
44511
|
-
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
44512
|
-
const policy = options.webhookTargetPolicy ?? {};
|
|
44513
|
-
const maxRedirects = normalizeMaxRedirects(policy.maxRedirects);
|
|
44514
|
-
const controller = new AbortController;
|
|
44515
|
-
const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs ?? 15000);
|
|
44516
|
-
try {
|
|
44517
|
-
let target = new URL(normalizeWebhookUrl(webhook.url));
|
|
44518
|
-
let requestHeaders = headers;
|
|
44519
|
-
let method = "POST";
|
|
44520
|
-
let requestBody = body;
|
|
44521
|
-
let redirectsFollowed = 0;
|
|
44522
|
-
for (;; ) {
|
|
44523
|
-
const resolved = await resolveWebhookTarget(target, policy).catch((error61) => {
|
|
44524
|
-
throw new Error(`Webhook target rejected by SSRF guard: ${error61.message}`);
|
|
44525
|
-
});
|
|
44526
|
-
const response = options.fetchImpl ? await options.fetchImpl(target, {
|
|
44527
|
-
method,
|
|
44528
|
-
headers: requestHeaders,
|
|
44529
|
-
body: requestBody,
|
|
44530
|
-
signal: controller.signal,
|
|
44531
|
-
redirect: "manual"
|
|
44532
|
-
}) : await pinnedNativeRequest(target, resolved.addresses, method, requestHeaders, requestBody, controller.signal, options.tls);
|
|
44533
|
-
const location = response.headers.get("location");
|
|
44534
|
-
if (isRedirectStatus(response.status) && location) {
|
|
44535
|
-
if (redirectsFollowed >= maxRedirects) {
|
|
44536
|
-
return failedAttempt(startedAt, `Webhook target exceeded ${maxRedirects} redirects`);
|
|
44537
|
-
}
|
|
44538
|
-
redirectsFollowed += 1;
|
|
44539
|
-
const next = new URL(location, target);
|
|
44540
|
-
target = next;
|
|
44541
|
-
if (!redirectKeepsBody(response.status)) {
|
|
44542
|
-
method = "GET";
|
|
44543
|
-
requestBody = undefined;
|
|
44544
|
-
requestHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => name.toLowerCase() !== "content-type" && name.toLowerCase() !== "content-length"));
|
|
44545
|
-
}
|
|
44546
|
-
continue;
|
|
44547
|
-
}
|
|
44548
|
-
const responseBody = truncate(await response.text());
|
|
44549
|
-
return {
|
|
44550
|
-
attempt: 1,
|
|
44551
|
-
status: response.ok ? "success" : "failed",
|
|
44552
|
-
startedAt,
|
|
44553
|
-
completedAt: now(),
|
|
44554
|
-
responseStatus: response.status,
|
|
44555
|
-
responseBody,
|
|
44556
|
-
error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
|
|
44557
|
-
};
|
|
44558
|
-
}
|
|
44559
|
-
} catch (error61) {
|
|
44560
|
-
return {
|
|
44561
|
-
attempt: 1,
|
|
44562
|
-
status: "failed",
|
|
44563
|
-
startedAt,
|
|
44564
|
-
completedAt: now(),
|
|
44565
|
-
error: error61 instanceof Error ? error61.message : String(error61)
|
|
44566
|
-
};
|
|
44567
|
-
} finally {
|
|
44568
|
-
clearTimeout(timeout);
|
|
44569
|
-
}
|
|
44570
|
-
}
|
|
44571
44127
|
function failedAttempt(startedAt, error61) {
|
|
44572
44128
|
return {
|
|
44573
44129
|
attempt: 1,
|
|
@@ -44596,7 +44152,7 @@ async function dispatchCommand(event, channel) {
|
|
|
44596
44152
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
44597
44153
|
HASNA_EVENT_JSON: eventJson
|
|
44598
44154
|
};
|
|
44599
|
-
return new Promise((
|
|
44155
|
+
return new Promise((resolve16) => {
|
|
44600
44156
|
const child = spawn3(channel.command.command, channel.command.args ?? [], {
|
|
44601
44157
|
cwd: channel.command.cwd,
|
|
44602
44158
|
env,
|
|
@@ -44614,7 +44170,7 @@ async function dispatchCommand(event, channel) {
|
|
|
44614
44170
|
});
|
|
44615
44171
|
child.on("error", (error61) => {
|
|
44616
44172
|
clearTimeout(timeout);
|
|
44617
|
-
|
|
44173
|
+
resolve16({
|
|
44618
44174
|
attempt: 1,
|
|
44619
44175
|
status: "failed",
|
|
44620
44176
|
startedAt,
|
|
@@ -44627,7 +44183,7 @@ async function dispatchCommand(event, channel) {
|
|
|
44627
44183
|
child.on("close", (code2, signal) => {
|
|
44628
44184
|
clearTimeout(timeout);
|
|
44629
44185
|
const success2 = code2 === 0;
|
|
44630
|
-
|
|
44186
|
+
resolve16({
|
|
44631
44187
|
attempt: 1,
|
|
44632
44188
|
status: success2 ? "success" : "failed",
|
|
44633
44189
|
startedAt,
|
|
@@ -44749,22 +44305,6 @@ function setPath(input2, path, replacement) {
|
|
|
44749
44305
|
if (last && last in cursor)
|
|
44750
44306
|
cursor[last] = replacement;
|
|
44751
44307
|
}
|
|
44752
|
-
var MAX_PACKAGE_BYTES2 = 1024 * 1024;
|
|
44753
|
-
var MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
|
|
44754
|
-
var INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
|
|
44755
|
-
var CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
|
|
44756
|
-
var AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
44757
|
-
var requireSecretsSdk2 = createRequire2(import.meta.url);
|
|
44758
|
-
var IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
44759
|
-
var AUTHORITY_OVERRIDE_HEADERS2 = new Set([
|
|
44760
|
-
"host",
|
|
44761
|
-
":authority",
|
|
44762
|
-
"forwarded",
|
|
44763
|
-
"x-forwarded-host",
|
|
44764
|
-
"x-original-host"
|
|
44765
|
-
]);
|
|
44766
|
-
var MAX_ENVELOPE_BYTES = 256 * 1024;
|
|
44767
|
-
var MAX_REQUEST_BYTES = MAX_ENVELOPE_BYTES * 2 + 8192;
|
|
44768
44308
|
function createEvent(input2) {
|
|
44769
44309
|
return {
|
|
44770
44310
|
id: input2.id ?? randomUUID22(),
|
|
@@ -44793,9 +44333,7 @@ class EventsClient {
|
|
|
44793
44333
|
this.transportOptions = {
|
|
44794
44334
|
fetchImpl: options.fetchImpl,
|
|
44795
44335
|
secretResolver: options.secretResolver,
|
|
44796
|
-
now: options.now
|
|
44797
|
-
tls: options.tls,
|
|
44798
|
-
webhookTargetPolicy: options.webhookTargetPolicy
|
|
44336
|
+
now: options.now
|
|
44799
44337
|
};
|
|
44800
44338
|
this.catalog = options.catalog ?? defaultEventTypeCatalog;
|
|
44801
44339
|
this.validateCatalogTypes = options.validateCatalogTypes ?? false;
|
|
@@ -45082,13 +44620,6 @@ function parseMatcherExpression(value, label) {
|
|
|
45082
44620
|
negated: false
|
|
45083
44621
|
};
|
|
45084
44622
|
}
|
|
45085
|
-
function webhookTargetPolicyFromEnv() {
|
|
45086
|
-
const value = process.env.HASNA_EVENTS_ALLOW_PRIVATE_WEBHOOK_TARGETS;
|
|
45087
|
-
if (!value)
|
|
45088
|
-
return;
|
|
45089
|
-
const hosts = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
45090
|
-
return hosts.length > 0 ? { allowPrivateHosts: hosts } : undefined;
|
|
45091
|
-
}
|
|
45092
44623
|
var DEFAULT_EVENT_LIST_LIMIT = 100;
|
|
45093
44624
|
function parseJsonObject(value, fallback) {
|
|
45094
44625
|
if (!value)
|
|
@@ -45114,7 +44645,7 @@ function parseHeaders(values) {
|
|
|
45114
44645
|
function createClient(options) {
|
|
45115
44646
|
if (options.createClient)
|
|
45116
44647
|
return options.createClient();
|
|
45117
|
-
return new EventsClient({ store: new JsonEventsStore(options.dataDir)
|
|
44648
|
+
return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
|
|
45118
44649
|
}
|
|
45119
44650
|
function print(value, json2, text3) {
|
|
45120
44651
|
if (json2)
|
|
@@ -45195,8 +44726,6 @@ function registerChannelCommands(program2, options) {
|
|
|
45195
44726
|
metadata: parseJsonObject(actionOptions.metadata, {})
|
|
45196
44727
|
}, { honorFilters: actionOptions.honorFilters });
|
|
45197
44728
|
print(result, json2, `${result.status}: ${result.channelId}`);
|
|
45198
|
-
if (result.status === "failed")
|
|
45199
|
-
process.exitCode = 1;
|
|
45200
44729
|
} catch (error61) {
|
|
45201
44730
|
fail(error61, json2);
|
|
45202
44731
|
}
|
|
@@ -45289,7 +44818,7 @@ function replaySummary(events2, deliveries, nextCursor) {
|
|
|
45289
44818
|
// src/cli/index.tsx
|
|
45290
44819
|
import { render } from "ink";
|
|
45291
44820
|
|
|
45292
|
-
//
|
|
44821
|
+
// ../../../../validation/build/apps/hooks/node_modules/commander/esm.mjs
|
|
45293
44822
|
var import__ = __toESM(require_commander(), 1);
|
|
45294
44823
|
var {
|
|
45295
44824
|
program: program2,
|
|
@@ -45308,18 +44837,18 @@ var {
|
|
|
45308
44837
|
// src/cli/index.tsx
|
|
45309
44838
|
import chalk2 from "chalk";
|
|
45310
44839
|
import { existsSync as existsSync18, readFileSync as readFileSync27, rmSync as rmSync6 } from "fs";
|
|
45311
|
-
import { join as
|
|
44840
|
+
import { join as join35, dirname as dirname28 } from "path";
|
|
45312
44841
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
45313
44842
|
|
|
45314
44843
|
// src/cli/components/App.tsx
|
|
45315
44844
|
import { useState as useState7 } from "react";
|
|
45316
44845
|
import { Box as Box8, Text as Text10, useApp, useInput as useInput5 } from "ink";
|
|
45317
44846
|
|
|
45318
|
-
//
|
|
44847
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-select-input/build/Indicator.js
|
|
45319
44848
|
import React from "react";
|
|
45320
44849
|
import { Box, Text } from "ink";
|
|
45321
44850
|
|
|
45322
|
-
//
|
|
44851
|
+
// ../../../../validation/build/apps/hooks/node_modules/is-unicode-supported/index.js
|
|
45323
44852
|
import process3 from "process";
|
|
45324
44853
|
function isUnicodeSupported() {
|
|
45325
44854
|
const { env } = process3;
|
|
@@ -45330,7 +44859,7 @@ function isUnicodeSupported() {
|
|
|
45330
44859
|
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";
|
|
45331
44860
|
}
|
|
45332
44861
|
|
|
45333
|
-
//
|
|
44862
|
+
// ../../../../validation/build/apps/hooks/node_modules/figures/index.js
|
|
45334
44863
|
var common2 = {
|
|
45335
44864
|
circleQuestionMark: "(?)",
|
|
45336
44865
|
questionMarkPrefix: "(?)",
|
|
@@ -45606,23 +45135,23 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
|
|
|
45606
45135
|
var figures_default = figures;
|
|
45607
45136
|
var replacements = Object.entries(specialMainSymbols);
|
|
45608
45137
|
|
|
45609
|
-
//
|
|
45138
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-select-input/build/Indicator.js
|
|
45610
45139
|
function Indicator({ isSelected = false }) {
|
|
45611
45140
|
return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures_default.pointer) : React.createElement(Text, null, " "));
|
|
45612
45141
|
}
|
|
45613
45142
|
var Indicator_default = Indicator;
|
|
45614
|
-
//
|
|
45143
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-select-input/build/Item.js
|
|
45615
45144
|
import * as React2 from "react";
|
|
45616
45145
|
import { Text as Text2 } from "ink";
|
|
45617
45146
|
function Item({ isSelected = false, label }) {
|
|
45618
45147
|
return React2.createElement(Text2, { color: isSelected ? "blue" : undefined }, label);
|
|
45619
45148
|
}
|
|
45620
45149
|
var Item_default = Item;
|
|
45621
|
-
//
|
|
45150
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-select-input/build/SelectInput.js
|
|
45622
45151
|
import { isDeepStrictEqual } from "util";
|
|
45623
45152
|
import React3, { useState, useEffect, useRef, useCallback } from "react";
|
|
45624
45153
|
|
|
45625
|
-
//
|
|
45154
|
+
// ../../../../validation/build/apps/hooks/node_modules/to-rotated/index.js
|
|
45626
45155
|
function toRotated(array3, steps) {
|
|
45627
45156
|
if (!Array.isArray(array3)) {
|
|
45628
45157
|
throw new TypeError(`Expected an array, got \`${typeof array3}\`.`);
|
|
@@ -45644,7 +45173,7 @@ function toRotated(array3, steps) {
|
|
|
45644
45173
|
];
|
|
45645
45174
|
}
|
|
45646
45175
|
|
|
45647
|
-
//
|
|
45176
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-select-input/build/SelectInput.js
|
|
45648
45177
|
import { Box as Box2, useInput } from "ink";
|
|
45649
45178
|
function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator_default, itemComponent = Item_default, limit: customLimit, onSelect, onHighlight }) {
|
|
45650
45179
|
const hasLimit = typeof customLimit === "number" && items.length > customLimit;
|
|
@@ -45940,7 +45469,7 @@ function HookSelect({
|
|
|
45940
45469
|
import { useState as useState4, useEffect as useEffect3 } from "react";
|
|
45941
45470
|
import { Box as Box6, Text as Text7, useInput as useInput4 } from "ink";
|
|
45942
45471
|
|
|
45943
|
-
//
|
|
45472
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-text-input/build/index.js
|
|
45944
45473
|
import React5, { useState as useState3, useEffect as useEffect2 } from "react";
|
|
45945
45474
|
import { Text as Text6, useInput as useInput3 } from "ink";
|
|
45946
45475
|
import chalk from "chalk";
|
|
@@ -46118,7 +45647,7 @@ function SearchView({
|
|
|
46118
45647
|
import { useState as useState6, useEffect as useEffect5 } from "react";
|
|
46119
45648
|
import { Box as Box7, Text as Text9 } from "ink";
|
|
46120
45649
|
|
|
46121
|
-
//
|
|
45650
|
+
// ../../../../validation/build/apps/hooks/node_modules/ink-spinner/build/index.js
|
|
46122
45651
|
var import_cli_spinners = __toESM(require_cli_spinners(), 1);
|
|
46123
45652
|
import React7, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
46124
45653
|
import { Text as Text8 } from "ink";
|
|
@@ -46485,10 +46014,10 @@ init_native_safety();
|
|
|
46485
46014
|
|
|
46486
46015
|
// src/lib/sumi-binding.ts
|
|
46487
46016
|
import { homedir as homedir14 } from "os";
|
|
46488
|
-
import { join as
|
|
46017
|
+
import { join as join24, sep as sep3 } from "path";
|
|
46489
46018
|
|
|
46490
46019
|
// hooks/hook-trash-guard/src/binary.ts
|
|
46491
|
-
import { dirname as dirname21, isAbsolute as isAbsolute20, join as
|
|
46020
|
+
import { dirname as dirname21, isAbsolute as isAbsolute20, join as join22, resolve as resolve20 } from "path";
|
|
46492
46021
|
import { accessSync, closeSync as closeSync19, constants as constants18, fstatSync as fstatSync18, lstatSync as lstatSync23, openSync as openSync19, readFileSync as readFileSync17, readlinkSync as readlinkSync3, readSync as readSync3, realpathSync as realpathSync11, statSync } from "fs";
|
|
46493
46022
|
import { spawnSync } from "child_process";
|
|
46494
46023
|
function trustedOwner(uid2) {
|
|
@@ -46510,7 +46039,7 @@ function safeExecutableFile(path, systemBinAlias = false) {
|
|
|
46510
46039
|
parent = dirname21(parent);
|
|
46511
46040
|
continue;
|
|
46512
46041
|
}
|
|
46513
|
-
const next =
|
|
46042
|
+
const next = join22(parent, part), info2 = lstatSync23(next);
|
|
46514
46043
|
if (systemBinAlias && next === "/bin" && info2.isSymbolicLink() && info2.uid === 0) {
|
|
46515
46044
|
const target = realpathSync11(next);
|
|
46516
46045
|
if (!safeBinaryDirectory(target))
|
|
@@ -46522,7 +46051,7 @@ function safeExecutableFile(path, systemBinAlias = false) {
|
|
|
46522
46051
|
return false;
|
|
46523
46052
|
parent = next;
|
|
46524
46053
|
}
|
|
46525
|
-
const candidate =
|
|
46054
|
+
const candidate = join22(parent, name), info = lstatSync23(candidate);
|
|
46526
46055
|
if (!trustedOwner(info.uid))
|
|
46527
46056
|
return false;
|
|
46528
46057
|
if (info.isSymbolicLink()) {
|
|
@@ -46535,9 +46064,9 @@ function safeExecutableFile(path, systemBinAlias = false) {
|
|
|
46535
46064
|
return false;
|
|
46536
46065
|
}
|
|
46537
46066
|
function safeInterpreterSearchDirectory(path) {
|
|
46538
|
-
if (!isAbsolute20(path) ||
|
|
46067
|
+
if (!isAbsolute20(path) || resolve20(path) !== (path.replace(/\/+$/, "") || "/"))
|
|
46539
46068
|
return false;
|
|
46540
|
-
for (let cursor =
|
|
46069
|
+
for (let cursor = resolve20(path);; cursor = dirname21(cursor)) {
|
|
46541
46070
|
try {
|
|
46542
46071
|
lstatSync23(cursor);
|
|
46543
46072
|
return safeBinaryDirectory(cursor);
|
|
@@ -46569,7 +46098,7 @@ function safeScriptInterpreter(executable2, pathValue) {
|
|
|
46569
46098
|
for (const dir of pathValue.split(":").slice(0, 64)) {
|
|
46570
46099
|
if (!safeInterpreterSearchDirectory(dir))
|
|
46571
46100
|
return false;
|
|
46572
|
-
const interpreter =
|
|
46101
|
+
const interpreter = resolve20(dir, "bun");
|
|
46573
46102
|
try {
|
|
46574
46103
|
if (!statSync(interpreter).isFile())
|
|
46575
46104
|
continue;
|
|
@@ -46604,7 +46133,7 @@ function inspectTrashBinary(env = process.env) {
|
|
|
46604
46133
|
for (const dir of pathValue.split(":").slice(0, 64)) {
|
|
46605
46134
|
if (!isAbsolute20(dir) || Date.now() >= deadline)
|
|
46606
46135
|
continue;
|
|
46607
|
-
const candidate =
|
|
46136
|
+
const candidate = resolve20(dir, "trash");
|
|
46608
46137
|
try {
|
|
46609
46138
|
const stat2 = statSync(candidate);
|
|
46610
46139
|
if (!stat2.isFile() || !trustedOwner(stat2.uid) || (stat2.mode & 73) === 0 || (stat2.mode & 18) !== 0) {
|
|
@@ -46612,7 +46141,7 @@ function inspectTrashBinary(env = process.env) {
|
|
|
46612
46141
|
continue;
|
|
46613
46142
|
}
|
|
46614
46143
|
const executable2 = realpathSync11(candidate);
|
|
46615
|
-
if (!safeBinaryDirectory(
|
|
46144
|
+
if (!safeBinaryDirectory(resolve20(dir)) || !safeBinaryDirectory(dirname21(executable2))) {
|
|
46616
46145
|
reject("unsafe_directory");
|
|
46617
46146
|
continue;
|
|
46618
46147
|
}
|
|
@@ -46620,15 +46149,15 @@ function inspectTrashBinary(env = process.env) {
|
|
|
46620
46149
|
reject("unsafe_directory");
|
|
46621
46150
|
continue;
|
|
46622
46151
|
}
|
|
46623
|
-
const packageRoot =
|
|
46624
|
-
const manifestPath =
|
|
46152
|
+
const packageRoot = resolve20(dirname21(executable2), "../..");
|
|
46153
|
+
const manifestPath = join22(packageRoot, "package.json");
|
|
46625
46154
|
const manifestStat = statSync(manifestPath);
|
|
46626
46155
|
if (!manifestStat.isFile() || !trustedOwner(manifestStat.uid) || manifestStat.size > 16384 || (manifestStat.mode & 18) !== 0 || lstatSync23(manifestPath).isSymbolicLink()) {
|
|
46627
46156
|
reject("unsafe_manifest");
|
|
46628
46157
|
continue;
|
|
46629
46158
|
}
|
|
46630
46159
|
const manifest = JSON.parse(readFileSync17(manifestPath, "utf8"));
|
|
46631
|
-
if (manifest.name !== "@hasna/trash" || typeof manifest.version !== "string" || typeof manifest.bin?.trash !== "string" || realpathSync11(
|
|
46160
|
+
if (manifest.name !== "@hasna/trash" || typeof manifest.version !== "string" || typeof manifest.bin?.trash !== "string" || realpathSync11(resolve20(packageRoot, manifest.bin.trash)) !== executable2) {
|
|
46632
46161
|
reject("unrecognized_package");
|
|
46633
46162
|
continue;
|
|
46634
46163
|
}
|
|
@@ -46673,7 +46202,7 @@ function failure(code2, reason) {
|
|
|
46673
46202
|
return { ok: false, target: "sumi", code: code2, ...reason ? { reason: reason.slice(0, 300) } : {} };
|
|
46674
46203
|
}
|
|
46675
46204
|
function nativeSafetyBindingDurable(worker, home) {
|
|
46676
|
-
return !(worker.startsWith(
|
|
46205
|
+
return !(worker.startsWith(join24(home, ".bun") + sep3) || worker.includes(`${sep3}node_modules${sep3}.bun${sep3}`));
|
|
46677
46206
|
}
|
|
46678
46207
|
async function provisionSumiSafetyBinding(options = {}) {
|
|
46679
46208
|
const home = options.home ?? homedir14();
|
|
@@ -46748,7 +46277,7 @@ init_transport2();
|
|
|
46748
46277
|
init_db();
|
|
46749
46278
|
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
46750
46279
|
var __dirname4 = dirname28(fileURLToPath6(import.meta.url));
|
|
46751
|
-
var pkgPath = existsSync18(
|
|
46280
|
+
var pkgPath = existsSync18(join35(__dirname4, "..", "package.json")) ? join35(__dirname4, "..", "package.json") : join35(__dirname4, "..", "..", "package.json");
|
|
46752
46281
|
var pkg2 = JSON.parse(readFileSync27(pkgPath, "utf-8"));
|
|
46753
46282
|
var program3 = new Command;
|
|
46754
46283
|
function resolveScope(options) {
|
|
@@ -46981,7 +46510,7 @@ program3.command("init").description("Register a new agent profile with a unique
|
|
|
46981
46510
|
if (profile.name) {
|
|
46982
46511
|
console.log(` ${chalk2.dim("Name:")} ${profile.name}`);
|
|
46983
46512
|
}
|
|
46984
|
-
console.log(` ${chalk2.dim("Profile:")} ${
|
|
46513
|
+
console.log(` ${chalk2.dim("Profile:")} ${join35(getProfilesDir(), `${profile.agent_id}.json`)}`);
|
|
46985
46514
|
console.log();
|
|
46986
46515
|
console.log(chalk2.dim(" Install hooks with this profile:"));
|
|
46987
46516
|
console.log(` hooks install gitguard --profile ${profile.agent_id}`);
|
|
@@ -47636,7 +47165,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
|
|
|
47636
47165
|
continue;
|
|
47637
47166
|
}
|
|
47638
47167
|
const hookDir = getHookPath(name);
|
|
47639
|
-
const hookScript =
|
|
47168
|
+
const hookScript = join35(hookDir, "src", "hook.ts");
|
|
47640
47169
|
if (!existsSync18(hookScript)) {
|
|
47641
47170
|
issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
|
|
47642
47171
|
hookHealthy = false;
|
|
@@ -47847,7 +47376,7 @@ program3.command("docs").argument("[hook]", "Hook name (shows general docs if om
|
|
|
47847
47376
|
return;
|
|
47848
47377
|
}
|
|
47849
47378
|
const hookPath = getHookPath(hook);
|
|
47850
|
-
const readmePath =
|
|
47379
|
+
const readmePath = join35(hookPath, "README.md");
|
|
47851
47380
|
let readme = "";
|
|
47852
47381
|
if (existsSync18(readmePath)) {
|
|
47853
47382
|
readme = readFileSync27(readmePath, "utf-8");
|
|
@@ -48645,7 +48174,7 @@ safety.command("verify").requiredOption("--target <target>", "sumi, codex or cla
|
|
|
48645
48174
|
throw new ClaudeSafetyError("settings_invalid");
|
|
48646
48175
|
console.log(JSON.stringify(await verifyClaudeSafetyConfiguration({
|
|
48647
48176
|
cwd: options.cwd,
|
|
48648
|
-
...process.env.CLAUDE_CONFIG_DIR ? { userSettingsPath:
|
|
48177
|
+
...process.env.CLAUDE_CONFIG_DIR ? { userSettingsPath: resolve21(process.env.CLAUDE_CONFIG_DIR, "settings.json") } : {}
|
|
48649
48178
|
})));
|
|
48650
48179
|
} catch (error61) {
|
|
48651
48180
|
console.log(JSON.stringify({ ok: false, target: "claude", code: error61 instanceof ClaudeSafetyError ? error61.code : "settings_invalid", nativeAdoptionVerified: false }));
|