@hasna/hooks 0.10.9 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/bin/hooks-mcp.js +354 -184
- package/bin/index.js +2879 -2638
- package/bin/native-readiness-entry.js +355 -0
- package/bin/native-safety-entry.js +7 -2
- package/bin/serve.js +9 -9
- package/dist/index.js +514 -296
- package/dist/lib/codex-safety-check.d.ts +2 -1
- package/dist/lib/codex-safety-trust.d.ts +40 -8
- package/dist/lib/installer.d.ts +11 -0
- package/dist/lib/native-readiness-command.d.ts +14 -0
- package/dist/lib/native-safety-registration.d.ts +38 -7
- package/dist/lib/readiness-process.d.ts +20 -0
- package/dist/native-readiness.d.ts +68 -0
- package/dist/native-readiness.js +328 -0
- package/dist/sdk/index.js +1 -1
- package/hooks/hook-trash-guard/src/binary.ts +6 -2
- package/hooks/native-readiness-entry.ts +31 -0
- package/package.json +7 -2
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
// src/native-readiness.ts
|
|
2
|
+
var import_node_crypto = require("node:crypto");
|
|
3
|
+
|
|
4
|
+
// src/lib/readiness-process.ts
|
|
5
|
+
var import_node_child_process = require("node:child_process");
|
|
6
|
+
var supervisor = String.raw`
|
|
7
|
+
const {spawn}=require("node:child_process");
|
|
8
|
+
const spec=JSON.parse(process.argv.at(-1));
|
|
9
|
+
// This runtime was created detached and is its group's live leader. Its
|
|
10
|
+
// independent timer and parent pipe remain effective if the observer exits
|
|
11
|
+
// or its event loop stops responding. Only this freshly created tree is hit.
|
|
12
|
+
const cleanup=()=>{try{process.kill(-process.pid,"SIGKILL")}catch{process.exit(1)}};
|
|
13
|
+
setTimeout(cleanup,spec.timeout);
|
|
14
|
+
process.stdin.once("end",cleanup);
|
|
15
|
+
process.stdin.once("error",cleanup);
|
|
16
|
+
process.stdin.on("data",cleanup);
|
|
17
|
+
process.stdin.resume();
|
|
18
|
+
for(const signal of ["SIGTERM","SIGINT","SIGHUP"])process.once(signal,cleanup);
|
|
19
|
+
let done=false, out=Buffer.alloc(0), err=Buffer.alloc(0);
|
|
20
|
+
function report(status,error){
|
|
21
|
+
if(done)return; done=true;
|
|
22
|
+
process.stdout.write(JSON.stringify({status,error,stdout:out.toString("utf8"),stderr:err.toString("utf8")})+"\n");
|
|
23
|
+
}
|
|
24
|
+
const child=spawn(spec.command,spec.args,{stdio:["ignore","pipe","pipe"],env:process.env});
|
|
25
|
+
for(const [stream,name] of [[child.stdout,"stdout"],[child.stderr,"stderr"]]){
|
|
26
|
+
stream.on("data",bytes=>{
|
|
27
|
+
if(done)return;
|
|
28
|
+
const before=name==="stdout"?out:err;
|
|
29
|
+
if(before.length+bytes.length>spec.maxBuffer){report(null,{code:"ENOBUFS"});return}
|
|
30
|
+
if(name==="stdout")out=Buffer.concat([out,bytes]);else err=Buffer.concat([err,bytes]);
|
|
31
|
+
});
|
|
32
|
+
stream.on("error",()=>report(null,{code:"ECHILD"}));
|
|
33
|
+
}
|
|
34
|
+
child.on("error",()=>report(null,{code:"ECHILD"}));
|
|
35
|
+
// A successful observation includes complete streams. A nested client that
|
|
36
|
+
// keeps them open after its parent exits is a failure requiring group cleanup.
|
|
37
|
+
child.on("exit",()=>setTimeout(()=>report(null,{code:"ECHILD"}),100));
|
|
38
|
+
child.on("close",(status,signal)=>report(status,signal?{code:"ECHILD"}:undefined));
|
|
39
|
+
`;
|
|
40
|
+
function runReadinessProcess(command, args, options) {
|
|
41
|
+
if (!["darwin", "linux"].includes(process.platform)) {
|
|
42
|
+
return Promise.resolve({ status: null, error: { code: "ENOTSUP" }, stdout: "", stderr: "" });
|
|
43
|
+
}
|
|
44
|
+
if (options.signal?.aborted) {
|
|
45
|
+
return Promise.resolve({ status: null, error: { code: "ABORT_ERR" }, stdout: "", stderr: "" });
|
|
46
|
+
}
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
const child = import_node_child_process.spawn(command, ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install", "--eval", supervisor, "--", JSON.stringify({ command, args, maxBuffer: options.maxBuffer, timeout: options.timeout })], {
|
|
49
|
+
cwd: options.cwd,
|
|
50
|
+
env: options.env,
|
|
51
|
+
detached: true,
|
|
52
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
53
|
+
});
|
|
54
|
+
let status = null, error;
|
|
55
|
+
let stopping = false, exited = false, finished = false;
|
|
56
|
+
let stdout = "", stderr = "", control = "";
|
|
57
|
+
const maximumEnvelope = options.maxBuffer * 12 + 1024;
|
|
58
|
+
let cleanup;
|
|
59
|
+
const finish = () => {
|
|
60
|
+
if (finished)
|
|
61
|
+
return;
|
|
62
|
+
finished = true;
|
|
63
|
+
clearTimeout(deadline);
|
|
64
|
+
clearTimeout(cleanup);
|
|
65
|
+
options.signal?.removeEventListener("abort", abort);
|
|
66
|
+
child.stdin?.destroy();
|
|
67
|
+
child.stdout?.destroy();
|
|
68
|
+
child.stderr?.destroy();
|
|
69
|
+
resolve({ status, error, stdout, stderr });
|
|
70
|
+
};
|
|
71
|
+
const stop = (code) => {
|
|
72
|
+
if (code && !finished)
|
|
73
|
+
error ??= { code };
|
|
74
|
+
if (finished || stopping)
|
|
75
|
+
return;
|
|
76
|
+
stopping = true;
|
|
77
|
+
if (exited || !child.pid) {
|
|
78
|
+
error ??= { code: "ECHILD" };
|
|
79
|
+
} else {
|
|
80
|
+
try {
|
|
81
|
+
child.stdin.end();
|
|
82
|
+
} catch {
|
|
83
|
+
error = { code: "ECHILD" };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
cleanup = setTimeout(() => {
|
|
87
|
+
error = { code: "ECHILD" };
|
|
88
|
+
finish();
|
|
89
|
+
}, 1000);
|
|
90
|
+
};
|
|
91
|
+
const abort = () => stop("ABORT_ERR");
|
|
92
|
+
const deadline = setTimeout(() => stop("ETIMEDOUT"), options.timeout);
|
|
93
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
94
|
+
if (options.signal?.aborted)
|
|
95
|
+
abort();
|
|
96
|
+
child.stdin?.on("error", () => {
|
|
97
|
+
if (!stopping)
|
|
98
|
+
stop("ECHILD");
|
|
99
|
+
});
|
|
100
|
+
child.stdout?.on("data", (bytes) => {
|
|
101
|
+
if (stopping)
|
|
102
|
+
return;
|
|
103
|
+
control += bytes.toString("utf8");
|
|
104
|
+
if (Buffer.byteLength(control) > maximumEnvelope)
|
|
105
|
+
return stop("ENOBUFS");
|
|
106
|
+
if (!control.endsWith(`
|
|
107
|
+
`))
|
|
108
|
+
return;
|
|
109
|
+
try {
|
|
110
|
+
const value = JSON.parse(control);
|
|
111
|
+
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))) {
|
|
112
|
+
return stop("EPROTO");
|
|
113
|
+
}
|
|
114
|
+
status = value.status;
|
|
115
|
+
stdout = value.stdout;
|
|
116
|
+
stderr = value.stderr;
|
|
117
|
+
stop(value.error?.code);
|
|
118
|
+
} catch {
|
|
119
|
+
stop("EPROTO");
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
child.stdout?.on("error", () => stop("EPROTO"));
|
|
123
|
+
child.stderr?.on("data", () => stop("ECHILD"));
|
|
124
|
+
child.stderr?.on("error", () => stop("ECHILD"));
|
|
125
|
+
child.on("error", () => {
|
|
126
|
+
error = { code: "ECHILD" };
|
|
127
|
+
stop();
|
|
128
|
+
});
|
|
129
|
+
child.on("exit", () => {
|
|
130
|
+
exited = true;
|
|
131
|
+
if (!stopping)
|
|
132
|
+
stop("ECHILD");
|
|
133
|
+
});
|
|
134
|
+
child.on("close", () => {
|
|
135
|
+
if (!stopping)
|
|
136
|
+
error = { code: "ECHILD" };
|
|
137
|
+
finish();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/native-readiness.ts
|
|
143
|
+
var import_node_fs = require("node:fs");
|
|
144
|
+
var import_node_os = require("node:os");
|
|
145
|
+
var import_node_path = require("node:path");
|
|
146
|
+
|
|
147
|
+
class ReadinessError extends Error {
|
|
148
|
+
code;
|
|
149
|
+
constructor(code) {
|
|
150
|
+
super(code);
|
|
151
|
+
this.code = code;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function need(value, code) {
|
|
155
|
+
if (!value)
|
|
156
|
+
throw new ReadinessError(code);
|
|
157
|
+
}
|
|
158
|
+
var sha = (value) => import_node_crypto.createHash("sha256").update(value).digest("hex");
|
|
159
|
+
var digest = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
|
|
160
|
+
var absolute = (v) => typeof v === "string" && v.length <= 4096 && import_node_path.isAbsolute(v) && import_node_path.resolve(v) === v && !/[\0\r\n]/.test(v);
|
|
161
|
+
var object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
162
|
+
var keys = (v, expected) => object(v) && Object.keys(v).sort().join() === expected.sort().join();
|
|
163
|
+
var pin = (v) => keys(v, ["path", "sha256"]) && absolute(v.path) && digest(v.sha256);
|
|
164
|
+
function isReadinessProvider(value) {
|
|
165
|
+
return value === "claude" || value === "codex" || value === "sumi";
|
|
166
|
+
}
|
|
167
|
+
function inside(home, path) {
|
|
168
|
+
const part = import_node_path.relative(home, path);
|
|
169
|
+
return part !== "" && part !== ".." && !part.startsWith("../") && !import_node_path.isAbsolute(part);
|
|
170
|
+
}
|
|
171
|
+
function parseTrashReadinessBinding(input, provider, home) {
|
|
172
|
+
const b = input;
|
|
173
|
+
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");
|
|
175
|
+
return structuredClone(b);
|
|
176
|
+
}
|
|
177
|
+
function trashReadinessBindingPath(provider, home = import_node_os.homedir()) {
|
|
178
|
+
need(isReadinessProvider(provider) && absolute(home), "binding_invalid");
|
|
179
|
+
return import_node_path.join(home, ".hasna", "hooks", "native", "trash-readiness", provider + ".json");
|
|
180
|
+
}
|
|
181
|
+
function readSafe(path, maximum, executable = false) {
|
|
182
|
+
need(absolute(path) && import_node_fs.realpathSync(path) === path, "unsafe_path");
|
|
183
|
+
for (let parent = import_node_path.dirname(path);; parent = import_node_path.dirname(parent)) {
|
|
184
|
+
const stat = import_node_fs.lstatSync(parent);
|
|
185
|
+
need(stat.isDirectory() && [0, process.getuid?.()].includes(stat.uid) && !(stat.mode & 18), "unsafe_path");
|
|
186
|
+
if (parent === import_node_path.dirname(parent))
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
const fd = import_node_fs.openSync(path, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NOFOLLOW | import_node_fs.constants.O_NONBLOCK);
|
|
190
|
+
try {
|
|
191
|
+
const stat = import_node_fs.fstatSync(fd);
|
|
192
|
+
need(stat.isFile() && [0, process.getuid?.()].includes(stat.uid) && !(stat.mode & 18) && stat.size <= maximum && (!executable || !!(stat.mode & 64)), "unsafe_path");
|
|
193
|
+
const bytes = Buffer.alloc(stat.size + 1);
|
|
194
|
+
let length = 0;
|
|
195
|
+
while (length < bytes.length) {
|
|
196
|
+
const count = import_node_fs.readSync(fd, bytes, length, bytes.length - length, null);
|
|
197
|
+
if (!count)
|
|
198
|
+
break;
|
|
199
|
+
length += count;
|
|
200
|
+
}
|
|
201
|
+
const after = import_node_fs.fstatSync(fd);
|
|
202
|
+
need(length === stat.size && after.size === stat.size && after.mtimeMs === stat.mtimeMs && after.ctimeMs === stat.ctimeMs, "file_changed");
|
|
203
|
+
return bytes.subarray(0, length);
|
|
204
|
+
} finally {
|
|
205
|
+
import_node_fs.closeSync(fd);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
var safeFailureCodes = new Set([
|
|
209
|
+
"unsupported_platform",
|
|
210
|
+
"station_detection_failed",
|
|
211
|
+
"station_mismatch",
|
|
212
|
+
"hosted_unavailable",
|
|
213
|
+
"authentication_refused",
|
|
214
|
+
"station_setup_required",
|
|
215
|
+
"invalid_status",
|
|
216
|
+
"deadline_exceeded",
|
|
217
|
+
"retention_mismatch",
|
|
218
|
+
"managed_instructions_refused",
|
|
219
|
+
"removal_instruction_missing",
|
|
220
|
+
"instructions_changed",
|
|
221
|
+
"native_config_changed",
|
|
222
|
+
"guard_refused",
|
|
223
|
+
"owner_refused"
|
|
224
|
+
]);
|
|
225
|
+
async function runTrashReadiness(provider, d = {}) {
|
|
226
|
+
const started = performance.now();
|
|
227
|
+
const result = (code, extra = {}) => ({
|
|
228
|
+
schema: "hasna.hooks.trash-readiness-result/v1",
|
|
229
|
+
provider,
|
|
230
|
+
ready: code === "ready",
|
|
231
|
+
code,
|
|
232
|
+
nativeAdoptionVerified: false,
|
|
233
|
+
...extra
|
|
234
|
+
});
|
|
235
|
+
let phase = "binding";
|
|
236
|
+
try {
|
|
237
|
+
const home = d.home ?? import_node_fs.realpathSync(import_node_os.homedir()), read = d.read ?? readSafe;
|
|
238
|
+
need(isReadinessProvider(provider), "binding_invalid");
|
|
239
|
+
const bindingPath = trashReadinessBindingPath(provider, home), bindingBytes = read(bindingPath, 65536);
|
|
240
|
+
const b = parseTrashReadinessBinding(JSON.parse(bindingBytes.toString("utf8")), provider, home);
|
|
241
|
+
phase = "consumer";
|
|
242
|
+
const checkPin = (p, maximum, executable = false) => {
|
|
243
|
+
const bytes = read(p.path, maximum, executable);
|
|
244
|
+
need(sha(bytes) === p.sha256, "file_changed");
|
|
245
|
+
return bytes;
|
|
246
|
+
};
|
|
247
|
+
checkPin(b.runtime, 200000000, true);
|
|
248
|
+
const manifestPath = import_node_path.join(b.trash.root, "package.json"), manifestBytes = read(manifestPath, 65536);
|
|
249
|
+
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
250
|
+
need(manifest.name === "@hasna/trash" && manifest.version === b.trash.version && manifest.bin?.trash === "dist/cli/index.js", "package_mismatch");
|
|
251
|
+
const cli = import_node_path.join(b.trash.root, "dist", "cli", "index.js");
|
|
252
|
+
checkPin({ path: cli, sha256: b.trash.cliSha256 }, 64 * 1024 * 1024, true);
|
|
253
|
+
const plan = JSON.parse(checkPin(b.plan, 65536).toString("utf8"));
|
|
254
|
+
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");
|
|
255
|
+
const args = ["--config=/dev/null", "--no-env-file", "--no-macros", "--no-install", cli, "station", "check", "--plan", b.plan.path];
|
|
256
|
+
const remaining = () => Math.floor(b.timeoutMs - (performance.now() - started));
|
|
257
|
+
const timeout = remaining();
|
|
258
|
+
need(timeout > 0, "deadline_exceeded");
|
|
259
|
+
const child = await (d.spawn ?? runReadinessProcess)(b.runtime.path, args, {
|
|
260
|
+
cwd: home,
|
|
261
|
+
env: { HOME: home, PATH: plan.spec.path, LANG: "C", NO_COLOR: "1" },
|
|
262
|
+
timeout,
|
|
263
|
+
maxBuffer: 16384,
|
|
264
|
+
signal: d.signal
|
|
265
|
+
});
|
|
266
|
+
need(remaining() > 0, "deadline_exceeded");
|
|
267
|
+
if (child.error && "code" in child.error && child.error.code === "ETIMEDOUT")
|
|
268
|
+
return result("deadline_exceeded");
|
|
269
|
+
if (child.error || child.signal || child.status === null)
|
|
270
|
+
return result("execution_failed");
|
|
271
|
+
need(typeof child.stdout === "string" && typeof child.stderr === "string" && Buffer.byteLength(child.stdout) <= 16384 && Buffer.byteLength(child.stderr) <= 16384, "output_invalid");
|
|
272
|
+
let value;
|
|
273
|
+
try {
|
|
274
|
+
value = JSON.parse(child.stdout);
|
|
275
|
+
} catch {
|
|
276
|
+
return result("output_invalid");
|
|
277
|
+
}
|
|
278
|
+
if (child.status !== 0 || value?.configurationReady !== true) {
|
|
279
|
+
return result(safeFailureCodes.has(value?.code) ? value.code : "check_failed");
|
|
280
|
+
}
|
|
281
|
+
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");
|
|
282
|
+
checkPin(b.plan, 65536);
|
|
283
|
+
checkPin({ path: cli, sha256: b.trash.cliSha256 }, 64 * 1024 * 1024, true);
|
|
284
|
+
checkPin(b.runtime, 200000000, true);
|
|
285
|
+
need(read(bindingPath, 65536).equals(bindingBytes) && read(manifestPath, 65536).equals(manifestBytes), "file_changed");
|
|
286
|
+
need(remaining() > 0, "deadline_exceeded");
|
|
287
|
+
return result("ready", { station: value.station, planDigest: value.planDigest });
|
|
288
|
+
} catch (error) {
|
|
289
|
+
return result(error instanceof ReadinessError ? error.code : phase === "binding" && error?.code === "ENOENT" ? "binding_missing" : "binding_invalid");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function readinessContext(result) {
|
|
293
|
+
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.`;
|
|
294
|
+
}
|
|
295
|
+
function readinessSessionStartOutput(result) {
|
|
296
|
+
return { hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: readinessContext(result) } };
|
|
297
|
+
}
|
|
298
|
+
async function handleReadinessSessionStart(provider, event, dependencies = {}) {
|
|
299
|
+
const input = event;
|
|
300
|
+
if (!object(input) || input.hook_event_name !== "SessionStart" || !["startup", "resume", "clear", "fork", "compact"].includes(input.source)) {
|
|
301
|
+
return readinessSessionStartOutput({ schema: "hasna.hooks.trash-readiness-result/v1", provider, ready: false, code: "input_invalid", nativeAdoptionVerified: false });
|
|
302
|
+
}
|
|
303
|
+
if (input.source === "compact")
|
|
304
|
+
return {};
|
|
305
|
+
return readinessSessionStartOutput(await runTrashReadiness(provider, dependencies));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// hooks/native-readiness-entry.ts
|
|
309
|
+
async function main() {
|
|
310
|
+
const provider = process.argv[2];
|
|
311
|
+
if (!isReadinessProvider(provider)) {
|
|
312
|
+
process.stderr.write(`Trash readiness needs attention (unsupported provider).
|
|
313
|
+
`);
|
|
314
|
+
process.exitCode = 1;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const invalid = () => readinessSessionStartOutput({
|
|
318
|
+
schema: "hasna.hooks.trash-readiness-result/v1",
|
|
319
|
+
provider,
|
|
320
|
+
ready: false,
|
|
321
|
+
code: "input_invalid",
|
|
322
|
+
nativeAdoptionVerified: false
|
|
323
|
+
});
|
|
324
|
+
try {
|
|
325
|
+
const input = await new Promise((accept, reject) => {
|
|
326
|
+
const chunks = [];
|
|
327
|
+
let size = 0;
|
|
328
|
+
const finish = (error) => {
|
|
329
|
+
clearTimeout(timer);
|
|
330
|
+
process.stdin.pause();
|
|
331
|
+
process.stdin.removeAllListeners("data");
|
|
332
|
+
process.stdin.removeAllListeners("end");
|
|
333
|
+
process.stdin.removeAllListeners("error");
|
|
334
|
+
error ? reject(error) : accept(Buffer.concat(chunks));
|
|
335
|
+
};
|
|
336
|
+
const timer = setTimeout(() => finish(new Error), 1000);
|
|
337
|
+
process.stdin.on("data", (chunk) => {
|
|
338
|
+
const bytes = Buffer.from(chunk);
|
|
339
|
+
size += bytes.length;
|
|
340
|
+
if (size > 65536)
|
|
341
|
+
finish(new Error);
|
|
342
|
+
else
|
|
343
|
+
chunks.push(bytes);
|
|
344
|
+
});
|
|
345
|
+
process.stdin.once("end", () => finish());
|
|
346
|
+
process.stdin.once("error", () => finish(new Error));
|
|
347
|
+
});
|
|
348
|
+
process.stdout.write(JSON.stringify(await handleReadinessSessionStart(provider, JSON.parse(input.toString("utf8")))) + `
|
|
349
|
+
`);
|
|
350
|
+
} catch {
|
|
351
|
+
process.stdout.write(JSON.stringify(invalid()) + `
|
|
352
|
+
`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
main();
|
|
@@ -170,14 +170,19 @@ function inspectTrashBinary(env = process.env) {
|
|
|
170
170
|
reject("unsafe_interpreter");
|
|
171
171
|
continue;
|
|
172
172
|
}
|
|
173
|
+
const remaining = deadline - Date.now();
|
|
174
|
+
if (remaining <= 0) {
|
|
175
|
+
reject("identity_failed");
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
173
178
|
const probe = spawnSync(candidate, ["--identity"], {
|
|
174
179
|
encoding: "utf8",
|
|
175
|
-
timeout:
|
|
180
|
+
timeout: remaining,
|
|
176
181
|
maxBuffer: 2048,
|
|
177
182
|
env: { PATH: pathValue },
|
|
178
183
|
stdio: ["ignore", "pipe", "pipe"]
|
|
179
184
|
});
|
|
180
|
-
if (probe.error || probe.status !== 0) {
|
|
185
|
+
if (probe.error || probe.status !== 0 || Date.now() >= deadline) {
|
|
181
186
|
reject("identity_failed");
|
|
182
187
|
continue;
|
|
183
188
|
}
|
package/bin/serve.js
CHANGED
|
@@ -676,7 +676,7 @@ function getHook(name) {
|
|
|
676
676
|
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "fs";
|
|
677
677
|
import { basename, dirname, isAbsolute, join as join3, normalize, resolve as resolve2, sep } from "path";
|
|
678
678
|
|
|
679
|
-
//
|
|
679
|
+
// node_modules/zod/v3/external.js
|
|
680
680
|
var exports_external = {};
|
|
681
681
|
__export(exports_external, {
|
|
682
682
|
void: () => voidType,
|
|
@@ -788,7 +788,7 @@ __export(exports_external, {
|
|
|
788
788
|
BRAND: () => BRAND
|
|
789
789
|
});
|
|
790
790
|
|
|
791
|
-
//
|
|
791
|
+
// node_modules/zod/v3/helpers/util.js
|
|
792
792
|
var util;
|
|
793
793
|
(function(util2) {
|
|
794
794
|
util2.assertEqual = (_) => {};
|
|
@@ -919,7 +919,7 @@ var getParsedType = (data) => {
|
|
|
919
919
|
}
|
|
920
920
|
};
|
|
921
921
|
|
|
922
|
-
//
|
|
922
|
+
// node_modules/zod/v3/ZodError.js
|
|
923
923
|
var ZodIssueCode = util.arrayToEnum([
|
|
924
924
|
"invalid_type",
|
|
925
925
|
"invalid_literal",
|
|
@@ -1038,7 +1038,7 @@ ZodError.create = (issues) => {
|
|
|
1038
1038
|
return error;
|
|
1039
1039
|
};
|
|
1040
1040
|
|
|
1041
|
-
//
|
|
1041
|
+
// node_modules/zod/v3/locales/en.js
|
|
1042
1042
|
var errorMap = (issue, _ctx) => {
|
|
1043
1043
|
let message;
|
|
1044
1044
|
switch (issue.code) {
|
|
@@ -1141,7 +1141,7 @@ var errorMap = (issue, _ctx) => {
|
|
|
1141
1141
|
};
|
|
1142
1142
|
var en_default = errorMap;
|
|
1143
1143
|
|
|
1144
|
-
//
|
|
1144
|
+
// node_modules/zod/v3/errors.js
|
|
1145
1145
|
var overrideErrorMap = en_default;
|
|
1146
1146
|
function setErrorMap(map) {
|
|
1147
1147
|
overrideErrorMap = map;
|
|
@@ -1149,7 +1149,7 @@ function setErrorMap(map) {
|
|
|
1149
1149
|
function getErrorMap() {
|
|
1150
1150
|
return overrideErrorMap;
|
|
1151
1151
|
}
|
|
1152
|
-
//
|
|
1152
|
+
// node_modules/zod/v3/helpers/parseUtil.js
|
|
1153
1153
|
var makeIssue = (params) => {
|
|
1154
1154
|
const { data, path, errorMaps, issueData } = params;
|
|
1155
1155
|
const fullPath = [...path, ...issueData.path || []];
|
|
@@ -1255,14 +1255,14 @@ var isAborted = (x) => x.status === "aborted";
|
|
|
1255
1255
|
var isDirty = (x) => x.status === "dirty";
|
|
1256
1256
|
var isValid = (x) => x.status === "valid";
|
|
1257
1257
|
var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
1258
|
-
//
|
|
1258
|
+
// node_modules/zod/v3/helpers/errorUtil.js
|
|
1259
1259
|
var errorUtil;
|
|
1260
1260
|
(function(errorUtil2) {
|
|
1261
1261
|
errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
|
1262
1262
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
|
|
1263
1263
|
})(errorUtil || (errorUtil = {}));
|
|
1264
1264
|
|
|
1265
|
-
//
|
|
1265
|
+
// node_modules/zod/v3/types.js
|
|
1266
1266
|
class ParseInputLazyPath {
|
|
1267
1267
|
constructor(parent, value, path, key) {
|
|
1268
1268
|
this._cachedPath = [];
|
|
@@ -5362,7 +5362,7 @@ import { readFileSync as readFileSync5 } from "fs";
|
|
|
5362
5362
|
import { dirname as dirname4, join as join8 } from "path";
|
|
5363
5363
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
5364
5364
|
|
|
5365
|
-
//
|
|
5365
|
+
// node_modules/@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";
|