@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/bin/index.js CHANGED
@@ -732,19 +732,350 @@ var init_registry = __esm(() => {
732
732
  ];
733
733
  });
734
734
 
735
+ // src/lib/readiness-process.ts
736
+ import { spawn } from "child_process";
737
+ function runReadinessProcess(command, args, options) {
738
+ if (!["darwin", "linux"].includes(process.platform)) {
739
+ return Promise.resolve({ status: null, error: { code: "ENOTSUP" }, stdout: "", stderr: "" });
740
+ }
741
+ if (options.signal?.aborted) {
742
+ return Promise.resolve({ status: null, error: { code: "ABORT_ERR" }, stdout: "", stderr: "" });
743
+ }
744
+ return new Promise((resolve2) => {
745
+ const child = spawn(command, ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install", "--eval", supervisor, "--", JSON.stringify({ command, args, maxBuffer: options.maxBuffer, timeout: options.timeout })], {
746
+ cwd: options.cwd,
747
+ env: options.env,
748
+ detached: true,
749
+ stdio: ["pipe", "pipe", "pipe"]
750
+ });
751
+ let status = null, error;
752
+ let stopping = false, exited = false, finished = false;
753
+ let stdout = "", stderr = "", control = "";
754
+ const maximumEnvelope = options.maxBuffer * 12 + 1024;
755
+ let cleanup;
756
+ const finish = () => {
757
+ if (finished)
758
+ return;
759
+ finished = true;
760
+ clearTimeout(deadline);
761
+ clearTimeout(cleanup);
762
+ options.signal?.removeEventListener("abort", abort);
763
+ child.stdin?.destroy();
764
+ child.stdout?.destroy();
765
+ child.stderr?.destroy();
766
+ resolve2({ status, error, stdout, stderr });
767
+ };
768
+ const stop = (code) => {
769
+ if (code && !finished)
770
+ error ??= { code };
771
+ if (finished || stopping)
772
+ return;
773
+ stopping = true;
774
+ if (exited || !child.pid) {
775
+ error ??= { code: "ECHILD" };
776
+ } else {
777
+ try {
778
+ child.stdin.end();
779
+ } catch {
780
+ error = { code: "ECHILD" };
781
+ }
782
+ }
783
+ cleanup = setTimeout(() => {
784
+ error = { code: "ECHILD" };
785
+ finish();
786
+ }, 1000);
787
+ };
788
+ const abort = () => stop("ABORT_ERR");
789
+ const deadline = setTimeout(() => stop("ETIMEDOUT"), options.timeout);
790
+ options.signal?.addEventListener("abort", abort, { once: true });
791
+ if (options.signal?.aborted)
792
+ abort();
793
+ child.stdin?.on("error", () => {
794
+ if (!stopping)
795
+ stop("ECHILD");
796
+ });
797
+ child.stdout?.on("data", (bytes) => {
798
+ if (stopping)
799
+ return;
800
+ control += bytes.toString("utf8");
801
+ if (Buffer.byteLength(control) > maximumEnvelope)
802
+ return stop("ENOBUFS");
803
+ if (!control.endsWith(`
804
+ `))
805
+ return;
806
+ try {
807
+ const value = JSON.parse(control);
808
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !["status", "error", "stdout", "stderr"].includes(key)) || !(value.status === null || Number.isInteger(value.status) && value.status >= 0 && value.status <= 255) || typeof value.stdout !== "string" || typeof value.stderr !== "string" || Buffer.byteLength(value.stdout) > options.maxBuffer || Buffer.byteLength(value.stderr) > options.maxBuffer || value.error !== undefined && (Object.keys(value.error).join() !== "code" || !["ENOBUFS", "ECHILD"].includes(value.error.code))) {
809
+ return stop("EPROTO");
810
+ }
811
+ status = value.status;
812
+ stdout = value.stdout;
813
+ stderr = value.stderr;
814
+ stop(value.error?.code);
815
+ } catch {
816
+ stop("EPROTO");
817
+ }
818
+ });
819
+ child.stdout?.on("error", () => stop("EPROTO"));
820
+ child.stderr?.on("data", () => stop("ECHILD"));
821
+ child.stderr?.on("error", () => stop("ECHILD"));
822
+ child.on("error", () => {
823
+ error = { code: "ECHILD" };
824
+ stop();
825
+ });
826
+ child.on("exit", () => {
827
+ exited = true;
828
+ if (!stopping)
829
+ stop("ECHILD");
830
+ });
831
+ child.on("close", () => {
832
+ if (!stopping)
833
+ error = { code: "ECHILD" };
834
+ finish();
835
+ });
836
+ });
837
+ }
838
+ var supervisor;
839
+ var init_readiness_process = __esm(() => {
840
+ supervisor = String.raw`
841
+ const {spawn}=require("node:child_process");
842
+ const spec=JSON.parse(process.argv.at(-1));
843
+ // This runtime was created detached and is its group's live leader. Its
844
+ // independent timer and parent pipe remain effective if the observer exits
845
+ // or its event loop stops responding. Only this freshly created tree is hit.
846
+ const cleanup=()=>{try{process.kill(-process.pid,"SIGKILL")}catch{process.exit(1)}};
847
+ setTimeout(cleanup,spec.timeout);
848
+ process.stdin.once("end",cleanup);
849
+ process.stdin.once("error",cleanup);
850
+ process.stdin.on("data",cleanup);
851
+ process.stdin.resume();
852
+ for(const signal of ["SIGTERM","SIGINT","SIGHUP"])process.once(signal,cleanup);
853
+ let done=false, out=Buffer.alloc(0), err=Buffer.alloc(0);
854
+ function report(status,error){
855
+ if(done)return; done=true;
856
+ process.stdout.write(JSON.stringify({status,error,stdout:out.toString("utf8"),stderr:err.toString("utf8")})+"\n");
857
+ }
858
+ const child=spawn(spec.command,spec.args,{stdio:["ignore","pipe","pipe"],env:process.env});
859
+ for(const [stream,name] of [[child.stdout,"stdout"],[child.stderr,"stderr"]]){
860
+ stream.on("data",bytes=>{
861
+ if(done)return;
862
+ const before=name==="stdout"?out:err;
863
+ if(before.length+bytes.length>spec.maxBuffer){report(null,{code:"ENOBUFS"});return}
864
+ if(name==="stdout")out=Buffer.concat([out,bytes]);else err=Buffer.concat([err,bytes]);
865
+ });
866
+ stream.on("error",()=>report(null,{code:"ECHILD"}));
867
+ }
868
+ child.on("error",()=>report(null,{code:"ECHILD"}));
869
+ // A successful observation includes complete streams. A nested client that
870
+ // keeps them open after its parent exits is a failure requiring group cleanup.
871
+ child.on("exit",()=>setTimeout(()=>report(null,{code:"ECHILD"}),100));
872
+ child.on("close",(status,signal)=>report(status,signal?{code:"ECHILD"}:undefined));
873
+ `;
874
+ });
875
+
876
+ // src/native-readiness.ts
877
+ var exports_native_readiness = {};
878
+ __export(exports_native_readiness, {
879
+ trashReadinessBindingPath: () => trashReadinessBindingPath,
880
+ runTrashReadiness: () => runTrashReadiness,
881
+ readinessSessionStartOutput: () => readinessSessionStartOutput,
882
+ readinessContext: () => readinessContext,
883
+ readTrashReadinessBindingFile: () => readTrashReadinessBindingFile,
884
+ parseTrashReadinessBinding: () => parseTrashReadinessBinding,
885
+ isReadinessProvider: () => isReadinessProvider,
886
+ handleReadinessSessionStart: () => handleReadinessSessionStart,
887
+ checkTrashReadinessBinding: () => checkTrashReadinessBinding,
888
+ TRASH_READINESS_NATIVE_TIMEOUT_SECONDS: () => TRASH_READINESS_NATIVE_TIMEOUT_SECONDS,
889
+ TRASH_READINESS_MAX_TIMEOUT_MS: () => TRASH_READINESS_MAX_TIMEOUT_MS,
890
+ TRASH_READINESS_DEFAULT_TIMEOUT_MS: () => TRASH_READINESS_DEFAULT_TIMEOUT_MS
891
+ });
892
+ import { createHash } from "crypto";
893
+ import { closeSync, constants, fstatSync, lstatSync, openSync, readSync, realpathSync } from "fs";
894
+ import { homedir as homedir2 } from "os";
895
+ import { dirname, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
896
+ function need(value, code) {
897
+ if (!value)
898
+ throw new ReadinessError(code);
899
+ }
900
+ function isReadinessProvider(value) {
901
+ return value === "claude" || value === "codex" || value === "sumi";
902
+ }
903
+ function inside(home, path) {
904
+ const part = relative(home, path);
905
+ return part !== "" && part !== ".." && !part.startsWith("../") && !isAbsolute(part);
906
+ }
907
+ function parseTrashReadinessBinding(input, provider, home) {
908
+ const b = input;
909
+ need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
910
+ 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");
911
+ return structuredClone(b);
912
+ }
913
+ function trashReadinessBindingPath(provider, home = homedir2()) {
914
+ need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
915
+ return join2(home, ".hasna", "hooks", "native", "trash-readiness", provider + ".json");
916
+ }
917
+ function readSafe(path, maximum, executable = false) {
918
+ need(absolute(path) && realpathSync(path) === path, "unsafe_path");
919
+ for (let parent = dirname(path);; parent = dirname(parent)) {
920
+ const stat = lstatSync(parent);
921
+ need(stat.isDirectory() && [0, process.getuid?.()].includes(stat.uid) && !(stat.mode & 18), "unsafe_path");
922
+ if (parent === dirname(parent))
923
+ break;
924
+ }
925
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
926
+ try {
927
+ const stat = fstatSync(fd);
928
+ need(stat.isFile() && [0, process.getuid?.()].includes(stat.uid) && !(stat.mode & 18) && stat.size <= maximum && (!executable || !!(stat.mode & 64)), "unsafe_path");
929
+ const bytes = Buffer.alloc(stat.size + 1);
930
+ let length = 0;
931
+ while (length < bytes.length) {
932
+ const count = readSync(fd, bytes, length, bytes.length - length, null);
933
+ if (!count)
934
+ break;
935
+ length += count;
936
+ }
937
+ const after = fstatSync(fd);
938
+ need(length === stat.size && after.size === stat.size && after.mtimeMs === stat.mtimeMs && after.ctimeMs === stat.ctimeMs, "file_changed");
939
+ return bytes.subarray(0, length);
940
+ } finally {
941
+ closeSync(fd);
942
+ }
943
+ }
944
+ function readTrashReadinessBindingFile(path, provider, home = realpathSync(homedir2())) {
945
+ const raw = readSafe(path, 65536);
946
+ return { binding: parseTrashReadinessBinding(JSON.parse(raw.toString("utf8")), provider, home), raw, sha256: sha(raw) };
947
+ }
948
+ async function runTrashReadiness(provider, d = {}) {
949
+ const started = performance.now();
950
+ const result = (code, extra = {}) => ({
951
+ schema: "hasna.hooks.trash-readiness-result/v1",
952
+ provider,
953
+ ready: code === "ready",
954
+ code,
955
+ nativeAdoptionVerified: false,
956
+ ...extra
957
+ });
958
+ let phase = "binding";
959
+ try {
960
+ const home = d.home ?? realpathSync(homedir2()), read = d.read ?? readSafe;
961
+ need(isReadinessProvider(provider), "binding_invalid");
962
+ const bindingPath = trashReadinessBindingPath(provider, home), bindingBytes = read(bindingPath, 65536);
963
+ const b = parseTrashReadinessBinding(JSON.parse(bindingBytes.toString("utf8")), provider, home);
964
+ phase = "consumer";
965
+ const checkPin = (p, maximum, executable = false) => {
966
+ const bytes = read(p.path, maximum, executable);
967
+ need(sha(bytes) === p.sha256, "file_changed");
968
+ return bytes;
969
+ };
970
+ checkPin(b.runtime, 200000000, true);
971
+ const manifestPath = join2(b.trash.root, "package.json"), manifestBytes = read(manifestPath, 65536);
972
+ const manifest = JSON.parse(manifestBytes.toString("utf8"));
973
+ need(manifest.name === "@hasna/trash" && manifest.version === b.trash.version && manifest.bin?.trash === "dist/cli/index.js", "package_mismatch");
974
+ const cli = join2(b.trash.root, "dist", "cli", "index.js");
975
+ checkPin({ path: cli, sha256: b.trash.cliSha256 }, 64 * 1024 * 1024, true);
976
+ const plan = JSON.parse(checkPin(b.plan, 65536).toString("utf8"));
977
+ need(plan?.schema === "hasna.trash.station-setup-plan/v1" && plan.stage === "ready" && plan.configurationReady === true && plan.nativeAdoptionVerified === false && digest(plan.planDigest) && plan.spec?.provider === provider && plan.spec.home === home && typeof plan.spec.station === "string" && /^[a-z0-9][a-z0-9-]{0,62}$/.test(plan.spec.station) && plan.spec.runtime?.path === b.runtime.path && plan.spec.runtime?.sha256 === b.runtime.sha256 && absolute(plan.spec.cwd) && (plan.spec.cwd === home || inside(home, plan.spec.cwd)) && typeof plan.spec.path === "string" && plan.spec.path.length <= 8192 && plan.spec.path.split(":").every(absolute), "plan_invalid");
978
+ const args = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install", cli, "station", "check", "--plan", b.plan.path];
979
+ const remaining = () => Math.floor(b.timeoutMs - (performance.now() - started));
980
+ const timeout = remaining();
981
+ need(timeout > 0, "deadline_exceeded");
982
+ const child = await (d.spawn ?? runReadinessProcess)(b.runtime.path, args, {
983
+ cwd: home,
984
+ env: { HOME: home, PATH: plan.spec.path, LANG: "C", NO_COLOR: "1" },
985
+ timeout,
986
+ maxBuffer: 16384,
987
+ signal: d.signal
988
+ });
989
+ need(remaining() > 0, "deadline_exceeded");
990
+ if (child.error && "code" in child.error && child.error.code === "ETIMEDOUT")
991
+ return result("deadline_exceeded");
992
+ if (child.error || child.signal || child.status === null)
993
+ return result("execution_failed");
994
+ need(typeof child.stdout === "string" && typeof child.stderr === "string" && Buffer.byteLength(child.stdout) <= 16384 && Buffer.byteLength(child.stderr) <= 16384, "output_invalid");
995
+ let value;
996
+ try {
997
+ value = JSON.parse(child.stdout);
998
+ } catch {
999
+ return result("output_invalid");
1000
+ }
1001
+ if (child.status !== 0 || value?.configurationReady !== true) {
1002
+ return result(safeFailureCodes.has(value?.code) ? value.code : "check_failed");
1003
+ }
1004
+ need(value.schema === "hasna.trash.station-setup-result/v1" && value.station === plan.spec.station && value.provider === provider && value.planDigest === plan.planDigest && value.serviceReady === true && value.guardVerified === true && value.managedInstructionsVerified === true && value.mcpConfigurationVerified === true && value.mcpExecutionVerified === false && value.nativeAdoptionVerified === false && child.stderr.length === 0, "output_invalid");
1005
+ checkPin(b.plan, 65536);
1006
+ checkPin({ path: cli, sha256: b.trash.cliSha256 }, 64 * 1024 * 1024, true);
1007
+ checkPin(b.runtime, 200000000, true);
1008
+ need(read(bindingPath, 65536).equals(bindingBytes) && read(manifestPath, 65536).equals(manifestBytes), "file_changed");
1009
+ need(remaining() > 0, "deadline_exceeded");
1010
+ return result("ready", { station: value.station, planDigest: value.planDigest });
1011
+ } catch (error) {
1012
+ return result(error instanceof ReadinessError ? error.code : phase === "binding" && error?.code === "ENOENT" ? "binding_missing" : "binding_invalid");
1013
+ }
1014
+ }
1015
+ function checkTrashReadinessBinding(input) {
1016
+ const home = realpathSync(homedir2()), b = parseTrashReadinessBinding(input, input?.provider, home);
1017
+ const path = trashReadinessBindingPath(b.provider, home), raw = Buffer.from(JSON.stringify(b) + `
1018
+ `);
1019
+ return runTrashReadiness(b.provider, { home, read: (selected, maximum, executable) => selected === path ? raw : readSafe(selected, maximum, executable) });
1020
+ }
1021
+ function readinessContext(result) {
1022
+ return result.ready ? `Trash readiness verified for ${result.station} (${result.provider}). Use Trash for recoverable file removal.` : `Trash readiness needs attention (${result.provider}: ${result.code}). Preserve files; do not fall back to direct deletion. Refresh the station setup before removal.`;
1023
+ }
1024
+ function readinessSessionStartOutput(result) {
1025
+ return { hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: readinessContext(result) } };
1026
+ }
1027
+ async function handleReadinessSessionStart(provider, event, dependencies = {}) {
1028
+ const input = event;
1029
+ if (!object(input) || input.hook_event_name !== "SessionStart" || !["startup", "resume", "clear", "fork", "compact"].includes(input.source)) {
1030
+ return readinessSessionStartOutput({ schema: "hasna.hooks.trash-readiness-result/v1", provider, ready: false, code: "input_invalid", nativeAdoptionVerified: false });
1031
+ }
1032
+ if (input.source === "compact")
1033
+ return {};
1034
+ return readinessSessionStartOutput(await runTrashReadiness(provider, dependencies));
1035
+ }
1036
+ var TRASH_READINESS_DEFAULT_TIMEOUT_MS = 45000, TRASH_READINESS_MAX_TIMEOUT_MS = 60000, TRASH_READINESS_NATIVE_TIMEOUT_SECONDS, ReadinessError, sha = (value) => createHash("sha256").update(value).digest("hex"), digest = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), absolute = (v) => typeof v === "string" && v.length <= 4096 && isAbsolute(v) && resolve2(v) === v && !/[\0\r\n]/.test(v), object = (v) => v !== null && typeof v === "object" && !Array.isArray(v), keys = (v, expected) => object(v) && Object.keys(v).sort().join() === expected.sort().join(), pin = (v) => keys(v, ["path", "sha256"]) && absolute(v.path) && digest(v.sha256), safeFailureCodes;
1037
+ var init_native_readiness = __esm(() => {
1038
+ init_readiness_process();
1039
+ TRASH_READINESS_NATIVE_TIMEOUT_SECONDS = TRASH_READINESS_MAX_TIMEOUT_MS / 1000 + 5;
1040
+ ReadinessError = class ReadinessError extends Error {
1041
+ code;
1042
+ constructor(code) {
1043
+ super(code);
1044
+ this.code = code;
1045
+ }
1046
+ };
1047
+ safeFailureCodes = new Set([
1048
+ "unsupported_platform",
1049
+ "station_detection_failed",
1050
+ "station_mismatch",
1051
+ "hosted_unavailable",
1052
+ "authentication_refused",
1053
+ "station_setup_required",
1054
+ "invalid_status",
1055
+ "deadline_exceeded",
1056
+ "retention_mismatch",
1057
+ "managed_instructions_refused",
1058
+ "removal_instruction_missing",
1059
+ "instructions_changed",
1060
+ "native_config_changed",
1061
+ "guard_refused",
1062
+ "owner_refused"
1063
+ ]);
1064
+ });
1065
+
735
1066
  // src/config.ts
