@hasna/hooks 0.9.0 → 0.9.2
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 +43 -5
- package/bin/hooks-mcp.js +4980 -0
- package/bin/index.js +586 -252
- package/bin/serve.js +34 -12
- package/dist/db/index.d.ts +8 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3016 -2782
- package/dist/lib/codex-settings.d.ts +3 -0
- package/dist/lib/db-writer.d.ts +30 -1
- package/dist/lib/installer.d.ts +1 -1
- package/dist/lib/local-opt-in.d.ts +26 -0
- package/dist/lib/sync.d.ts +17 -1
- package/dist/sdk/index.d.ts +103 -0
- package/dist/sdk/index.js +1050 -0
- package/dist/storage.js +15 -1
- package/hooks/hook-mementos-context/README.md +80 -0
- package/hooks/hook-mementos-context/src/hook.ts +116 -0
- package/hooks/hook-trash-guard/README.md +20 -5
- package/hooks/hook-trash-guard/package.json +1 -1
- package/hooks/hook-trash-guard/src/hook.ts +45 -17
- package/package.json +11 -5
- package/scripts/validate-package.ts +31 -4
package/README.md
CHANGED
|
@@ -48,6 +48,16 @@ tools return compact summaries by default, while explicit flags such as
|
|
|
48
48
|
`compact:false`, `verbose:true`, or a detail tool like `hooks_info` return full
|
|
49
49
|
records.
|
|
50
50
|
|
|
51
|
+
## Optional Mementos prompt context
|
|
52
|
+
|
|
53
|
+
`hooks install mementos-context --target codex` registers a native prompt hook.
|
|
54
|
+
Enable it in the calling shell with `HOOKS_MEMENTOS_ENABLED=1`; set
|
|
55
|
+
`HOOKS_MEMENTOS_PROJECT` to an existing Mementos project. Provider judgments are
|
|
56
|
+
separately opt-in. The hook returns bounded, quoted memory data and continues
|
|
57
|
+
on errors. See [setup, scope and provider options](hooks/hook-mementos-context/README.md).
|
|
58
|
+
Codex requires review and trust of the exact registration through `/hooks`.
|
|
59
|
+
Claude Code and Codewith also support this hook through their explicit targets.
|
|
60
|
+
|
|
51
61
|
## Codewith-native hooks
|
|
52
62
|
|
|
53
63
|
@hasna/hooks includes unprefixed Codewith-native hook names:
|
|
@@ -130,7 +140,32 @@ HOOKS_LOCAL=1 hooks list # accepted alias
|
|
|
130
140
|
|
|
131
141
|
Local mode is answered BEFORE the resolver runs (so an unhosted run touches neither the Keychain nor the credential file) and says so on stderr, once per process.
|
|
132
142
|
|
|
133
|
-
|
|
143
|
+
**Hosted is a route, not just admission (owner ruling 2026-09-07).** Once a registry credential resolves — the env pair, the Keychain item, or the credentials file — the on-box SQLite store is refused for the whole process: `hooks log *`, `hooks storage *`, the MCP `hooks_log_*` / `storage_*` / `send_feedback` tools and the hook-event writer answer `REMOTE_COMMAND_UNSUPPORTED` (naming the opt-in) instead of reading or creating `~/.hasna/hooks/hooks.db`. Pins and trust keep working on the hosted route through `hooks.lock` alone; the SQLite `hooks` table is a local-mode mirror.
|
|
144
|
+
|
|
145
|
+
**`hooks run` decides its route like every other client verb.** Under the explicit opt-in it executes the hook and records the event in the on-box store (the child hook sees `HOOKS_LOCAL`); on the hosted route it executes the hook but refuses the event write loudly (one stderr line — the hosted registry has no event route); with nothing configured it exits 1 with one line naming the credential tiers and the opt-in, and creates nothing. Agents that wire `hooks run <name>` into their settings on an unconfigured machine therefore need either a registry credential or `HASNA_HOOKS_LOCAL=1` in the hook's environment.
|
|
146
|
+
|
|
147
|
+
Surfaces that never open the client store and are server/operator-only by design need neither setting: `serve` (`hooks-serve`), `cf`, `migrate`, `init`, `profile-export`/`profile-import`, `channels`, `events`, and `--help`/`--version`. `hooks mcp` and the `hooks-mcp` bin decide their authority themselves before any transport connects (below).
|
|
148
|
+
|
|
149
|
+
**MCP server (`hooks-mcp`).** One package, four surfaces: the stdio MCP server is the `hooks-mcp` bin (34 tools).
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
bun install -g @hasna/hooks # then "command": "hooks-mcp" in your agent's mcpServers
|
|
153
|
+
bunx -p @hasna/hooks hooks-mcp # no global install
|
|
154
|
+
hooks mcp --stdio # same server through the CLI; --sse / --http for the shared transports
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`hooks-mcp` fails closed at startup: with nothing configured it prints one `REMOTE_API_*` line naming the credential tiers and `HASNA_HOOKS_LOCAL=1`, exits 1 before answering `initialize`, and creates no file. Under a resolved credential it serves the catalog/install tools and the local-only tools refuse with `REMOTE_COMMAND_UNSUPPORTED`; under the opt-in it serves the on-box store and prints `hooks: LOCAL mode — …` on stderr once.
|
|
158
|
+
|
|
159
|
+
**SDK (`@hasna/hooks/sdk`).** The importable surface is a hosted registry client that resolves its credential through the same chain and throws `REMOTE_API_*` when nothing resolves — it never returns a client bound to a local file, and it refuses `HASNA_HOOKS_LOCAL=1` by name (the on-box store is the CLI's). The bundle is self-contained: node builtins only, no `bun:sqlite`.
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import { createHooksClient } from "@hasna/hooks/sdk";
|
|
163
|
+
|
|
164
|
+
const registry = createHooksClient(); // throws REMOTE_API_CONFIG_MISSING with nothing configured
|
|
165
|
+
const catalog = await registry.catalog(); // GET <origin>/api/v1/catalog
|
|
166
|
+
const lock = await registry.lock(); // GET <origin>/api/v1/lock
|
|
167
|
+
const artifact = await registry.artifact("gitguard", lock.hooks.gitguard.version);
|
|
168
|
+
```
|
|
134
169
|
|
|
135
170
|
```bash
|
|
136
171
|
hooks init --cloudflare --api-url https://registry.example.com --api-key <vault-key-name>
|
|
@@ -205,7 +240,7 @@ the data layer, so it is no longer expressed as one.
|
|
|
205
240
|
| `HASNA_HOOKS_API_KEY_OVERRIDE` | Deliberate per-run key override (tier 1). |
|
|
206
241
|
| `HASNA_HOOKS_API_KEY_REF` | Vault ITEM KEY name; resolved through `@hasna/secrets` at request time. Never a value. |
|
|
207
242
|
| `HASNA_PROFILE` | Selects which identity profile the chain reads. |
|
|
208
|
-
| `HASNA_HOOKS_LOCAL` / `HOOKS_LOCAL` | Explicit opt-in to local mode (bundled registry +
|
|
243
|
+
| `HASNA_HOOKS_LOCAL` / `HOOKS_LOCAL` | Explicit opt-in to local mode (bundled registry + on-box SQLite store); answered before the resolver runs and printed on stderr. The ONLY way any client surface (`hooks`, `hooks-mcp`, `hooks run`) opens `hooks.db`; a configured registry credential outranks it. |
|
|
209
244
|
| `HASNA_STATION` | Keychain account when reading `hasna.credentials.hooks.*`. |
|
|
210
245
|
| `HASNA_HOME` / `HASNA_CONFIG_HOME` | Move the disk credential root (`<…>/hooks/config/credentials`). `~/.hasna/fleet-env`, `~/.hasna/cloud`, `~/.config/hasna` and `$XDG_CONFIG_HOME` are never read. |
|
|
211
246
|
| `HASNA_HOOKS_DATA_DIR` / `HOOKS_DATA_DIR`, `HASNA_HOOKS_HOME` / `HOOKS_HOME`, `HASNA_HOOKS_DB_PATH` / `HOOKS_DB_PATH`, `HASNA_HOOKS_LOCK_PATH` / `HOOKS_LOCK_PATH` | Local store locations (data root, DB, lock). |
|
|
@@ -213,9 +248,12 @@ the data layer, so it is no longer expressed as one.
|
|
|
213
248
|
|
|
214
249
|
## Runtime model
|
|
215
250
|
|
|
216
|
-
This package is an npm CLI
|
|
217
|
-
|
|
218
|
-
|
|
251
|
+
This package is an npm CLI (`hooks`), a stdio MCP server (`hooks-mcp`), a local
|
|
252
|
+
registry server (`hooks-serve`) and an importable hosted client (`@hasna/hooks/sdk`).
|
|
253
|
+
Installing and running hooks needs nothing deployed anywhere, but the on-box SQLite
|
|
254
|
+
store is never a silent default: every client surface either resolves a registry
|
|
255
|
+
credential (hosted route — no local store is opened) or is told `HASNA_HOOKS_LOCAL=1`
|
|
256
|
+
(local mode — announced on stderr); with neither it exits non-zero and creates nothing.
|
|
219
257
|
|
|
220
258
|
## Data Directory
|
|
221
259
|
|