@hasna/hooks 0.11.3 → 0.11.5
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 -1
- package/bin/hooks-mcp.js +67 -65
- package/bin/index.js +404 -398
- package/bin/native-readiness-entry.js +3 -1
- package/bin/native-safety-entry.js +96 -8
- package/bin/serve.js +9 -9
- package/dist/index.js +74 -74
- package/dist/native-readiness.d.ts +3 -0
- package/dist/native-readiness.js +8 -2
- package/dist/sdk/index.js +1 -1
- package/hooks/hook-trash-guard/src/hook.ts +40 -10
- package/hooks/hook-workspace-repos-guard/src/hook.ts +46 -0
- package/package.json +1 -1
|
@@ -143,6 +143,8 @@ function runReadinessProcess(command, args, options) {
|
|
|
143
143
|
var import_node_fs = require("node:fs");
|
|
144
144
|
var import_node_os = require("node:os");
|
|
145
145
|
var import_node_path = require("node:path");
|
|
146
|
+
var TRASH_READINESS_MAX_TIMEOUT_MS = 60000;
|
|
147
|
+
var TRASH_READINESS_NATIVE_TIMEOUT_SECONDS = TRASH_READINESS_MAX_TIMEOUT_MS / 1000 + 5;
|
|
146
148
|
|
|
147
149
|
class ReadinessError extends Error {
|
|
148
150
|
code;
|
|
@@ -171,7 +173,7 @@ function inside(home, path) {
|
|
|
171
173
|
function parseTrashReadinessBinding(input, provider, home) {
|
|
172
174
|
const b = input;
|
|
173
175
|
need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
|
|
174
|
-
need(keys(b, ["schema", "provider", "home", "runtime", "trash", "plan", "timeoutMs"]) && b.schema === "hasna.hooks.trash-readiness/v1" && b.provider === provider && b.home === home && pin(b.runtime) && pin(b.plan) && keys(b.trash, ["root", "version", "cliSha256"]) && absolute(b.trash.root) && typeof b.trash.version === "string" && b.trash.version.length <= 128 && /^\d+\.\d+\.\d+$/.test(b.trash.version) && digest(b.trash.cliSha256) && Number.isInteger(b.timeoutMs) && b.timeoutMs >= 1000 && b.timeoutMs <=
|
|
176
|
+
need(keys(b, ["schema", "provider", "home", "runtime", "trash", "plan", "timeoutMs"]) && b.schema === "hasna.hooks.trash-readiness/v1" && b.provider === provider && b.home === home && pin(b.runtime) && pin(b.plan) && keys(b.trash, ["root", "version", "cliSha256"]) && absolute(b.trash.root) && typeof b.trash.version === "string" && b.trash.version.length <= 128 && /^\d+\.\d+\.\d+$/.test(b.trash.version) && digest(b.trash.cliSha256) && Number.isInteger(b.timeoutMs) && b.timeoutMs >= 1000 && b.timeoutMs <= TRASH_READINESS_MAX_TIMEOUT_MS && inside(home, b.plan.path) && inside(home, b.trash.root), "binding_invalid");
|
|
175
177
|
return structuredClone(b);
|
|
176
178
|
}
|
|
177
179
|
function trashReadinessBindingPath(provider, home = import_node_os.homedir()) {
|
|
@@ -292,7 +292,7 @@ var REFUSED_VERBS = {
|
|
|
292
292
|
unlink: "`unlink` is a delete that trash-guard does not rewrite. Re-run it as `rm -- <path>` and it is redirected into trash.",
|
|
293
293
|
shred: "`shred` destroys content irrecoverably and is never allowed. Re-run it as `rm -- <path>` and it is redirected into trash."
|
|
294
294
|
};
|
|
295
|
-
var OPAQUE_COMMANDS = new Set(["sh", "bash", "zsh", "dash", "ksh", "ash", "eval", "source", ".", "su", "runuser"]);
|
|
295
|
+
var OPAQUE_COMMANDS = new Set(["sh", "bash", "zsh", "dash", "ksh", "ash", "eval", "source", ".", "su", "runuser", "env"]);
|
|
296
296
|
var WRAPPERS = {
|
|
297
297
|
sudo: ["-u", "--user", "-g", "--group", "-p", "--prompt", "-C", "--chdir", "-h", "--host", "-r", "--role", "-t", "--type", "-U", "--other-user"],
|
|
298
298
|
doas: ["-u", "-C"],
|
|
@@ -306,7 +306,7 @@ var WRAPPERS = {
|
|
|
306
306
|
setsid: [],
|
|
307
307
|
command: [],
|
|
308
308
|
builtin: [],
|
|
309
|
-
exec: []
|
|
309
|
+
exec: ["-a"]
|
|
310
310
|
};
|
|
311
311
|
var WRAPPER_POSITIONALS = {
|
|
312
312
|
timeout: 1
|
|
@@ -318,6 +318,9 @@ var DELETE_VERB_WORD_RE = /(^|[^A-Za-z0-9_.-])(rm|rmdir|unlink|shred)(?![A-Za-z0
|
|
|
318
318
|
function mentionsDeleteVerb(text) {
|
|
319
319
|
return DELETE_VERB_WORD_RE.test(decodeWord(text));
|
|
320
320
|
}
|
|
321
|
+
function envSplitCommandText(words) {
|
|
322
|
+
return words.map((word) => word.replace(/^-[iv0]*S|^--split-string=/, " ")).join(" ");
|
|
323
|
+
}
|
|
321
324
|
var ASSIGNMENT_RE = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
322
325
|
function baseVerb(word) {
|
|
323
326
|
const slash = word.lastIndexOf("/");
|
|
@@ -340,8 +343,8 @@ function lexCommand(command) {
|
|
|
340
343
|
if (pendingRedirect)
|
|
341
344
|
redirects.add(index);
|
|
342
345
|
wordStart = -1;
|
|
346
|
+
pendingRedirect = false;
|
|
343
347
|
}
|
|
344
|
-
pendingRedirect = false;
|
|
345
348
|
};
|
|
346
349
|
const closeSegment = (end) => {
|
|
347
350
|
closeWord(end);
|
|
@@ -349,6 +352,7 @@ function lexCommand(command) {
|
|
|
349
352
|
segments.push({ words, redirects });
|
|
350
353
|
words = [];
|
|
351
354
|
redirects = new Set;
|
|
355
|
+
pendingRedirect = false;
|
|
352
356
|
};
|
|
353
357
|
const scanSingle = (from) => {
|
|
354
358
|
const end = command.indexOf("'", from + 1);
|
|
@@ -495,9 +499,13 @@ function lexCommand(command) {
|
|
|
495
499
|
continue;
|
|
496
500
|
}
|
|
497
501
|
if (ch === ">" || ch === "<") {
|
|
502
|
+
if (wordStart >= 0 && /^\d+$/.test(command.slice(wordStart, i)))
|
|
503
|
+
wordStart = -1;
|
|
498
504
|
closeWord(i);
|
|
499
505
|
pendingRedirect = true;
|
|
500
|
-
i
|
|
506
|
+
i++;
|
|
507
|
+
if (command[i] === ch || command[i] === "&" || ch === ">" && command[i] === "|" || ch === "<" && command[i] === ">")
|
|
508
|
+
i++;
|
|
501
509
|
continue;
|
|
502
510
|
}
|
|
503
511
|
if (ch === "'") {
|
|
@@ -626,6 +634,10 @@ function commandWordIndex(segment) {
|
|
|
626
634
|
let index = 0;
|
|
627
635
|
let guard = 0;
|
|
628
636
|
while (index < segment.words.length && guard++ < 32) {
|
|
637
|
+
if (segment.redirects.has(index)) {
|
|
638
|
+
index++;
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
629
641
|
const raw = segment.words[index].text;
|
|
630
642
|
const decoded = decodeWord(raw);
|
|
631
643
|
if (ASSIGNMENT_RE.test(decoded) && !decoded.startsWith("-")) {
|
|
@@ -636,10 +648,25 @@ function commandWordIndex(segment) {
|
|
|
636
648
|
index++;
|
|
637
649
|
continue;
|
|
638
650
|
}
|
|
639
|
-
const
|
|
651
|
+
const wrapper = baseVerb(decoded);
|
|
652
|
+
if (wrapper === "command") {
|
|
653
|
+
for (const word of segment.words.filter((_, at) => at > index && !segment.redirects.has(at))) {
|
|
654
|
+
const option = decodeWord(word.text);
|
|
655
|
+
if (option === "--" || !option.startsWith("-"))
|
|
656
|
+
break;
|
|
657
|
+
if (/^-[pvV]*[vV][pvV]*$/.test(option))
|
|
658
|
+
return -1;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
const wrapperValues = WRAPPERS[wrapper];
|
|
640
662
|
if (wrapperValues) {
|
|
663
|
+
const wrapperIndex = index;
|
|
641
664
|
index++;
|
|
642
665
|
while (index < segment.words.length) {
|
|
666
|
+
if (segment.redirects.has(index)) {
|
|
667
|
+
index++;
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
643
670
|
const option = decodeWord(segment.words[index].text);
|
|
644
671
|
if (!option.startsWith("-") || option === "-")
|
|
645
672
|
break;
|
|
@@ -647,11 +674,16 @@ function commandWordIndex(segment) {
|
|
|
647
674
|
index++;
|
|
648
675
|
break;
|
|
649
676
|
}
|
|
677
|
+
if (wrapper === "env" && (/^-[iv0]*S/.test(option) || /^--split-string(?:=|$)/.test(option)))
|
|
678
|
+
return wrapperIndex;
|
|
650
679
|
index++;
|
|
651
|
-
if (wrapperValues.includes(option))
|
|
680
|
+
if (wrapperValues.includes(option) || wrapper === "exec" && /^-[cl]*a$/.test(option)) {
|
|
681
|
+
while (segment.redirects.has(index))
|
|
682
|
+
index++;
|
|
652
683
|
index++;
|
|
684
|
+
}
|
|
653
685
|
}
|
|
654
|
-
let positionals = WRAPPER_POSITIONALS[
|
|
686
|
+
let positionals = WRAPPER_POSITIONALS[wrapper] ?? 0;
|
|
655
687
|
while (positionals > 0 && index < segment.words.length) {
|
|
656
688
|
const positional = decodeWord(segment.words[index].text);
|
|
657
689
|
if (positional.startsWith("-") && positional !== "-")
|
|
@@ -862,7 +894,8 @@ function scanCommand(command, options) {
|
|
|
862
894
|
});
|
|
863
895
|
continue;
|
|
864
896
|
}
|
|
865
|
-
|
|
897
|
+
const opaqueText = verb === "env" ? envSplitCommandText(segment.words.map((word) => decodeWord(word.text))) : segmentText(segment);
|
|
898
|
+
if (OPAQUE_COMMANDS.has(verb) && mentionsDeleteVerb(opaqueText)) {
|
|
866
899
|
result.refusals.push({
|
|
867
900
|
reason: `\`${verb}\` runs a command string this hook cannot rewrite in place. Run the delete directly as \`rm -- <path>\` (intercepted and redirected into trash), or as a script that uses \`trash guard\` itself.`
|
|
868
901
|
});
|
|
@@ -1305,6 +1338,61 @@ function shellWords(command) {
|
|
|
1305
1338
|
return words;
|
|
1306
1339
|
}
|
|
1307
1340
|
function segmentOperation(segment) {
|
|
1341
|
+
const trimmed = segment.trim();
|
|
1342
|
+
if (!trimmed)
|
|
1343
|
+
return "read";
|
|
1344
|
+
const parsed = lexCommand(trimmed);
|
|
1345
|
+
if (!parsed.trustworthy || parsed.substitutions.length || /\$\{[^}]*[|;()]|[<>]\(/.test(trimmed))
|
|
1346
|
+
return opaqueOperation(trimmed);
|
|
1347
|
+
const operations = parsed.segments.map((part) => {
|
|
1348
|
+
const index = commandWordIndex(part);
|
|
1349
|
+
if (index < 0)
|
|
1350
|
+
return "read";
|
|
1351
|
+
const words = part.words.filter((_, at) => at >= index && !part.redirects.has(at)).map((word) => decodeWord(word.text));
|
|
1352
|
+
const tool = words[0].split("/").pop();
|
|
1353
|
+
if (["rm", "rmdir", "unlink", "shred", "rmtree", "del"].includes(tool ?? ""))
|
|
1354
|
+
return "delete";
|
|
1355
|
+
if (tool === "trash") {
|
|
1356
|
+
let at = 1;
|
|
1357
|
+
while (at < words.length && words[at].startsWith("-")) {
|
|
1358
|
+
const flag = words[at++];
|
|
1359
|
+
if (["--help", "-h", "--version", "-V", "--identity"].includes(flag))
|
|
1360
|
+
return "read";
|
|
1361
|
+
if (["--agent", "--spool", "--files", "--info", "--config"].includes(flag))
|
|
1362
|
+
at++;
|
|
1363
|
+
else if (!["--json", "--local"].includes(flag))
|
|
1364
|
+
return "delete";
|
|
1365
|
+
}
|
|
1366
|
+
if (at === words.length || ["status", "doctor", "list", "info", "get", "pending", "station", "setup", "backup", "storage", "retrieval", "backup-storage", "backup-inspect", "backup-refresh", "help"].includes(words[at]))
|
|
1367
|
+
return "read";
|
|
1368
|
+
if (["restore", "restore-capsule"].includes(words[at]))
|
|
1369
|
+
return "write";
|
|
1370
|
+
return "delete";
|
|
1371
|
+
}
|
|
1372
|
+
if (tool === "git") {
|
|
1373
|
+
const sub = gitSubcommand(part, index);
|
|
1374
|
+
if (sub === "clean" || sub === "rm")
|
|
1375
|
+
return "delete";
|
|
1376
|
+
return sub === "clone" || sub === "init" ? "write" : "read";
|
|
1377
|
+
}
|
|
1378
|
+
if (tool === "env" && mentionsDeleteVerb(envSplitCommandText(words)))
|
|
1379
|
+
return "delete";
|
|
1380
|
+
if (["sh", "bash", "zsh", "dash", "ksh", "ash", "eval", "source", ".", "su", "runuser", "env", "xargs", "find", "busybox", "toybox"].includes(tool ?? "")) {
|
|
1381
|
+
return opaqueOperation(words.join(" "));
|
|
1382
|
+
}
|
|
1383
|
+
if (["mkdir", "mkfile", "touch", "mv", "cp", "ln", "tee", "install", "dd", "rsync", "scp", "truncate"].includes(tool ?? ""))
|
|
1384
|
+
return "write";
|
|
1385
|
+
if (tool === "curl" || tool === "wget")
|
|
1386
|
+
return WRITE_FLAGS.test(words.join(" ")) ? "write" : "read";
|
|
1387
|
+
if (tool === "sed" && words.slice(1).some((word) => /^-i|^--in-place(?:=|$)/.test(word)))
|
|
1388
|
+
return "write";
|
|
1389
|
+
if (["python", "python3", "node", "bun"].includes(tool ?? "") && words.some((word) => word === "-c" || word === "-e"))
|
|
1390
|
+
return "write";
|
|
1391
|
+
return "read";
|
|
1392
|
+
});
|
|
1393
|
+
return operations.includes("delete") ? "delete" : operations.includes("write") ? "write" : "read";
|
|
1394
|
+
}
|
|
1395
|
+
function opaqueOperation(segment) {
|
|
1308
1396
|
const trimmed = segment.trim();
|
|
1309
1397
|
if (!trimmed)
|
|
1310
1398
|
return "read";
|
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";
|
|
@@ -7547,6 +7547,66 @@ import { join as join10, dirname as dirname7, basename as basename3, resolve as
|
|
|
7547
7547
|
import { homedir as homedir6 } from "os";
|
|
7548
7548
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7549
7549
|
|
|
7550
|
+
// src/lib/readiness-process.ts
|
|
7551
|
+
var supervisor = String.raw`
|
|
7552
|
+
const {spawn}=require("node:child_process");
|
|
7553
|
+
const spec=JSON.parse(process.argv.at(-1));
|
|
7554
|
+
// This runtime was created detached and is its group's live leader. Its
|
|
7555
|
+
// independent timer and parent pipe remain effective if the observer exits
|
|
7556
|
+
// or its event loop stops responding. Only this freshly created tree is hit.
|
|
7557
|
+
const cleanup=()=>{try{process.kill(-process.pid,"SIGKILL")}catch{process.exit(1)}};
|
|
7558
|
+
setTimeout(cleanup,spec.timeout);
|
|
7559
|
+
process.stdin.once("end",cleanup);
|
|
7560
|
+
process.stdin.once("error",cleanup);
|
|
7561
|
+
process.stdin.on("data",cleanup);
|
|
7562
|
+
process.stdin.resume();
|
|
7563
|
+
for(const signal of ["SIGTERM","SIGINT","SIGHUP"])process.once(signal,cleanup);
|
|
7564
|
+
let done=false, out=Buffer.alloc(0), err=Buffer.alloc(0);
|
|
7565
|
+
function report(status,error){
|
|
7566
|
+
if(done)return; done=true;
|
|
7567
|
+
process.stdout.write(JSON.stringify({status,error,stdout:out.toString("utf8"),stderr:err.toString("utf8")})+"\n");
|
|
7568
|
+
}
|
|
7569
|
+
const child=spawn(spec.command,spec.args,{stdio:["ignore","pipe","pipe"],env:process.env});
|
|
7570
|
+
for(const [stream,name] of [[child.stdout,"stdout"],[child.stderr,"stderr"]]){
|
|
7571
|
+
stream.on("data",bytes=>{
|
|
7572
|
+
if(done)return;
|
|
7573
|
+
const before=name==="stdout"?out:err;
|
|
7574
|
+
if(before.length+bytes.length>spec.maxBuffer){report(null,{code:"ENOBUFS"});return}
|
|
7575
|
+
if(name==="stdout")out=Buffer.concat([out,bytes]);else err=Buffer.concat([err,bytes]);
|
|
7576
|
+
});
|
|
7577
|
+
stream.on("error",()=>report(null,{code:"ECHILD"}));
|
|
7578
|
+
}
|
|
7579
|
+
child.on("error",()=>report(null,{code:"ECHILD"}));
|
|
7580
|
+
// A successful observation includes complete streams. A nested client that
|
|
7581
|
+
// keeps them open after its parent exits is a failure requiring group cleanup.
|
|
7582
|
+
child.on("exit",()=>setTimeout(()=>report(null,{code:"ECHILD"}),100));
|
|
7583
|
+
child.on("close",(status,signal)=>report(status,signal?{code:"ECHILD"}:undefined));
|
|
7584
|
+
`;
|
|
7585
|
+
|
|
7586
|
+
// src/native-readiness.ts
|
|
7587
|
+
var TRASH_READINESS_MAX_TIMEOUT_MS = 60000;
|
|
7588
|
+
var TRASH_READINESS_NATIVE_TIMEOUT_SECONDS = TRASH_READINESS_MAX_TIMEOUT_MS / 1000 + 5;
|
|
7589
|
+
function isReadinessProvider(value) {
|
|
7590
|
+
return value === "claude" || value === "codex" || value === "sumi";
|
|
7591
|
+
}
|
|
7592
|
+
var safeFailureCodes = new Set([
|
|
7593
|
+
"unsupported_platform",
|
|
7594
|
+
"station_detection_failed",
|
|
7595
|
+
"station_mismatch",
|
|
7596
|
+
"hosted_unavailable",
|
|
7597
|
+
"authentication_refused",
|
|
7598
|
+
"station_setup_required",
|
|
7599
|
+
"invalid_status",
|
|
7600
|
+
"deadline_exceeded",
|
|
7601
|
+
"retention_mismatch",
|
|
7602
|
+
"managed_instructions_refused",
|
|
7603
|
+
"removal_instruction_missing",
|
|
7604
|
+
"instructions_changed",
|
|
7605
|
+
"native_config_changed",
|
|
7606
|
+
"guard_refused",
|
|
7607
|
+
"owner_refused"
|
|
7608
|
+
]);
|
|
7609
|
+
|
|
7550
7610
|
// src/lib/resolve.ts
|
|
7551
7611
|
import { dirname as dirname2, join as join6 } from "path";
|
|
7552
7612
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -7774,66 +7834,6 @@ import { createHash as createHash2 } from "crypto";
|
|
|
7774
7834
|
import { constants as constants2, closeSync as closeSync2, existsSync as existsSync7, fstatSync as fstatSync2, lstatSync as lstatSync2, openSync as openSync2, readFileSync as readFileSync4, realpathSync as realpathSync3 } from "fs";
|
|
7775
7835
|
import { dirname as dirname4, isAbsolute as isAbsolute3, join as join8 } from "path";
|
|
7776
7836
|
import { homedir as homedir4 } from "os";
|
|
7777
|
-
|
|
7778
|
-
// src/lib/readiness-process.ts
|
|
7779
|
-
var supervisor = String.raw`
|
|
7780
|
-
const {spawn}=require("node:child_process");
|
|
7781
|
-
const spec=JSON.parse(process.argv.at(-1));
|
|
7782
|
-
// This runtime was created detached and is its group's live leader. Its
|
|
7783
|
-
// independent timer and parent pipe remain effective if the observer exits
|
|
7784
|
-
// or its event loop stops responding. Only this freshly created tree is hit.
|
|
7785
|
-
const cleanup=()=>{try{process.kill(-process.pid,"SIGKILL")}catch{process.exit(1)}};
|
|
7786
|
-
setTimeout(cleanup,spec.timeout);
|
|
7787
|
-
process.stdin.once("end",cleanup);
|
|
7788
|
-
process.stdin.once("error",cleanup);
|
|
7789
|
-
process.stdin.on("data",cleanup);
|
|
7790
|
-
process.stdin.resume();
|
|
7791
|
-
for(const signal of ["SIGTERM","SIGINT","SIGHUP"])process.once(signal,cleanup);
|
|
7792
|
-
let done=false, out=Buffer.alloc(0), err=Buffer.alloc(0);
|
|
7793
|
-
function report(status,error){
|
|
7794
|
-
if(done)return; done=true;
|
|
7795
|
-
process.stdout.write(JSON.stringify({status,error,stdout:out.toString("utf8"),stderr:err.toString("utf8")})+"\n");
|
|
7796
|
-
}
|
|
7797
|
-
const child=spawn(spec.command,spec.args,{stdio:["ignore","pipe","pipe"],env:process.env});
|
|
7798
|
-
for(const [stream,name] of [[child.stdout,"stdout"],[child.stderr,"stderr"]]){
|
|
7799
|
-
stream.on("data",bytes=>{
|
|
7800
|
-
if(done)return;
|
|
7801
|
-
const before=name==="stdout"?out:err;
|
|
7802
|
-
if(before.length+bytes.length>spec.maxBuffer){report(null,{code:"ENOBUFS"});return}
|
|
7803
|
-
if(name==="stdout")out=Buffer.concat([out,bytes]);else err=Buffer.concat([err,bytes]);
|
|
7804
|
-
});
|
|
7805
|
-
stream.on("error",()=>report(null,{code:"ECHILD"}));
|
|
7806
|
-
}
|
|
7807
|
-
child.on("error",()=>report(null,{code:"ECHILD"}));
|
|
7808
|
-
// A successful observation includes complete streams. A nested client that
|
|
7809
|
-
// keeps them open after its parent exits is a failure requiring group cleanup.
|
|
7810
|
-
child.on("exit",()=>setTimeout(()=>report(null,{code:"ECHILD"}),100));
|
|
7811
|
-
child.on("close",(status,signal)=>report(status,signal?{code:"ECHILD"}:undefined));
|
|
7812
|
-
`;
|
|
7813
|
-
|
|
7814
|
-
// src/native-readiness.ts
|
|
7815
|
-
function isReadinessProvider(value) {
|
|
7816
|
-
return value === "claude" || value === "codex" || value === "sumi";
|
|
7817
|
-
}
|
|
7818
|
-
var safeFailureCodes = new Set([
|
|
7819
|
-
"unsupported_platform",
|
|
7820
|
-
"station_detection_failed",
|
|
7821
|
-
"station_mismatch",
|
|
7822
|
-
"hosted_unavailable",
|
|
7823
|
-
"authentication_refused",
|
|
7824
|
-
"station_setup_required",
|
|
7825
|
-
"invalid_status",
|
|
7826
|
-
"deadline_exceeded",
|
|
7827
|
-
"retention_mismatch",
|
|
7828
|
-
"managed_instructions_refused",
|
|
7829
|
-
"removal_instruction_missing",
|
|
7830
|
-
"instructions_changed",
|
|
7831
|
-
"native_config_changed",
|
|
7832
|
-
"guard_refused",
|
|
7833
|
-
"owner_refused"
|
|
7834
|
-
]);
|
|
7835
|
-
|
|
7836
|
-
// src/lib/native-readiness-command.ts
|
|
7837
7837
|
var quote2 = (value) => "'" + value.replaceAll("'", "'\\''") + "'";
|
|
7838
7838
|
var bootstrap = String.raw`/* hasna-native-readiness-v1 */ (() => {
|
|
7839
7839
|
const fs = require("node:fs"), path = require("node:path"), crypto = require("node:crypto");
|
|
@@ -8106,7 +8106,7 @@ function writeHookSettingsPreimage(path, settings, before) {
|
|
|
8106
8106
|
// src/lib/claude-skills-coordination.ts
|
|
8107
8107
|
import { createHash as createHash6 } from "crypto";
|
|
8108
8108
|
|
|
8109
|
-
//
|
|
8109
|
+
// ../../node_modules/.bun/@hasna+skills@0.9.17+a00d3064559565bb/node_modules/@hasna/skills/dist/index.js
|
|
8110
8110
|
import { existsSync as existsSync10 } from "fs";
|
|
8111
8111
|
import { homedir as homedir5 } from "os";
|
|
8112
8112
|
import { join as join9, resolve as resolve3 } from "path";
|
|
@@ -39769,7 +39769,7 @@ function registerHook(name, scope = "global", target = "claude", profile, mement
|
|
|
39769
39769
|
name,
|
|
39770
39770
|
event: "SessionStart",
|
|
39771
39771
|
matcher: "^(startup|resume|clear|fork)$",
|
|
39772
|
-
timeoutSeconds:
|
|
39772
|
+
timeoutSeconds: TRASH_READINESS_NATIVE_TIMEOUT_SECONDS,
|
|
39773
39773
|
displayName: "Trash Readiness",
|
|
39774
39774
|
description: "Read-only native startup readiness",
|
|
39775
39775
|
version: "0.1.0",
|
|
@@ -41563,7 +41563,7 @@ function selectCodexSafety(discovery, configuration, home, cwd, featureEnabled,
|
|
|
41563
41563
|
need5(selected.length !== 0, "guard_missing");
|
|
41564
41564
|
need5(selected.length === 1, "guard_ambiguous");
|
|
41565
41565
|
const hook = selected[0], binding = readiness ? nativeReadinessCommandBinding(hook.command) : nativeSafetyCommandBinding(hook.command);
|
|
41566
|
-
need5(binding.home === home && (!readiness || binding?.provider === "codex") && hook.eventName === (readiness ? "sessionStart" : "preToolUse") && hook.handlerType === "command" && hook.matcher === (readiness ? "^(startup|resume|clear|fork)$" : matcher) && hook.timeoutSec === (readiness ?
|
|
41566
|
+
need5(binding.home === home && (!readiness || binding?.provider === "codex") && hook.eventName === (readiness ? "sessionStart" : "preToolUse") && hook.handlerType === "command" && hook.matcher === (readiness ? "^(startup|resume|clear|fork)$" : matcher) && hook.timeoutSec === (readiness ? TRASH_READINESS_NATIVE_TIMEOUT_SECONDS : 10) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && typeof hook.key === "string" && hook.key.length <= 4096 && typeof hook.sourcePath === "string" && isAbsolute17(hook.sourcePath) && hook.pluginId === null && hook.isManaged === false && ["user", "project"].includes(hook.source) && typeof hook.currentHash === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash), "guard_definition_invalid");
|
|
41567
41567
|
need5(typeof hook.enabled === "boolean" && ["trusted", "untrusted", "modified"].includes(hook.trustStatus), "guard_definition_invalid");
|
|
41568
41568
|
if (requireReady) {
|
|
41569
41569
|
need5(hook.enabled === true, "guard_disabled");
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type ReadinessChildResult, type ReadinessProcessOptions } from "./lib/readiness-process";
|
|
2
2
|
export type ReadinessProvider = "claude" | "codex" | "sumi";
|
|
3
|
+
export declare const TRASH_READINESS_DEFAULT_TIMEOUT_MS = 45000;
|
|
4
|
+
export declare const TRASH_READINESS_MAX_TIMEOUT_MS = 60000;
|
|
5
|
+
export declare const TRASH_READINESS_NATIVE_TIMEOUT_SECONDS: number;
|
|
3
6
|
type Pin = {
|
|
4
7
|
path: string;
|
|
5
8
|
sha256: string;
|
package/dist/native-readiness.js
CHANGED
|
@@ -144,6 +144,9 @@ function runReadinessProcess(command, args, options) {
|
|
|
144
144
|
import { closeSync, constants, fstatSync, lstatSync, openSync, readSync, realpathSync } from "fs";
|
|
145
145
|
import { homedir } from "os";
|
|
146
146
|
import { dirname, isAbsolute, join, relative, resolve } from "path";
|
|
147
|
+
var TRASH_READINESS_DEFAULT_TIMEOUT_MS = 45000;
|
|
148
|
+
var TRASH_READINESS_MAX_TIMEOUT_MS = 60000;
|
|
149
|
+
var TRASH_READINESS_NATIVE_TIMEOUT_SECONDS = TRASH_READINESS_MAX_TIMEOUT_MS / 1000 + 5;
|
|
147
150
|
|
|
148
151
|
class ReadinessError extends Error {
|
|
149
152
|
code;
|
|
@@ -172,7 +175,7 @@ function inside(home, path) {
|
|
|
172
175
|
function parseTrashReadinessBinding(input, provider, home) {
|
|
173
176
|
const b = input;
|
|
174
177
|
need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
|
|
175
|
-
need(keys(b, ["schema", "provider", "home", "runtime", "trash", "plan", "timeoutMs"]) && b.schema === "hasna.hooks.trash-readiness/v1" && b.provider === provider && b.home === home && pin(b.runtime) && pin(b.plan) && keys(b.trash, ["root", "version", "cliSha256"]) && absolute(b.trash.root) && typeof b.trash.version === "string" && b.trash.version.length <= 128 && /^\d+\.\d+\.\d+$/.test(b.trash.version) && digest(b.trash.cliSha256) && Number.isInteger(b.timeoutMs) && b.timeoutMs >= 1000 && b.timeoutMs <=
|
|
178
|
+
need(keys(b, ["schema", "provider", "home", "runtime", "trash", "plan", "timeoutMs"]) && b.schema === "hasna.hooks.trash-readiness/v1" && b.provider === provider && b.home === home && pin(b.runtime) && pin(b.plan) && keys(b.trash, ["root", "version", "cliSha256"]) && absolute(b.trash.root) && typeof b.trash.version === "string" && b.trash.version.length <= 128 && /^\d+\.\d+\.\d+$/.test(b.trash.version) && digest(b.trash.cliSha256) && Number.isInteger(b.timeoutMs) && b.timeoutMs >= 1000 && b.timeoutMs <= TRASH_READINESS_MAX_TIMEOUT_MS && inside(home, b.plan.path) && inside(home, b.trash.root), "binding_invalid");
|
|
176
179
|
return structuredClone(b);
|
|
177
180
|
}
|
|
178
181
|
function trashReadinessBindingPath(provider, home = homedir()) {
|
|
@@ -324,5 +327,8 @@ export {
|
|
|
324
327
|
parseTrashReadinessBinding,
|
|
325
328
|
isReadinessProvider,
|
|
326
329
|
handleReadinessSessionStart,
|
|
327
|
-
checkTrashReadinessBinding
|
|
330
|
+
checkTrashReadinessBinding,
|
|
331
|
+
TRASH_READINESS_NATIVE_TIMEOUT_SECONDS,
|
|
332
|
+
TRASH_READINESS_MAX_TIMEOUT_MS,
|
|
333
|
+
TRASH_READINESS_DEFAULT_TIMEOUT_MS
|
|
328
334
|
};
|
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";
|