@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.
@@ -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 <= 15000 && inside(home, b.plan.path) && inside(home, b.trash.root), "binding_invalid");
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 += command[i + 1] === ch && ch === ">" ? 2 : 1;
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 wrapperValues = WRAPPERS[decoded];
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[decoded] ?? 0;
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
- if (OPAQUE_COMMANDS.has(verb) && mentionsDeleteVerb(segmentText(segment))) {
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
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
- // ../../../../codex0157-source-repair/isolated-build/repo/apps/hooks/node_modules/@hasna/contracts/dist/client/transport.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/typeAliases.js
1061
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/typeAliases.js
1062
1062
  var init_typeAliases = () => {};
1063
1063
 
1064
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
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
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/zod@3.25.76/node_modules/zod/index.js
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
- // ../../../../codex0157-source-repair/isolated-build/repo/apps/hooks/node_modules/@hasna/contracts/dist/client/transport.js
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
- // ../../../../../../../../.bun/install/cache/@hasna/skills@0.9.17@@@1/dist/index.js
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: 20,
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 ? 20 : 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");
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;
@@ -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 <= 15000 && inside(home, b.plan.path) && inside(home, b.trash.root), "binding_invalid");
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
- // ../../../../codex0157-source-repair/isolated-build/repo/apps/hooks/node_modules/@hasna/contracts/dist/client/transport.js
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";