@hasna/hooks 0.10.3 → 0.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bin/hooks-mcp.js +4 -1
- package/bin/index.js +589 -111
- package/bin/native-safety-entry.js +266 -70
- package/dist/index.js +4 -1
- package/dist/lib/native-safety.d.ts +1 -0
- package/dist/native-safety.d.ts +88 -0
- package/dist/native-safety.js +401 -0
- package/hooks/hook-trash-guard/src/binary.ts +158 -0
- package/hooks/hook-trash-guard/src/hook.ts +38 -43
- package/hooks/native-safety-entry.ts +10 -2
- package/package.json +6 -2
- package/scripts/validate-package.ts +12 -3
package/README.md
CHANGED
|
@@ -82,6 +82,16 @@ or in-place edits. A missing or unauthenticated Trash client refuses the rewritt
|
|
|
82
82
|
operation; it never falls back to raw removal. Configure hosted Trash and verify a
|
|
83
83
|
disposable capture/restore before relying on recoverable deletion.
|
|
84
84
|
|
|
85
|
+
`hooks safety inspect` is a small, read-only installation check. It returns
|
|
86
|
+
compact JSON with the verified Trash path and version, or a fixed failure code
|
|
87
|
+
such as `unsafe_executable`, `unsafe_directory`, `unsafe_manifest` or
|
|
88
|
+
`identity_failed`, and exits nonzero on failure. It checks package identity,
|
|
89
|
+
ownership, permissions and a bounded credential-free protocol probe; it does not
|
|
90
|
+
contact the registry or Trash API. Use it after setup and package upgrades.
|
|
91
|
+
Repair unsafe installation permissions with a verified package installer, then
|
|
92
|
+
check again. This check alone does not prove hosted authentication, native hook
|
|
93
|
+
trust or a running agent's interception.
|
|
94
|
+
|
|
85
95
|
## Optional Mementos prompt context
|
|
86
96
|
|
|
87
97
|
`hooks install mementos-context --target codex` registers a native prompt hook.
|
|
@@ -300,6 +310,51 @@ store is never a silent default: every client surface either resolves a registry
|
|
|
300
310
|
credential (hosted route — no local store is opened) or is told `HASNA_HOOKS_LOCAL=1`
|
|
301
311
|
(local mode — announced on stderr); with neither it exits non-zero and creates nothing.
|
|
302
312
|
|
|
313
|
+
## Required Sumi safety binding
|
|
314
|
+
|
|
315
|
+
`hooks safety install trash-guard --target sumi` registers the bundled composite
|
|
316
|
+
guard for Sumi's required native adapter. `hooks safety verify --target sumi`
|
|
317
|
+
checks the exact saved supervisor by classifying a synthetic removal without
|
|
318
|
+
creating a file or executing the rewritten command. Both
|
|
319
|
+
commands are credential-free and return compact JSON. Verification explicitly
|
|
320
|
+
reports `nativeAdoptionVerified: false`: a fresh native Sumi tool invocation is
|
|
321
|
+
still required to prove that the installed harness uses this binding.
|
|
322
|
+
|
|
323
|
+
The owner-only `~/.hasna/hooks/native/sumi-trash-guard.json` pins the supervisor's
|
|
324
|
+
runtime, worker, home and PATH. Identical setup is a no-op. An upgrade requires
|
|
325
|
+
`--expected-binding-sha256 <current-digest>` and preserves the previous record.
|
|
326
|
+
An interrupted lock or unexpected current record requires reconciliation; setup
|
|
327
|
+
does not overwrite it. This file is native configuration, not a Hooks app store.
|
|
328
|
+
Setup checks the supervisor's bound PATH before registration; verification checks
|
|
329
|
+
the same readback digest before and after the probe. Package-manager bin file
|
|
330
|
+
symlinks are supported, but symlinked or writable PATH directory ancestry refuses
|
|
331
|
+
instead of hiding an unsafe parent through realpath resolution. The published
|
|
332
|
+
Trash script's Bun interpreter and all preceding PATH directories are checked
|
|
333
|
+
before its identity probe runs; unsafe or unsupported interpreter resolution
|
|
334
|
+
reports `unsafe_interpreter` without executing it.
|
|
335
|
+
|
|
336
|
+
Native adapters import `@hasna/hooks/native-safety` and pass the final shell/patch
|
|
337
|
+
operation to `evaluateNativeSafetyForExecution`, with cancellation and an explicit
|
|
338
|
+
agent label. A rewrite returns the complete command, shell, resolved cwd and
|
|
339
|
+
environment. The adapter must use those fields together, disable environment
|
|
340
|
+
inheritance, and prevent later hooks from changing them. Every rewritten removal
|
|
341
|
+
uses the verified absolute Bun runtime with a clean environment and project
|
|
342
|
+
configuration, env files, macros and installation disabled. Deletions combined
|
|
343
|
+
with shell environment changes are refused; run those removals separately.
|
|
344
|
+
|
|
345
|
+
Use `hooks safety verify --target sumi --execution` for a small, read-only check
|
|
346
|
+
that the saved worker supports this execution contract. A legacy worker that only
|
|
347
|
+
classifies commands cannot pass it. The compatible `evaluateNativeSafety` API and
|
|
348
|
+
verification without `--execution` classify commands only; their success does not
|
|
349
|
+
prove execution compatibility. Neither check runs the returned deletion, creates
|
|
350
|
+
a test file, authenticates Trash or proves native adoption.
|
|
351
|
+
|
|
352
|
+
The bounded agent label can identify the Sumi session in Trash's existing name
|
|
353
|
+
field; it does not invent unsupported harness/session fields. Missing or unhealthy
|
|
354
|
+
bindings reject the call. This covers supported shell removal and whole-file patch
|
|
355
|
+
deletion, not arbitrary filesystem writes or plugin executor replacements.
|
|
356
|
+
Installing the record alone does not activate a harness.
|
|
357
|
+
|
|
303
358
|
## Data Directory
|
|
304
359
|
|
|
305
360
|
Data is stored in `~/.hasna/hooks/`.
|
package/bin/hooks-mcp.js
CHANGED
|
@@ -2781,6 +2781,9 @@ function buildNativeSafetyCommand(binding) {
|
|
|
2781
2781
|
return prefix + [encoded, binding.runtime, binding.home, binding.path].map(quote).join(" ");
|
|
2782
2782
|
}
|
|
2783
2783
|
function nativeSafetyRegistration(command) {
|
|
2784
|
+
return nativeSafetyCommandBinding(command)?.name;
|
|
2785
|
+
}
|
|
2786
|
+
function nativeSafetyCommandBinding(command) {
|
|
2784
2787
|
if (!command.startsWith(prefix))
|
|
2785
2788
|
return;
|
|
2786
2789
|
const encoded = command.slice(prefix.length).match(/^'([A-Za-z0-9_-]+)' /)?.[1];
|
|
@@ -2788,7 +2791,7 @@ function nativeSafetyRegistration(command) {
|
|
|
2788
2791
|
return;
|
|
2789
2792
|
try {
|
|
2790
2793
|
const binding = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
2791
|
-
return buildNativeSafetyCommand(binding) === command ? binding
|
|
2794
|
+
return buildNativeSafetyCommand(binding) === command ? binding : undefined;
|
|
2792
2795
|
} catch {
|
|
2793
2796
|
return;
|
|
2794
2797
|
}
|