736
- import { join as join2 } from "path";
1067
+ import { join as join3 } from "path";
737
1068
  function getHooksDataDir() {
738
1069
  return getEffectiveDataRoot();
739
1070
  }
740
1071
  function getCustomHooksDir() {
741
- return join2(getHooksDataDir(), "hooks");
1072
+ return join3(getHooksDataDir(), "hooks");
742
1073
  }
743
1074
  function getLockPath() {
744
1075
  const explicit = process.env.HASNA_HOOKS_LOCK_PATH ?? process.env.HOOKS_LOCK_PATH;
745
1076
  if (explicit)
746
1077
  return explicit;
747
- return join2(getHooksDataDir(), "hooks.lock");
1078
+ return join3(getHooksDataDir(), "hooks.lock");
748
1079
  }
749
1080
  var init_config = __esm(() => {
750
1081
  init_app_home();
@@ -774,8 +1105,8 @@ __export(exports_manifest, {
774
1105
  ScriptContainmentError: () => ScriptContainmentError,
775
1106
  HOOK_NAME_RE: () => HOOK_NAME_RE
776
1107
  });
777
- import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "fs";
778
- import { basename, dirname, isAbsolute, join as join3, normalize, resolve as resolve2, sep } from "path";
1108
+ import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, realpathSync as realpathSync2, writeFileSync } from "fs";
1109
+ import { basename, dirname as dirname2, isAbsolute as isAbsolute2, join as join4, normalize, resolve as resolve3, sep } from "path";
779
1110
  import { z } from "zod";
780
1111
  function parseManifest(json) {
781
1112
  const parsed = JSON.parse(json);
@@ -791,8 +1122,8 @@ function isWithin(child, parent) {
791
1122
  return child === parent || child.startsWith(parent + sep);
792
1123
  }
793
1124
  function assertContainedLexical(target, root, raw) {
794
- const lexical = resolve2(target);
795
- const rootLexical = resolve2(root);
1125
+ const lexical = resolve3(target);
1126
+ const rootLexical = resolve3(root);
796
1127
  if (!isWithin(lexical, rootLexical)) {
797
1128
  throw new ScriptContainmentError(target, root, raw);
798
1129
  }
@@ -802,16 +1133,16 @@ function realpathNearest(path) {
802
1133
  const tail = [];
803
1134
  let cur = path;
804
1135
  while (!existsSync2(cur)) {
805
- const parent = dirname(cur);
1136
+ const parent = dirname2(cur);
806
1137
  if (parent === cur)
807
1138
  break;
808
1139
  tail.unshift(basename(cur));
809
1140
  cur = parent;
810
1141
  }
811
- return join3(realpathSync(cur), ...tail);
1142
+ return join4(realpathSync2(cur), ...tail);
812
1143
  }
813
1144
  function assertContainedReal(root, target, raw) {
814
- const rootReal = realpathSync(root);
1145
+ const rootReal = realpathSync2(root);
815
1146
  const targetReal = realpathNearest(target);
816
1147
  if (!isWithin(targetReal, rootReal)) {
817
1148
  throw new ScriptContainmentError(target, root, raw);
@@ -832,7 +1163,7 @@ function scriptRelFor(manifest) {
832
1163
  return `script${ext}`;
833
1164
  }
834
1165
  const rel = normalize(manifest.script);
835
- if (isAbsolute(rel)) {
1166
+ if (isAbsolute2(rel)) {
836
1167
  throw new Error(`manifest script must be relative or inline, got absolute path '${manifest.script}'`);
837
1168
  }
838
1169
  return rel;
@@ -841,25 +1172,25 @@ function resolveScript(manifest, manifestDir) {
841
1172
  if (isInlineScript(manifest))
842
1173
  return { path: scriptRelFor(manifest), content: manifest.script };
843
1174
  const rel = scriptRelFor(manifest);
844
- const resolved = assertContained(join3(manifestDir, rel), manifestDir, manifest.script);
1175
+ const resolved = assertContained(join4(manifestDir, rel), manifestDir, manifest.script);
845
1176
  if (!existsSync2(resolved)) {
846
1177
  throw new Error(`manifest script file not found: ${resolved}`);
847
1178
  }
848
1179
  return { path: rel, content: readFileSync(resolved, "utf-8") };
849
1180
  }
850
1181
  function customHookDir(name) {
851
- return join3(getCustomHooksDir(), shortManifestName(name));
1182
+ return join4(getCustomHooksDir(), shortManifestName(name));
852
1183
  }
853
1184
  function readCustomManifest(name) {
854
1185
  const dir = customHookDir(name);
855
- const manifestPath = join3(dir, "manifest.json");
1186
+ const manifestPath = join4(dir, "manifest.json");
856
1187
  if (!existsSync2(manifestPath))
857
1188
  return;
858
1189
  try {
859
1190
  const manifest = parseManifest(readFileSync(manifestPath, "utf-8"));
860
1191
  const script = resolveScript(manifest, dir);
861
1192
  const scriptIsInline = isInlineScript(manifest);
862
- return { manifest, scriptPath: join3(dir, script.path), scriptContent: script.content, scriptIsInline };
1193
+ return { manifest, scriptPath: join4(dir, script.path), scriptContent: script.content, scriptIsInline };
863
1194
  } catch (err) {
864
1195
  if (err instanceof ScriptContainmentError)
865
1196
  throw err;
@@ -880,18 +1211,18 @@ function listCustomHooks() {
880
1211
  }
881
1212
  function writeCustomHook(name, manifest, scriptContent, scriptRelPath) {
882
1213
  const dir = customHookDir(name);
883
- if (isAbsolute(scriptRelPath)) {
1214
+ if (isAbsolute2(scriptRelPath)) {
884
1215
  throw new ScriptContainmentError(scriptRelPath, dir);
885
1216
  }
886
- const scriptPath = scriptRelPath.includes("/") ? join3(dir, scriptRelPath) : join3(dir, scriptRelPath);
1217
+ const scriptPath = scriptRelPath.includes("/") ? join4(dir, scriptRelPath) : join4(dir, scriptRelPath);
887
1218
  assertContainedLexical(scriptPath, dir, scriptRelPath);
888
1219
  mkdirSync(dir, { recursive: true });
889
1220
  assertContainedReal(dir, scriptPath, scriptRelPath);
890
- const scriptDir = dirname(scriptPath);
1221
+ const scriptDir = dirname2(scriptPath);
891
1222
  if (scriptDir !== dir)
892
1223
  mkdirSync(scriptDir, { recursive: true });
893
1224
  writeFileSync(scriptPath, scriptContent, "utf-8");
894
- writeFileSync(join3(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + `
1225
+ writeFileSync(join4(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + `
895
1226
  `, "utf-8");
896
1227
  return { dir, scriptPath };
897
1228
  }
@@ -935,14 +1266,14 @@ __export(exports_resolve, {
935
1266
  resolveHook: () => resolveHook,
936
1267
  resolveBundledHooksDir: () => resolveBundledHooksDir
937
1268
  });
938
- import { dirname as dirname2, join as join4 } from "path";
1269
+ import { dirname as dirname3, join as join5 } from "path";
939
1270
  import { existsSync as existsSync3 } from "fs";
940
1271
  import { fileURLToPath } from "url";
941
- function resolveBundledHooksDir(moduleDir = dirname2(fileURLToPath(import.meta.url))) {
942
- const sourceLayout = join4(moduleDir, "..", "..", "hooks");
943
- if (existsSync3(join4(sourceLayout, "hook-gitguard")))
1272
+ function resolveBundledHooksDir(moduleDir = dirname3(fileURLToPath(import.meta.url))) {
1273
+ const sourceLayout = join5(moduleDir, "..", "..", "hooks");
1274
+ if (existsSync3(join5(sourceLayout, "hook-gitguard")))
944
1275
  return sourceLayout;
945
- return join4(moduleDir, "..", "hooks");
1276
+ return join5(moduleDir, "..", "hooks");
946
1277
  }
947
1278
  function resolveHookDir(name) {
948
1279
  const custom = readCustomManifest(name);
@@ -953,10 +1284,10 @@ function resolveHookDir(name) {
953
1284
  return;
954
1285
  const short = shortManifestName(name);
955
1286
  const bundledBase = resolveBundledHooksDir();
956
- const direct = join4(bundledBase, short);
1287
+ const direct = join5(bundledBase, short);
957
1288
  if (existsSync3(direct))
958
1289
  return direct;
959
- const prefixed = join4(bundledBase, `hook-${short}`);
1290
+ const prefixed = join5(bundledBase, `hook-${short}`);
960
1291
  return existsSync3(prefixed) ? prefixed : undefined;
961
1292
  }
962
1293
  function resolveScriptPath(name) {
@@ -966,7 +1297,7 @@ function resolveScriptPath(name) {
966
1297
  const dir = resolveHookDir(name);
967
1298
  if (!dir)
968
1299
  return;
969
- const script = join4(dir, "src", "hook.ts");
1300
+ const script = join5(dir, "src", "hook.ts");
970
1301
  return existsSync3(script) ? script : undefined;
971
1302
  }
972
1303
  function resolveHookMeta(name) {
@@ -1023,15 +1354,15 @@ var init_resolve = __esm(() => {
1023
1354
  });
1024
1355
 
1025
1356
  // src/lib/native-safety.ts
1026
- import { createHash } from "crypto";
1027
- import { closeSync, constants, existsSync as existsSync4, fstatSync, lstatSync, openSync, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "fs";
1028
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join5 } from "path";
1029
- import { homedir as homedir2 } from "os";
1357
+ import { createHash as createHash2 } from "crypto";
1358
+ import { closeSync as closeSync2, constants as constants2, existsSync as existsSync4, fstatSync as fstatSync2, lstatSync as lstatSync2, openSync as openSync2, readFileSync as readFileSync2, realpathSync as realpathSync3 } from "fs";
1359
+ import { dirname as dirname4, isAbsolute as isAbsolute3, join as join6 } from "path";
1360
+ import { homedir as homedir3 } from "os";
1030
1361
  function isNativeSafetyName(name) {
1031
1362
  return name === "trash-guard" || name === "workspace-repos-guard";
1032
1363
  }
1033
1364
  function validateBinding(b) {
1034
- if (!b || !isNativeSafetyName(b.name) || ![b.runtime, b.worker, b.home].every((p) => typeof p === "string" && isAbsolute2(p) && !/[\0\r\n]/.test(p)) || ![b.runtimeSHA256, b.workerSHA256].every((h) => /^[0-9a-f]{64}$/.test(h)) || typeof b.path !== "string" || b.path.split(":").some((p) => !isAbsolute2(p) || /[\0\r\n]/.test(p)))
1365
+ if (!b || !isNativeSafetyName(b.name) || ![b.runtime, b.worker, b.home].every((p) => typeof p === "string" && isAbsolute3(p) && !/[\0\r\n]/.test(p)) || ![b.runtimeSHA256, b.workerSHA256].every((h) => /^[0-9a-f]{64}$/.test(h)) || typeof b.path !== "string" || b.path.split(":").some((p) => !isAbsolute3(p) || /[\0\r\n]/.test(p)))
1035
1366
  throw new Error("Invalid native safety binding");
1036
1367
  }
1037
1368
  function buildNativeSafetyCommand(binding) {
@@ -1056,27 +1387,27 @@ function nativeSafetyCommandBinding(command) {
1056
1387
  }
1057
1388
  }
1058
1389
  function pinEligibleFile(file, maximum, executable = false) {
1059
- if (!isAbsolute2(file) || realpathSync2(file) !== file)
1390
+ if (!isAbsolute3(file) || realpathSync3(file) !== file)
1060
1391
  throw new Error("Native safety requires canonical files");
1061
- for (let parent = dirname3(file);; ) {
1062
- const s = lstatSync(parent);
1392
+ for (let parent = dirname4(file);; ) {
1393
+ const s = lstatSync2(parent);
1063
1394
  if (!s.isDirectory() || ![0, process.getuid()].includes(s.uid) || s.mode & 18)
1064
1395
  throw new Error("Native safety requires trusted, non-writable file ancestry");
1065
- if (parent === dirname3(parent))
1396
+ if (parent === dirname4(parent))
1066
1397
  break;
1067
- parent = dirname3(parent);
1398
+ parent = dirname4(parent);
1068
1399
  }
1069
- const fd = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW);
1400
+ const fd = openSync2(file, constants2.O_RDONLY | constants2.O_NOFOLLOW);
1070
1401
  try {
1071
- const s = fstatSync(fd);
1402
+ const s = fstatSync2(fd);
1072
1403
  if (!s.isFile() || ![0, process.getuid()].includes(s.uid) || s.mode & 18 || s.size > maximum || executable && !(s.mode & 64))
1073
1404
  throw new Error("Native safety requires an eligible installed file");
1074
1405
  const bytes = readFileSync2(fd);
1075
1406
  if (bytes.length > maximum)
1076
1407
  throw new Error("Native safety file exceeds its bound");
1077
- return createHash("sha256").update(bytes).digest("hex");
1408
+ return createHash2("sha256").update(bytes).digest("hex");
1078
1409
  } finally {
1079
- closeSync(fd);
1410
+ closeSync2(fd);
1080
1411
  }
1081
1412
  }
1082
1413
  function pinVerified(file, expected, maximum, executable = false) {
@@ -1093,14 +1424,14 @@ function nativeSafetyBindingVerified(command) {
1093
1424
  return pinVerified(binding.runtime, binding.runtimeSHA256, 200000000, true) && pinVerified(binding.worker, binding.workerSHA256, 256000);
1094
1425
  }
1095
1426
  function installedNativeSafetyCommand(name) {
1096
- const home = realpathSync2(homedir2());
1097
- const runtime = realpathSync2(process.execPath);
1098
- const candidates = [join5(import.meta.dir, "../../bin/native-safety-entry.js"), join5(import.meta.dir, "../bin/native-safety-entry.js"), join5(import.meta.dir, "native-safety-entry.js")];
1427
+ const home = realpathSync3(homedir3());
1428
+ const runtime = realpathSync3(process.execPath);
1429
+ const candidates = [join6(import.meta.dir, "../../bin/native-safety-entry.js"), join6(import.meta.dir, "../bin/native-safety-entry.js"), join6(import.meta.dir, "native-safety-entry.js")];
1099
1430
  const worker = candidates.find(existsSync4);
1100
1431
  if (!worker)
1101
1432
  throw new Error("Bundled native safety runner is missing; build or reinstall @hasna/hooks before installing its guards.");
1102
- const canonicalWorker = realpathSync2(worker);
1103
- return buildNativeSafetyCommand({ name, runtime, runtimeSHA256: pinEligibleFile(runtime, 200000000, true), worker: canonicalWorker, workerSHA256: pinEligibleFile(canonicalWorker, 256000), home, path: `${dirname3(runtime)}:${join5(home, ".bun/bin")}:/usr/local/bin:/usr/bin:/bin` });
1433
+ const canonicalWorker = realpathSync3(worker);
1434
+ return buildNativeSafetyCommand({ name, runtime, runtimeSHA256: pinEligibleFile(runtime, 200000000, true), worker: canonicalWorker, workerSHA256: pinEligibleFile(canonicalWorker, 256000), home, path: `${dirname4(runtime)}:${join6(home, ".bun/bin")}:/usr/local/bin:/usr/bin:/bin` });
1104
1435
  }
1105
1436
  var supervisorSource, quote = (value) => "'" + value.replaceAll("'", "'\\''") + "'", program, shell, prefix;
1106
1437
  var init_native_safety = __esm(() => {
@@ -1171,333 +1502,6 @@ if [ "$result" -ne 0 ]; then printf '%s\\n' 'Native safety guard refused: verifi
1171
1502
  prefix = `/usr/bin/env -i /bin/sh -c ${quote(shell)} hasna-native-safety-v1 `;
1172
1503
  });
1173
1504
 
1174
- // src/lib/readiness-process.ts
1175
- import { spawn } from "child_process";
1176
- function runReadinessProcess(command, args, options) {
1177
- if (!["darwin", "linux"].includes(process.platform)) {
1178
- return Promise.resolve({ status: null, error: { code: "ENOTSUP" }, stdout: "", stderr: "" });
1179
- }
1180
- if (options.signal?.aborted) {
1181
- return Promise.resolve({ status: null, error: { code: "ABORT_ERR" }, stdout: "", stderr: "" });
1182
- }
1183
- return new Promise((resolve3) => {
1184
- const child = spawn(command, ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install", "--eval", supervisor, "--", JSON.stringify({ command, args, maxBuffer: options.maxBuffer, timeout: options.timeout })], {
1185
- cwd: options.cwd,
1186
- env: options.env,
1187
- detached: true,
1188
- stdio: ["pipe", "pipe", "pipe"]
1189
- });
1190
- let status = null, error;
1191
- let stopping = false, exited = false, finished = false;
1192
- let stdout = "", stderr = "", control = "";
1193
- const maximumEnvelope = options.maxBuffer * 12 + 1024;
1194
- let cleanup;
1195
- const finish = () => {
1196
- if (finished)
1197
- return;
1198
- finished = true;
1199
- clearTimeout(deadline);
1200
- clearTimeout(cleanup);
1201
- options.signal?.removeEventListener("abort", abort);
1202
- child.stdin?.destroy();
1203
- child.stdout?.destroy();
1204
- child.stderr?.destroy();
1205
- resolve3({ status, error, stdout, stderr });
1206
- };
1207
- const stop = (code) => {
1208
- if (code && !finished)
1209
- error ??= { code };
1210
- if (finished || stopping)
1211
- return;
1212
- stopping = true;
1213
- if (exited || !child.pid) {
1214
- error ??= { code: "ECHILD" };
1215
- } else {
1216
- try {
1217
- child.stdin.end();
1218
- } catch {
1219
- error = { code: "ECHILD" };
1220
- }
1221
- }
1222
- cleanup = setTimeout(() => {
1223
- error = { code: "ECHILD" };
1224
- finish();
1225
- }, 1000);
1226
- };
1227
- const abort = () => stop("ABORT_ERR");
1228
- const deadline = setTimeout(() => stop("ETIMEDOUT"), options.timeout);
1229
- options.signal?.addEventListener("abort", abort, { once: true });
1230
- if (options.signal?.aborted)
1231
- abort();
1232
- child.stdin?.on("error", () => {
1233
- if (!stopping)
1234
- stop("ECHILD");
1235
- });
1236
- child.stdout?.on("data", (bytes) => {
1237
- if (stopping)
1238
- return;
1239
- control += bytes.toString("utf8");
1240
- if (Buffer.byteLength(control) > maximumEnvelope)
1241
- return stop("ENOBUFS");
1242
- if (!control.endsWith(`
1243
- `))
1244
- return;
1245
- try {
1246
- const value = JSON.parse(control);
1247
- if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !["status", "error", "stdout", "stderr"].includes(key)) || !(value.status === null || Number.isInteger(value.status) && value.status >= 0 && value.status <= 255) || typeof value.stdout !== "string" || typeof value.stderr !== "string" || Buffer.byteLength(value.stdout) > options.maxBuffer || Buffer.byteLength(value.stderr) > options.maxBuffer || value.error !== undefined && (Object.keys(value.error).join() !== "code" || !["ENOBUFS", "ECHILD"].includes(value.error.code))) {
1248
- return stop("EPROTO");
1249
- }
1250
- status = value.status;
1251
- stdout = value.stdout;
1252
- stderr = value.stderr;
1253
- stop(value.error?.code);
1254
- } catch {
1255
- stop("EPROTO");
1256
- }
1257
- });
1258
- child.stdout?.on("error", () => stop("EPROTO"));
1259
- child.stderr?.on("data", () => stop("ECHILD"));
1260
- child.stderr?.on("error", () => stop("ECHILD"));
1261
- child.on("error", () => {
1262
- error = { code: "ECHILD" };
1263
- stop();
1264
- });
1265
- child.on("exit", () => {
1266
- exited = true;
1267
- if (!stopping)
1268
- stop("ECHILD");
1269
- });
1270
- child.on("close", () => {
1271
- if (!stopping)
1272
- error = { code: "ECHILD" };
1273
- finish();
1274
- });
1275
- });
1276
- }
1277
- var supervisor;
1278
- var init_readiness_process = __esm(() => {
1279
- supervisor = String.raw`
1280
- const {spawn}=require("node:child_process");
1281
- const spec=JSON.parse(process.argv.at(-1));
1282
- // This runtime was created detached and is its group's live leader. Its
1283
- // independent timer and parent pipe remain effective if the observer exits
1284
- // or its event loop stops responding. Only this freshly created tree is hit.
1285
- const cleanup=()=>{try{process.kill(-process.pid,"SIGKILL")}catch{process.exit(1)}};
1286
- setTimeout(cleanup,spec.timeout);
1287
- process.stdin.once("end",cleanup);
1288
- process.stdin.once("error",cleanup);
1289
- process.stdin.on("data",cleanup);
1290
- process.stdin.resume();
1291
- for(const signal of ["SIGTERM","SIGINT","SIGHUP"])process.once(signal,cleanup);
1292
- let done=false, out=Buffer.alloc(0), err=Buffer.alloc(0);
1293
- function report(status,error){
1294
- if(done)return; done=true;
1295
- process.stdout.write(JSON.stringify({status,error,stdout:out.toString("utf8"),stderr:err.toString("utf8")})+"\n");
1296
- }
1297
- const child=spawn(spec.command,spec.args,{stdio:["ignore","pipe","pipe"],env:process.env});
1298
- for(const [stream,name] of [[child.stdout,"stdout"],[child.stderr,"stderr"]]){
1299
- stream.on("data",bytes=>{
1300
- if(done)return;
1301
- const before=name==="stdout"?out:err;
1302
- if(before.length+bytes.length>spec.maxBuffer){report(null,{code:"ENOBUFS"});return}
1303
- if(name==="stdout")out=Buffer.concat([out,bytes]);else err=Buffer.concat([err,bytes]);
1304
- });
1305
- stream.on("error",()=>report(null,{code:"ECHILD"}));
1306
- }
1307
- child.on("error",()=>report(null,{code:"ECHILD"}));
1308
- // A successful observation includes complete streams. A nested client that
1309
- // keeps them open after its parent exits is a failure requiring group cleanup.
1310
- child.on("exit",()=>setTimeout(()=>report(null,{code:"ECHILD"}),100));
1311
- child.on("close",(status,signal)=>report(status,signal?{code:"ECHILD"}:undefined));
1312
- `;
1313
- });
1314
-
1315
- // src/native-readiness.ts
1316
- var exports_native_readiness = {};
1317
- __export(exports_native_readiness, {
1318
- trashReadinessBindingPath: () => trashReadinessBindingPath,
1319
- runTrashReadiness: () => runTrashReadiness,
1320
- readinessSessionStartOutput: () => readinessSessionStartOutput,
1321
- readinessContext: () => readinessContext,
1322
- readTrashReadinessBindingFile: () => readTrashReadinessBindingFile,
1323
- parseTrashReadinessBinding: () => parseTrashReadinessBinding,
1324
- isReadinessProvider: () => isReadinessProvider,
1325
- handleReadinessSessionStart: () => handleReadinessSessionStart,
1326
- checkTrashReadinessBinding: () => checkTrashReadinessBinding
1327
- });
1328
- import { createHash as createHash2 } from "crypto";
1329
- import { closeSync as closeSync2, constants as constants2, fstatSync as fstatSync2, lstatSync as lstatSync2, openSync as openSync2, readSync, realpathSync as realpathSync3 } from "fs";
1330
- import { homedir as homedir3 } from "os";
1331
- import { dirname as dirname4, isAbsolute as isAbsolute3, join as join6, relative, resolve as resolve3 } from "path";
1332
- function need(value, code) {
1333
- if (!value)
1334
- throw new ReadinessError(code);
1335
- }
1336
- function isReadinessProvider(value) {
1337
- return value === "claude" || value === "codex" || value === "sumi";
1338
- }
1339
- function inside(home, path) {
1340
- const part = relative(home, path);
1341
- return part !== "" && part !== ".." && !part.startsWith("../") && !isAbsolute3(part);
1342
- }
1343
- function parseTrashReadinessBinding(input, provider, home) {
1344
- const b = input;
1345
- need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
1346
- 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");
1347
- return structuredClone(b);
1348
- }
1349
- function trashReadinessBindingPath(provider, home = homedir3()) {
1350
- need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
1351
- return join6(home, ".hasna", "hooks", "native", "trash-readiness", provider + ".json");
1352
- }
1353
- function readSafe(path, maximum, executable = false) {
1354
- need(absolute(path) && realpathSync3(path) === path, "unsafe_path");
1355
- for (let parent = dirname4(path);; parent = dirname4(parent)) {
1356
- const stat = lstatSync2(parent);
1357
- need(stat.isDirectory() && [0, process.getuid?.()].includes(stat.uid) && !(stat.mode & 18), "unsafe_path");
1358
- if (parent === dirname4(parent))
1359
- break;
1360
- }
1361
- const fd = openSync2(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
1362
- try {
1363
- const stat = fstatSync2(fd);
1364
- need(stat.isFile() && [0, process.getuid?.()].includes(stat.uid) && !(stat.mode & 18) && stat.size <= maximum && (!executable || !!(stat.mode & 64)), "unsafe_path");
1365
- const bytes = Buffer.alloc(stat.size + 1);
1366
- let length = 0;
1367
- while (length < bytes.length) {
1368
- const count = readSync(fd, bytes, length, bytes.length - length, null);
1369
- if (!count)
1370
- break;
1371
- length += count;
1372
- }
1373
- const after = fstatSync2(fd);
1374
- need(length === stat.size && after.size === stat.size && after.mtimeMs === stat.mtimeMs && after.ctimeMs === stat.ctimeMs, "file_changed");
1375
- return bytes.subarray(0, length);
1376
- } finally {
1377
- closeSync2(fd);
1378
- }
1379
- }
1380
- function readTrashReadinessBindingFile(path, provider, home = realpathSync3(homedir3())) {
1381
- const raw = readSafe(path, 65536);
1382
- return { binding: parseTrashReadinessBinding(JSON.parse(raw.toString("utf8")), provider, home), raw, sha256: sha(raw) };
1383
- }
1384
- async function runTrashReadiness(provider, d = {}) {
1385
- const started = performance.now();
1386
- const result = (code, extra = {}) => ({
1387
- schema: "hasna.hooks.trash-readiness-result/v1",
1388
- provider,
1389
- ready: code === "ready",
1390
- code,
1391
- nativeAdoptionVerified: false,
1392
- ...extra
1393
- });
1394
- let phase = "binding";
1395
- try {
1396
- const home = d.home ?? realpathSync3(homedir3()), read = d.read ?? readSafe;
1397
- need(isReadinessProvider(provider), "binding_invalid");
1398
- const bindingPath = trashReadinessBindingPath(provider, home), bindingBytes = read(bindingPath, 65536);
1399
- const b = parseTrashReadinessBinding(JSON.parse(bindingBytes.toString("utf8")), provider, home);
1400
- phase = "consumer";
1401
- const checkPin = (p, maximum, executable = false) => {
1402
- const bytes = read(p.path, maximum, executable);
1403
- need(sha(bytes) === p.sha256, "file_changed");
1404
- return bytes;
1405
- };
1406
- checkPin(b.runtime, 200000000, true);
1407
- const manifestPath = join6(b.trash.root, "package.json"), manifestBytes = read(manifestPath, 65536);
1408
- const manifest = JSON.parse(manifestBytes.toString("utf8"));
1409
- need(manifest.name === "@hasna/trash" && manifest.version === b.trash.version && manifest.bin?.trash === "dist/cli/index.js", "package_mismatch");
1410
- const cli = join6(b.trash.root, "dist", "cli", "index.js");
1411
- checkPin({ path: cli, sha256: b.trash.cliSha256 }, 64 * 1024 * 1024, true);
1412
- const plan = JSON.parse(checkPin(b.plan, 65536).toString("utf8"));
1413
- need(plan?.schema === "hasna.trash.station-setup-plan/v1" && plan.stage === "ready" && plan.configurationReady === true && plan.nativeAdoptionVerified === false && digest(plan.planDigest) && plan.spec?.provider === provider && plan.spec.home === home && typeof plan.spec.station === "string" && /^[a-z0-9][a-z0-9-]{0,62}$/.test(plan.spec.station) && plan.spec.runtime?.path === b.runtime.path && plan.spec.runtime?.sha256 === b.runtime.sha256 && absolute(plan.spec.cwd) && (plan.spec.cwd === home || inside(home, plan.spec.cwd)) && typeof plan.spec.path === "string" && plan.spec.path.length <= 8192 && plan.spec.path.split(":").every(absolute), "plan_invalid");
1414
- const args = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install", cli, "station", "check", "--plan", b.plan.path];
1415
- const remaining = () => Math.floor(b.timeoutMs - (performance.now() - started));
1416
- const timeout = remaining();
1417
- need(timeout > 0, "deadline_exceeded");
1418
- const child = await (d.spawn ?? runReadinessProcess)(b.runtime.path, args, {
1419
- cwd: home,
1420
- env: { HOME: home, PATH: plan.spec.path, LANG: "C", NO_COLOR: "1" },
1421
- timeout,
1422
- maxBuffer: 16384,
1423
- signal: d.signal
1424
- });
1425
- need(remaining() > 0, "deadline_exceeded");
1426
- if (child.error && "code" in child.error && child.error.code === "ETIMEDOUT")
1427
- return result("deadline_exceeded");
1428
- if (child.error || child.signal || child.status === null)
1429
- return result("execution_failed");
1430
- need(typeof child.stdout === "string" && typeof child.stderr === "string" && Buffer.byteLength(child.stdout) <= 16384 && Buffer.byteLength(child.stderr) <= 16384, "output_invalid");
1431
- let value;
1432
- try {
1433
- value = JSON.parse(child.stdout);
1434
- } catch {
1435
- return result("output_invalid");
1436
- }
1437
- if (child.status !== 0 || value?.configurationReady !== true) {
1438
- return result(safeFailureCodes.has(value?.code) ? value.code : "check_failed");
1439
- }
1440
- need(value.schema === "hasna.trash.station-setup-result/v1" && value.station === plan.spec.station && value.provider === provider && value.planDigest === plan.planDigest && value.serviceReady === true && value.guardVerified === true && value.managedInstructionsVerified === true && value.mcpConfigurationVerified === true && value.mcpExecutionVerified === false && value.nativeAdoptionVerified === false && child.stderr.length === 0, "output_invalid");
1441
- checkPin(b.plan, 65536);
1442
- checkPin({ path: cli, sha256: b.trash.cliSha256 }, 64 * 1024 * 1024, true);
1443
- checkPin(b.runtime, 200000000, true);
1444
- need(read(bindingPath, 65536).equals(bindingBytes) && read(manifestPath, 65536).equals(manifestBytes), "file_changed");
1445
- need(remaining() > 0, "deadline_exceeded");
1446
- return result("ready", { station: value.station, planDigest: value.planDigest });
1447
- } catch (error) {
1448
- return result(error instanceof ReadinessError ? error.code : phase === "binding" && error?.code === "ENOENT" ? "binding_missing" : "binding_invalid");
1449
- }
1450
- }
1451
- function checkTrashReadinessBinding(input) {
1452
- const home = realpathSync3(homedir3()), b = parseTrashReadinessBinding(input, input?.provider, home);
1453
- const path = trashReadinessBindingPath(b.provider, home), raw = Buffer.from(JSON.stringify(b) + `
1454
- `);
1455
- return runTrashReadiness(b.provider, { home, read: (selected, maximum, executable) => selected === path ? raw : readSafe(selected, maximum, executable) });
1456
- }
1457
- function readinessContext(result) {
1458
- return result.ready ? `Trash readiness verified for ${result.station} (${result.provider}). Use Trash for recoverable file removal.` : `Trash readiness needs attention (${result.provider}: ${result.code}). Preserve files; do not fall back to direct deletion. Refresh the station setup before removal.`;
1459
- }
1460
- function readinessSessionStartOutput(result) {
1461
- return { hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: readinessContext(result) } };
1462
- }
1463
- async function handleReadinessSessionStart(provider, event, dependencies = {}) {
1464
- const input = event;
1465
- if (!object(input) || input.hook_event_name !== "SessionStart" || !["startup", "resume", "clear", "fork", "compact"].includes(input.source)) {
1466
- return readinessSessionStartOutput({ schema: "hasna.hooks.trash-readiness-result/v1", provider, ready: false, code: "input_invalid", nativeAdoptionVerified: false });
1467
- }
1468
- if (input.source === "compact")
1469
- return {};
1470
- return readinessSessionStartOutput(await runTrashReadiness(provider, dependencies));
1471
- }
1472
- var ReadinessError, sha = (value) => createHash2("sha256").update(value).digest("hex"), digest = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), absolute = (v) => typeof v === "string" && v.length <= 4096 && isAbsolute3(v) && resolve3(v) === v && !/[\0\r\n]/.test(v), object = (v) => v !== null && typeof v === "object" && !Array.isArray(v), keys = (v, expected) => object(v) && Object.keys(v).sort().join() === expected.sort().join(), pin = (v) => keys(v, ["path", "sha256"]) && absolute(v.path) && digest(v.sha256), safeFailureCodes;
1473
- var init_native_readiness = __esm(() => {
1474
- init_readiness_process();
1475
- ReadinessError = class ReadinessError extends Error {
1476
- code;
1477
- constructor(code) {
1478
- super(code);
1479
- this.code = code;
1480
- }
1481
- };
1482
- safeFailureCodes = new Set([
1483
- "unsupported_platform",
1484
- "station_detection_failed",
1485
- "station_mismatch",
1486
- "hosted_unavailable",
1487
- "authentication_refused",
1488
- "station_setup_required",
1489
- "invalid_status",
1490
- "deadline_exceeded",
1491
- "retention_mismatch",
1492
- "managed_instructions_refused",
1493
- "removal_instruction_missing",
1494
- "instructions_changed",
1495
- "native_config_changed",
1496
- "guard_refused",
1497
- "owner_refused"
1498
- ]);
1499
- });
1500
-
1501
1505
  // src/lib/native-readiness-command.ts
1502
1506
  import { createHash as createHash3 } from "crypto";
1503
1507
  import { constants as constants3, closeSync as closeSync3, existsSync as existsSync5, fstatSync as fstatSync3, lstatSync as lstatSync3, openSync as openSync3, readFileSync as readFileSync3, realpathSync as realpathSync4 } from "fs";
@@ -2516,7 +2520,7 @@ var init_codex_settings = __esm(() => {
2516
2520
  snapshots = new WeakMap;
2517
2521
  });
2518
2522
 
2519
- // ../../../../../../../../.bun/install/cache/@hasna/skills@0.9.17@@@1/dist/index.js
2523
+ // ../../node_modules/.bun/@hasna+skills@0.9.17+a00d3064559565bb/node_modules/@hasna/skills/dist/index.js
2520
2524
  import { existsSync as existsSync10 } from "fs";
2521
2525
  import { homedir as homedir6 } from "os";
2522
2526
  import { join as join10, resolve as resolve4 } from "path";
@@ -33965,7 +33969,7 @@ function registerHook(name, scope = "global", target = "claude", profile, mement
33965
33969
  name,
33966
33970
  event: "SessionStart",
33967
33971
  matcher: "^(startup|resume|clear|fork)$",
33968
- timeoutSeconds: 20,
33972
+ timeoutSeconds: TRASH_READINESS_NATIVE_TIMEOUT_SECONDS,
33969
33973
  displayName: "Trash Readiness",
33970
33974
  description: "Read-only native startup readiness",
33971
33975
  version: "0.1.0",
@@ -34351,6 +34355,7 @@ function uninstallHook(name, scope = "global", target = "claude") {
34351
34355
  var __dirname2, HOOKS_DIR, EVENT_MAP, settingsPreimages, getInstalledHooks, JSON_SETTINGS_TARGETS;
34352
34356
  var init_installer = __esm(() => {
34353
34357
  init_registry();
34358
+ init_native_readiness();
34354
34359
  init_resolve();
34355
34360
  init_manifest();
34356
34361
  init_registration();
@@ -35177,7 +35182,7 @@ function selectCodexSafety(discovery, configuration, home, cwd, featureEnabled,
35177
35182
  need8(selected.length !== 0, "guard_missing");
35178
35183
  need8(selected.length === 1, "guard_ambiguous");
35179
35184
  const hook = selected[0], binding = readiness ? nativeReadinessCommandBinding(hook.command) : nativeSafetyCommandBinding(hook.command);
35180
- need8(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" && isAbsolute18(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");
35185
+ need8(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" && isAbsolute18(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");
35181
35186
  need8(typeof hook.enabled === "boolean" && ["trusted", "untrusted", "modified"].includes(hook.trustStatus), "guard_definition_invalid");
35182
35187
  if (requireReady) {
35183
35188
  need8(hook.enabled === true, "guard_disabled");
@@ -35248,6 +35253,7 @@ var init_codex_safety_check = __esm(() => {
35248
35253
  init_native_safety();
35249
35254
  init_native_readiness_command();
35250
35255
  init_native_safety2();
35256
+ init_native_readiness();
35251
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"]);
35252
35258
  CodexSafetyError = class CodexSafetyError extends Error {
35253
35259
  code;
@@ -35489,7 +35495,7 @@ var init_codex_safety_trust = __esm(() => {
35489
35495
  };
35490
35496
  });
35491
35497
 
35492
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
35498
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
35493
35499
  var require_error = __commonJS((exports) => {
35494
35500
  class CommanderError extends Error {
35495
35501
  constructor(exitCode, code2, message) {
@@ -35513,7 +35519,7 @@ var require_error = __commonJS((exports) => {
35513
35519
  exports.InvalidArgumentError = InvalidArgumentError;
35514
35520
  });
35515
35521
 
35516
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
35522
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
35517
35523
  var require_argument = __commonJS((exports) => {
35518
35524
  var { InvalidArgumentError } = require_error();
35519
35525
 
@@ -35592,7 +35598,7 @@ var require_argument = __commonJS((exports) => {
35592
35598
  exports.humanReadableArgName = humanReadableArgName;
35593
35599
  });
35594
35600
 
35595
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
35601
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
35596
35602
  var require_help = __commonJS((exports) => {
35597
35603
  var { humanReadableArgName } = require_argument();
35598
35604
 
@@ -35841,7 +35847,7 @@ var require_help = __commonJS((exports) => {
35841
35847
  exports.Help = Help;
35842
35848
  });
35843
35849
 
35844
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
35850
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
35845
35851
  var require_option = __commonJS((exports) => {
35846
35852
  var { InvalidArgumentError } = require_error();
35847
35853
 
@@ -35992,7 +35998,7 @@ var require_option = __commonJS((exports) => {
35992
35998
  exports.DualOptions = DualOptions;
35993
35999
  });
35994
36000
 
35995
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
36001
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
35996
36002
  var require_suggestSimilar = __commonJS((exports) => {
35997
36003
  var maxDistance = 3;
35998
36004
  function editDistance(a, b) {
@@ -36065,7 +36071,7 @@ var require_suggestSimilar = __commonJS((exports) => {
36065
36071
  exports.suggestSimilar = suggestSimilar;
36066
36072
  });
36067
36073
 
36068
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
36074
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
36069
36075
  var require_command = __commonJS((exports) => {
36070
36076
  var EventEmitter = __require("events").EventEmitter;
36071
36077
  var childProcess = __require("child_process");
@@ -37308,7 +37314,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
37308
37314
  exports.Command = Command;
37309
37315
  });
37310
37316
 
37311
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
37317
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
37312
37318
  var require_commander = __commonJS((exports) => {
37313
37319
  var { Argument } = require_argument();
37314
37320
  var { Command } = require_command();
@@ -37328,7 +37334,7 @@ var require_commander = __commonJS((exports) => {
37328
37334
  exports.InvalidOptionArgumentError = InvalidArgumentError;
37329
37335
  });
37330
37336
 
37331
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/spinners.json
37337
+ // ../../node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/spinners.json
37332
37338
  var require_spinners = __commonJS((exports, module) => {
37333
37339
  module.exports = {
37334
37340
  dots: {
@@ -38954,7 +38960,7 @@ var require_spinners = __commonJS((exports, module) => {
38954
38960
  };
38955
38961
  });
38956
38962
 
38957
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/index.js
38963
+ // ../../node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/index.js
38958
38964
  var require_cli_spinners = __commonJS((exports, module) => {
38959
38965
  var spinners = Object.assign({}, require_spinners());
38960
38966
  var spinnersList = Object.keys(spinners);
@@ -39138,7 +39144,7 @@ var init_profiles = __esm(() => {
39138
39144
  init_app_home();
39139
39145
  });
39140
39146
 
39141
- // ../../../../codex0157-source-repair/isolated-build/repo/apps/hooks/node_modules/@hasna/contracts/dist/client/transport.js
39147
+ // ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
39142
39148
  import { isIP as isIP2 } from "net";
39143
39149
  import { spawnSync as spawnSync2 } from "child_process";
39144
39150
  import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
@@ -43627,7 +43633,7 @@ async function verifyClaudeSafetyConfiguration(options = {}, dependencies = {})
43627
43633
  // src/cli/index.tsx
43628
43634
  init_codex_safety_trust();
43629
43635
 
43630
- // ../../../../../../../repos/clones/hasna/apps/apps/events/dist/commander.js
43636
+ // ../events/dist/commander.js
43631
43637
  import { chmod, mkdir, readFile as readFile2, rename, writeFile } from "fs/promises";
43632
43638
  import { Buffer as Buffer2 } from "buffer";
43633
43639
  import { existsSync as existsSync22 } from "fs";
@@ -45283,7 +45289,7 @@ function replaySummary(events2, deliveries, nextCursor) {
45283
45289
  // src/cli/index.tsx
45284
45290
  import { render } from "ink";
45285
45291
 
45286
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
45292
+ // ../../node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
45287
45293
  var import__ = __toESM(require_commander(), 1);
45288
45294
  var {
45289
45295
  program: program2,
@@ -45309,11 +45315,11 @@ import { fileURLToPath as fileURLToPath6 } from "url";
45309
45315
  import { useState as useState7 } from "react";
45310
45316
  import { Box as Box8, Text as Text10, useApp, useInput as useInput5 } from "ink";
45311
45317
 
45312
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
45318
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
45313
45319
  import React from "react";
45314
45320
  import { Box, Text } from "ink";
45315
45321
 
45316
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
45322
+ // ../../node_modules/.bun/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
45317
45323
  import process3 from "process";
45318
45324
  function isUnicodeSupported() {
45319
45325
  const { env } = process3;
@@ -45324,7 +45330,7 @@ function isUnicodeSupported() {
45324
45330
  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";
45325
45331
  }
45326
45332
 
45327
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/figures@6.1.0/node_modules/figures/index.js
45333
+ // ../../node_modules/.bun/figures@6.1.0/node_modules/figures/index.js
45328
45334
  var common2 = {
45329
45335
  circleQuestionMark: "(?)",
45330
45336
  questionMarkPrefix: "(?)",
@@ -45600,23 +45606,23 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
45600
45606
  var figures_default = figures;
45601
45607
  var replacements = Object.entries(specialMainSymbols);
45602
45608
 
45603
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
45609
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
45604
45610
  function Indicator({ isSelected = false }) {
45605
45611
  return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures_default.pointer) : React.createElement(Text, null, " "));
45606
45612
  }
45607
45613
  var Indicator_default = Indicator;
45608
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Item.js
45614
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Item.js
45609
45615
  import * as React2 from "react";
45610
45616
  import { Text as Text2 } from "ink";
45611
45617
  function Item({ isSelected = false, label }) {
45612
45618
  return React2.createElement(Text2, { color: isSelected ? "blue" : undefined }, label);
45613
45619
  }
45614
45620
  var Item_default = Item;
45615
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
45621
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
45616
45622
  import { isDeepStrictEqual } from "util";
45617
45623
  import React3, { useState, useEffect, useRef, useCallback } from "react";
45618
45624
 
45619
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/to-rotated@1.0.0/node_modules/to-rotated/index.js
45625
+ // ../../node_modules/.bun/to-rotated@1.0.0/node_modules/to-rotated/index.js
45620
45626
  function toRotated(array3, steps) {
45621
45627
  if (!Array.isArray(array3)) {
45622
45628
  throw new TypeError(`Expected an array, got \`${typeof array3}\`.`);
@@ -45638,7 +45644,7 @@ function toRotated(array3, steps) {
45638
45644
  ];
45639
45645
  }
45640
45646
 
45641
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
45647
+ // ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
45642
45648
  import { Box as Box2, useInput } from "ink";
45643
45649
  function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator_default, itemComponent = Item_default, limit: customLimit, onSelect, onHighlight }) {
45644
45650
  const hasLimit = typeof customLimit === "number" && items.length > customLimit;
@@ -45934,7 +45940,7 @@ function HookSelect({
45934
45940
  import { useState as useState4, useEffect as useEffect3 } from "react";
45935
45941
  import { Box as Box6, Text as Text7, useInput as useInput4 } from "ink";
45936
45942
 
45937
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-text-input@6.0.0+fa875fef9f949ebd/node_modules/ink-text-input/build/index.js
45943
+ // ../../node_modules/.bun/ink-text-input@6.0.0+fa875fef9f949ebd/node_modules/ink-text-input/build/index.js
45938
45944
  import React5, { useState as useState3, useEffect as useEffect2 } from "react";
45939
45945
  import { Text as Text6, useInput as useInput3 } from "ink";
45940
45946
  import chalk from "chalk";
@@ -46112,7 +46118,7 @@ function SearchView({
46112
46118
  import { useState as useState6, useEffect as useEffect5 } from "react";
46113
46119
  import { Box as Box7, Text as Text9 } from "ink";
46114
46120
 
46115
- // ../../../../../../../repos/clones/hasna/apps/node_modules/.bun/ink-spinner@5.0.0+fa875fef9f949ebd/node_modules/ink-spinner/build/index.js
46121
+ // ../../node_modules/.bun/ink-spinner@5.0.0+fa875fef9f949ebd/node_modules/ink-spinner/build/index.js
46116
46122
  var import_cli_spinners = __toESM(require_cli_spinners(), 1);
46117
46123
  import React7, { useState as useState5, useEffect as useEffect4 } from "react";
46118
46124
  import { Text as Text8 } from "ink";