@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
|
@@ -899,8 +899,9 @@ function evaluate(input, deps) {
|
|
|
899
899
|
if (false) {}
|
|
900
900
|
|
|
901
901
|
// hooks/hook-workspace-repos-guard/src/hook.ts
|
|
902
|
+
import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
902
903
|
import { homedir } from "os";
|
|
903
|
-
import { isAbsolute as isAbsolute2, join as join2, normalize as normalize2, relative, resolve as resolve2, sep as sep2 } from "path";
|
|
904
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, normalize as normalize2, relative, resolve as resolve2, sep as sep2 } from "path";
|
|
904
905
|
var FILE_WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
905
906
|
var PATCH_TOOLS = new Set(["apply_patch", "ApplyPatch", "functions.apply_patch"]);
|
|
906
907
|
var DEFAULT_ORGS = ["hasna", "hasnaxyz", "hasna-products"];
|
|
@@ -914,11 +915,47 @@ function legacyRoot(home) {
|
|
|
914
915
|
function protectedRoots(home) {
|
|
915
916
|
return [reposRoot(home), legacyRoot(home)];
|
|
916
917
|
}
|
|
917
|
-
function
|
|
918
|
+
function allowedOrgsFile(home) {
|
|
919
|
+
return join2(home, ".hasna", "hooks", "config", "workspace-repos-guard-orgs");
|
|
920
|
+
}
|
|
921
|
+
var ORG_NAME = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
|
|
922
|
+
function ownedAndClosed(stat) {
|
|
923
|
+
const uid = process.getuid?.();
|
|
924
|
+
return uid !== undefined && (stat.uid === 0 || stat.uid === uid) && (stat.mode & 18) === 0;
|
|
925
|
+
}
|
|
926
|
+
function readAllowedOrgsFile(home) {
|
|
927
|
+
const file = allowedOrgsFile(home);
|
|
928
|
+
let text;
|
|
929
|
+
try {
|
|
930
|
+
const fd = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
931
|
+
try {
|
|
932
|
+
const stat = fstatSync(fd);
|
|
933
|
+
if (!stat.isFile() || !ownedAndClosed(stat) || stat.size > 4096)
|
|
934
|
+
return null;
|
|
935
|
+
text = readFileSync2(fd, "utf8");
|
|
936
|
+
} finally {
|
|
937
|
+
closeSync(fd);
|
|
938
|
+
}
|
|
939
|
+
const top = normalize2(home);
|
|
940
|
+
for (let dir = dirname2(file);dir !== top; dir = dirname2(dir)) {
|
|
941
|
+
const stat = lstatSync(dir);
|
|
942
|
+
if (!stat.isDirectory() || !ownedAndClosed(stat) || dir === dirname2(dir))
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
if (!ownedAndClosed(statSync2(top)))
|
|
946
|
+
return null;
|
|
947
|
+
} catch {
|
|
948
|
+
return null;
|
|
949
|
+
}
|
|
950
|
+
const names = text.replace(/#[^\n]*/g, "").split(/[\s,]+/).filter(Boolean);
|
|
951
|
+
return names.length > 0 && names.every((name) => ORG_NAME.test(name)) ? new Set(names) : null;
|
|
952
|
+
}
|
|
953
|
+
function resolveAllowedOrgs(env = process.env, home = homedir()) {
|
|
918
954
|
const raw = env.WORKSPACE_REPOS_GUARD_ORGS;
|
|
919
|
-
if (typeof raw
|
|
920
|
-
return new Set(
|
|
921
|
-
|
|
955
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
956
|
+
return new Set(raw.split(",").map((s) => s.trim()).filter(Boolean));
|
|
957
|
+
}
|
|
958
|
+
return readAllowedOrgsFile(home) ?? new Set(DEFAULT_ORGS);
|
|
922
959
|
}
|
|
923
960
|
function classifyPath(target, root, orgs, op) {
|
|
924
961
|
if (op === "read")
|
|
@@ -952,6 +989,11 @@ function classifyPath(target, root, orgs, op) {
|
|
|
952
989
|
return { blocked: false };
|
|
953
990
|
}
|
|
954
991
|
var WRITE_FLAGS = /\b(?:-o|--output|-O|--output-document|-out)\b/;
|
|
992
|
+
var FD_DUPLICATION = /\d*[<>]&\s*(?:\d+|-)(?=$|[\s;&|)])/g;
|
|
993
|
+
var OUTPUT_REDIRECT = /(?:\d+|&)?(?:>>|>\||>&|<>|>)\s*([^\s;&|<>()\x60]*)/g;
|
|
994
|
+
function withoutFdDuplication(segment) {
|
|
995
|
+
return segment.replace(FD_DUPLICATION, " ");
|
|
996
|
+
}
|
|
955
997
|
function segmentOperation(segment) {
|
|
956
998
|
const trimmed = segment.trim();
|
|
957
999
|
if (!trimmed)
|
|
@@ -980,7 +1022,7 @@ function segmentOperation(segment) {
|
|
|
980
1022
|
} else if (/(?:^|\s)(?:python3?|node|bun)\b[^;&|]*\s+-[ce](?:\s|$)/.test(trimmed)) {
|
|
981
1023
|
return "write";
|
|
982
1024
|
}
|
|
983
|
-
if (/(?:^|[;&|])\s*echo\b/.test(trimmed) ||
|
|
1025
|
+
if (/(?:^|[;&|])\s*echo\b/.test(trimmed) || />/.test(withoutFdDuplication(trimmed)))
|
|
984
1026
|
return "write";
|
|
985
1027
|
return "read";
|
|
986
1028
|
}
|
|
@@ -1017,22 +1059,51 @@ function unwrapSegment(segment) {
|
|
|
1017
1059
|
function regexEscape(text) {
|
|
1018
1060
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1019
1061
|
}
|
|
1062
|
+
function cdDestinations(operand, bases, home) {
|
|
1063
|
+
if (operand === undefined)
|
|
1064
|
+
return [home];
|
|
1065
|
+
let word = expandHomeSpelling2(operand, home);
|
|
1066
|
+
const quoted = word.match(/^(['"])(.*)\1$/);
|
|
1067
|
+
if (quoted)
|
|
1068
|
+
word = quoted[2];
|
|
1069
|
+
if (!word || word === "-" || /[$\x60*?[\]{}~\\'"]/.test(word))
|
|
1070
|
+
return null;
|
|
1071
|
+
return [...new Set(bases.map((base) => resolve2(base, word)))];
|
|
1072
|
+
}
|
|
1073
|
+
var REL_OPERAND = /(?:^|\s)(\.\.?|[^\s"';&|<>()\x60/]+(?:\/[^\s"';&|<>()\x60]*)?)\s*$/;
|
|
1020
1074
|
function bashTargets(command, home, cwd) {
|
|
1021
1075
|
if (!command)
|
|
1022
1076
|
return [];
|
|
1023
1077
|
const roots = protectedRoots(home);
|
|
1024
|
-
const
|
|
1078
|
+
const underRoot = (path) => roots.some((root) => path === root || path.startsWith(`${root}${sep2}`));
|
|
1079
|
+
const parts = command.split(/(\s*&&\s*|\s*\|\|\s*|;\s*|\n+)/);
|
|
1025
1080
|
const targets = [];
|
|
1026
|
-
let
|
|
1027
|
-
|
|
1081
|
+
let current = [cwd];
|
|
1082
|
+
let reachable = new Set([cwd]);
|
|
1083
|
+
let certain = true;
|
|
1084
|
+
const subshells = [];
|
|
1085
|
+
for (let index = 0;index < parts.length; index += 2) {
|
|
1086
|
+
const separator = index === 0 ? "" : parts[index - 1].trim();
|
|
1087
|
+
if (separator === "||")
|
|
1088
|
+
certain = false;
|
|
1089
|
+
else if (separator !== "&&")
|
|
1090
|
+
certain = true;
|
|
1091
|
+
if (separator !== "&&" || !certain)
|
|
1092
|
+
current = [...reachable];
|
|
1093
|
+
const rawSegment = parts[index];
|
|
1094
|
+
const opens = (rawSegment.match(/^[\s({]*/)?.[0].match(/\(/g) ?? []).length;
|
|
1095
|
+
const closes = (rawSegment.match(/[\s)}]*$/)?.[0].match(/\)/g) ?? []).length;
|
|
1096
|
+
for (let i = 0;i < opens; i++)
|
|
1097
|
+
subshells.push({ current: [...current], reachable: new Set(reachable), certain });
|
|
1028
1098
|
const segment = unwrapSegment(rawSegment);
|
|
1029
1099
|
const op = segmentOperation(segment);
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1100
|
+
const plainCd = segment.match(/^cd(?:\s+(?:-[A-Za-z@]+|--))*(?:\s+([^\s;&|<>()\x60]+))?$/);
|
|
1101
|
+
const embeddedCd = plainCd ? null : segment.match(/(?:^|\s)cd(?:\s+(?:-[A-Za-z]+|--))*\s+([^\s;&|<>()\x60]+)/);
|
|
1102
|
+
if (embeddedCd) {
|
|
1103
|
+
for (const dir of cdDestinations(embeddedCd[1], current, home) ?? [])
|
|
1104
|
+
reachable.add(dir);
|
|
1105
|
+
certain = false;
|
|
1106
|
+
current = [...reachable];
|
|
1036
1107
|
}
|
|
1037
1108
|
const homeLiteral = regexEscape(home);
|
|
1038
1109
|
const suffix = roots.map((root) => regexEscape(root.slice(home.length + 1))).join("|");
|
|
@@ -1046,14 +1117,35 @@ function bashTargets(command, home, cwd) {
|
|
|
1046
1117
|
targets.push({ path: normalize2(expanded).replace(/\/+$/, ""), op });
|
|
1047
1118
|
}
|
|
1048
1119
|
if (!foundExplicit && (op === "delete" || op === "write")) {
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1120
|
+
const operands = [];
|
|
1121
|
+
const commandPart = withoutFdDuplication(segment).replace(OUTPUT_REDIRECT, (_match, operand) => {
|
|
1122
|
+
if (operand)
|
|
1123
|
+
operands.push(operand);
|
|
1124
|
+
return " ";
|
|
1125
|
+
});
|
|
1126
|
+
const commandOp = segmentOperation(commandPart);
|
|
1127
|
+
const relMatch = commandOp === "read" ? null : commandPart.match(REL_OPERAND);
|
|
1128
|
+
for (const base of current.filter(underRoot)) {
|
|
1129
|
+
for (const operand of operands) {
|
|
1130
|
+
targets.push({ path: normalize2(resolve2(base, expandHomeSpelling2(operand, home))), op: "write" });
|
|
1054
1131
|
}
|
|
1132
|
+
if (relMatch)
|
|
1133
|
+
targets.push({ path: normalize2(resolve2(base, relMatch[1])), op: commandOp });
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (plainCd) {
|
|
1137
|
+
const next = cdDestinations(plainCd[1], current, home);
|
|
1138
|
+
if (next) {
|
|
1139
|
+
for (const dir of next)
|
|
1140
|
+
reachable.add(dir);
|
|
1141
|
+
if (certain)
|
|
1142
|
+
current = next;
|
|
1143
|
+
} else {
|
|
1144
|
+
certain = false;
|
|
1055
1145
|
}
|
|
1056
1146
|
}
|
|
1147
|
+
for (let i = 0;i < closes && subshells.length > 0; i++)
|
|
1148
|
+
({ current, reachable, certain } = subshells.pop());
|
|
1057
1149
|
}
|
|
1058
1150
|
return targets;
|
|
1059
1151
|
}
|
|
@@ -1067,14 +1159,14 @@ function patchTargets(patch, cwd) {
|
|
|
1067
1159
|
}
|
|
1068
1160
|
return targets;
|
|
1069
1161
|
}
|
|
1070
|
-
function evaluate2(input) {
|
|
1162
|
+
function evaluate2(input, options = {}) {
|
|
1071
1163
|
const warnings = [];
|
|
1072
1164
|
if (input.hook_event_name !== "PreToolUse")
|
|
1073
1165
|
return { output: { continue: true }, warnings };
|
|
1074
1166
|
const tool = typeof input.tool_name === "string" ? input.tool_name : "";
|
|
1075
|
-
const home = homedir();
|
|
1167
|
+
const home = options.home ?? homedir();
|
|
1076
1168
|
const roots = protectedRoots(home);
|
|
1077
|
-
const orgs = resolveAllowedOrgs();
|
|
1169
|
+
const orgs = resolveAllowedOrgs(process.env, home);
|
|
1078
1170
|
if (tool === "Bash") {
|
|
1079
1171
|
const command = getCommand(input);
|
|
1080
1172
|
if (!command)
|
package/bin/serve.js
CHANGED
|
@@ -676,7 +676,7 @@ function getHook(name) {
|
|
|
676
676
|
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "fs";
|
|
677
677
|
import { basename, dirname, isAbsolute, join as join3, normalize, resolve as resolve2, sep } from "path";
|
|
678
678
|
|
|
679
|
-
//
|
|
679
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
680
680
|
var exports_external = {};
|
|
681
681
|
__export(exports_external, {
|
|
682
682
|
void: () => voidType,
|
|
@@ -788,7 +788,7 @@ __export(exports_external, {
|
|
|
788
788
|
BRAND: () => BRAND
|
|
789
789
|
});
|
|
790
790
|
|
|
791
|
-
//
|
|
791
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
792
792
|
var util;
|
|
793
793
|
(function(util2) {
|
|
794
794
|
util2.assertEqual = (_) => {};
|
|
@@ -919,7 +919,7 @@ var getParsedType = (data) => {
|
|
|
919
919
|
}
|
|
920
920
|
};
|
|
921
921
|
|
|
922
|
-
//
|
|
922
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
923
923
|
var ZodIssueCode = util.arrayToEnum([
|
|
924
924
|
"invalid_type",
|
|
925
925
|
"invalid_literal",
|
|
@@ -1038,7 +1038,7 @@ ZodError.create = (issues) => {
|
|
|
1038
1038
|
return error;
|
|
1039
1039
|
};
|
|
1040
1040
|
|
|
1041
|
-
//
|
|
1041
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
1042
1042
|
var errorMap = (issue, _ctx) => {
|
|
1043
1043
|
let message;
|
|
1044
1044
|
switch (issue.code) {
|
|
@@ -1141,7 +1141,7 @@ var errorMap = (issue, _ctx) => {
|
|
|
1141
1141
|
};
|
|
1142
1142
|
var en_default = errorMap;
|
|
1143
1143
|
|
|
1144
|
-
//
|
|
1144
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
1145
1145
|
var overrideErrorMap = en_default;
|
|
1146
1146
|
function setErrorMap(map) {
|
|
1147
1147
|
overrideErrorMap = map;
|
|
@@ -1149,7 +1149,7 @@ function setErrorMap(map) {
|
|
|
1149
1149
|
function getErrorMap() {
|
|
1150
1150
|
return overrideErrorMap;
|
|
1151
1151
|
}
|
|
1152
|
-
//
|
|
1152
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
1153
1153
|
var makeIssue = (params) => {
|
|
1154
1154
|
const { data, path, errorMaps, issueData } = params;
|
|
1155
1155
|
const fullPath = [...path, ...issueData.path || []];
|
|
@@ -1255,14 +1255,14 @@ var isAborted = (x) => x.status === "aborted";
|
|
|
1255
1255
|
var isDirty = (x) => x.status === "dirty";
|
|
1256
1256
|
var isValid = (x) => x.status === "valid";
|
|
1257
1257
|
var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
1258
|
-
//
|
|
1258
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1259
1259
|
var errorUtil;
|
|
1260
1260
|
(function(errorUtil2) {
|
|
1261
1261
|
errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
|
1262
1262
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
|
|
1263
1263
|
})(errorUtil || (errorUtil = {}));
|
|
1264
1264
|
|
|
1265
|
-
//
|
|
1265
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1266
1266
|
class ParseInputLazyPath {
|
|
1267
1267
|
constructor(parent, value, path, key) {
|
|
1268
1268
|
this._cachedPath = [];
|
|
@@ -5362,7 +5362,7 @@ import { readFileSync as readFileSync5 } from "fs";
|
|
|
5362
5362
|
import { dirname as dirname4, join as join8 } from "path";
|
|
5363
5363
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
5364
5364
|
|
|
5365
|
-
//
|
|
5365
|
+
// ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
|
|
5366
5366
|
import { spawnSync } from "child_process";
|
|
5367
5367
|
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync22 } from "fs";
|
|
5368
5368
|
import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
|
package/dist/index.js
CHANGED
|
@@ -581,7 +581,7 @@ var init_redact = __esm(() => {
|
|
|
581
581
|
];
|
|
582
582
|
});
|
|
583
583
|
|
|
584
|
-
//
|
|
584
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
585
585
|
var util, objectUtil, ZodParsedType, getParsedType = (data) => {
|
|
586
586
|
const t = typeof data;
|
|
587
587
|
switch (t) {
|
|
@@ -712,7 +712,7 @@ var init_util = __esm(() => {
|
|
|
712
712
|
]);
|
|
713
713
|
});
|
|
714
714
|
|
|
715
|
-
//
|
|
715
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
716
716
|
var ZodIssueCode, quotelessJson = (obj) => {
|
|
717
717
|
const json = JSON.stringify(obj, null, 2);
|
|
718
718
|
return json.replace(/"([^"]+)":/g, "$1:");
|
|
@@ -833,7 +833,7 @@ var init_ZodError = __esm(() => {
|
|
|
833
833
|
};
|
|
834
834
|
});
|
|
835
835
|
|
|
836
|
-
//
|
|
836
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
837
837
|
var errorMap = (issue, _ctx) => {
|
|
838
838
|
let message;
|
|
839
839
|
switch (issue.code) {
|
|
@@ -940,7 +940,7 @@ var init_en = __esm(() => {
|
|
|
940
940
|
en_default = errorMap;
|
|
941
941
|
});
|
|
942
942
|
|
|
943
|
-
//
|
|
943
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
944
944
|
function setErrorMap(map) {
|
|
945
945
|
overrideErrorMap = map;
|
|
946
946
|
}
|
|
@@ -953,7 +953,7 @@ var init_errors = __esm(() => {
|
|
|
953
953
|
overrideErrorMap = en_default;
|
|
954
954
|
});
|
|
955
955
|
|
|
956
|
-
//
|
|
956
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
957
957
|
function addIssueToContext(ctx, issueData) {
|
|
958
958
|
const overrideMap = getErrorMap();
|
|
959
959
|
const issue = makeIssue({
|
|
@@ -1058,10 +1058,10 @@ var init_parseUtil = __esm(() => {
|
|
|
1058
1058
|
});
|
|
1059
1059
|
});
|
|
1060
1060
|
|
|
1061
|
-
//
|
|
1061
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/typeAliases.js
|
|
1062
1062
|
var init_typeAliases = () => {};
|
|
1063
1063
|
|
|
1064
|
-
//
|
|
1064
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1065
1065
|
var errorUtil;
|
|
1066
1066
|
var init_errorUtil = __esm(() => {
|
|
1067
1067
|
(function(errorUtil2) {
|
|
@@ -1070,7 +1070,7 @@ var init_errorUtil = __esm(() => {
|
|
|
1070
1070
|
})(errorUtil || (errorUtil = {}));
|
|
1071
1071
|
});
|
|
1072
1072
|
|
|
1073
|
-
//
|
|
1073
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1074
1074
|
class ParseInputLazyPath {
|
|
1075
1075
|
constructor(parent, value, path, key) {
|
|
1076
1076
|
this._cachedPath = [];
|
|
@@ -4421,7 +4421,7 @@ var init_types = __esm(() => {
|
|
|
4421
4421
|
NEVER = INVALID;
|
|
4422
4422
|
});
|
|
4423
4423
|
|
|
4424
|
-
//
|
|
4424
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
4425
4425
|
var exports_external = {};
|
|
4426
4426
|
__export(exports_external, {
|
|
4427
4427
|
void: () => voidType,
|
|
@@ -4541,7 +4541,7 @@ var init_external = __esm(() => {
|
|
|
4541
4541
|
init_ZodError();
|
|
4542
4542
|
});
|
|
4543
4543
|
|
|
4544
|
-
//
|
|
4544
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/index.js
|
|
4545
4545
|
var init_zod = __esm(() => {
|
|
4546
4546
|
init_external();
|
|
4547
4547
|
init_external();
|
|
@@ -5101,7 +5101,7 @@ var init_profiles = __esm(() => {
|
|
|
5101
5101
|
init_app_home();
|
|
5102
5102
|
});
|
|
5103
5103
|
|
|
5104
|
-
//
|
|
5104
|
+
// ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
|
|
5105
5105
|
import { isIP } from "net";
|
|
5106
5106
|
import { spawnSync } from "child_process";
|
|
5107
5107
|
import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
|
|
@@ -7920,7 +7920,7 @@ function writeCodexSettings(path, settings) {
|
|
|
7920
7920
|
// src/lib/claude-skills-coordination.ts
|
|
7921
7921
|
import { createHash as createHash5 } from "crypto";
|
|
7922
7922
|
|
|
7923
|
-
//
|
|
7923
|
+
// ../../node_modules/.bun/@hasna+skills@0.9.14+a00d3064559565bb/node_modules/@hasna/skills/dist/index.js
|
|
7924
7924
|
import { existsSync as existsSync9 } from "fs";
|
|
7925
7925
|
import { homedir as homedir4 } from "os";
|
|
7926
7926
|
import { join as join8, resolve as resolve3 } from "path";
|
package/dist/sdk/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
//
|
|
2
|
+
// ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
|
|
3
3
|
import { isIP } from "net";
|
|
4
4
|
import { spawnSync } from "child_process";
|
|
5
5
|
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync2 } from "fs";
|
|
@@ -32,17 +32,39 @@ Home spellings (`~`, `$HOME`, `${HOME}`, quoted or not, including split-quote
|
|
|
32
32
|
forms like `"$HOME"/.hasna/repos/clones`, which Bash treats identically to the
|
|
33
33
|
unquoted spelling) are expanded before classification; `apply_patch` tools
|
|
34
34
|
are inspected through their `Add File` / `Update File` / `Delete File`
|
|
35
|
-
markers;
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
markers; parenthesized command groups (`(cd ... && rm -rf ...)`) are
|
|
36
|
+
unwrapped.
|
|
37
|
+
|
|
38
|
+
Bash relative operands (a trailing bare name, `.`, `..`, and the operand of
|
|
39
|
+
an output redirection such as `> file` or `>> file`) are resolved against the
|
|
40
|
+
directory the command segment runs in, and only count when that directory is
|
|
41
|
+
under a protected root. That directory starts as the command's cwd. A plain
|
|
42
|
+
`cd DIR` moves it for the segments joined to it by `&&`, so
|
|
43
|
+
`cd /tmp && printf x > out` is not attributed to the session cwd. After `;`,
|
|
44
|
+
a newline or `||` the `cd` may have failed, so the earlier directories stay
|
|
45
|
+
in scope. A `cd` inside `( ... )`, a pipeline or the background does not move
|
|
46
|
+
it, and neither does a `cd` whose target cannot be resolved statically.
|
|
47
|
+
Descriptor duplication (`2>&1`, `>&2`, `1>&-`) is not a write.
|
|
38
48
|
|
|
39
49
|
## Configuration
|
|
40
50
|
|
|
41
|
-
Allowed orgs default to `hasna,hasnaxyz,hasna-products
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
Allowed orgs default to `hasna,hasnaxyz,hasna-products`. Private workspace
|
|
52
|
+
orgs must be added per-install; they are never part of the public default.
|
|
53
|
+
There are two per-install routes, checked in this order:
|
|
54
|
+
|
|
55
|
+
1. The `WORKSPACE_REPOS_GUARD_ORGS` env var (comma-separated), for installs
|
|
56
|
+
that run the hook with the harness environment (`hooks run`).
|
|
57
|
+
2. The file `$HOME/.hasna/hooks/config/workspace-repos-guard-orgs`. The
|
|
58
|
+
native safety registration (`hooks safety install`) runs the guard with
|
|
59
|
+
only `HOME` and `PATH`, so the env var never reaches it and this file is
|
|
60
|
+
the route that does. List the org names separated by commas or whitespace;
|
|
61
|
+
`#` starts a comment. The list replaces the default, so include the
|
|
62
|
+
default orgs you still need. The file and every directory from it up to
|
|
63
|
+
`HOME` must be owned by the user or root and not writable by group or
|
|
64
|
+
others. A missing, untrusted or malformed file is ignored and the default
|
|
65
|
+
applies.
|
|
66
|
+
|
|
67
|
+
The home directory is resolved with `os.homedir()` — never hardcoded.
|
|
46
68
|
|
|
47
69
|
## Failure mode
|
|
48
70
|
|