@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 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
- Surfaces that are local, runtime, or operator-only by design never need either setting: `run`, `serve`, `mcp`, `cf`, `migrate`, `init`, `profile-export`/`profile-import`, `channels`, `events`, and `--help`/`--version`.
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 + local store); answered before the resolver runs and printed on stderr. |
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 and MCP server. Installing
217
- and running hooks needs nothing deployed anywhere — the SQLite backend is the
218
- default and requires no server.
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