@hasna/hooks 0.8.0 → 0.9.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.
Files changed (63) hide show
  1. package/README.md +33 -5
  2. package/bin/hooks-mcp.js +4862 -0
  3. package/bin/index.js +592 -170
  4. package/bin/serve.js +33 -10
  5. package/dist/db/index.d.ts +8 -0
  6. package/dist/index.d.ts +4 -1
  7. package/dist/index.js +2870 -2709
  8. package/dist/lib/db-writer.d.ts +30 -1
  9. package/dist/lib/installer.d.ts +40 -1
  10. package/dist/lib/local-opt-in.d.ts +26 -0
  11. package/dist/lib/registration.d.ts +75 -0
  12. package/dist/lib/registry.d.ts +14 -0
  13. package/dist/lib/sync.d.ts +17 -1
  14. package/dist/sdk/index.d.ts +103 -0
  15. package/dist/sdk/index.js +1050 -0
  16. package/dist/storage.js +15 -1
  17. package/hooks/hook-agent-rules-version-check/README.md +1 -1
  18. package/hooks/hook-trash-guard/README.md +147 -0
  19. package/hooks/hook-trash-guard/package.json +12 -0
  20. package/hooks/hook-trash-guard/src/hook.ts +1142 -0
  21. package/package.json +10 -3
  22. package/scripts/validate-package.ts +31 -4
  23. package/hooks/codewith-native-common.test.ts +0 -1935
  24. package/hooks/hook-affected-tests/tsconfig.json +0 -25
  25. package/hooks/hook-agent-rules-version-check/src/hook.test.ts +0 -104
  26. package/hooks/hook-agent-rules-version-check/tsconfig.json +0 -25
  27. package/hooks/hook-announce-start/tsconfig.json +0 -25
  28. package/hooks/hook-announce-stop/tsconfig.json +0 -25
  29. package/hooks/hook-autoformat/tsconfig.json +0 -25
  30. package/hooks/hook-branchprotect/tsconfig.json +0 -25
  31. package/hooks/hook-checkbugs/tsconfig.json +0 -15
  32. package/hooks/hook-checkdocs/tsconfig.json +0 -15
  33. package/hooks/hook-checkfiles/tsconfig.json +0 -15
  34. package/hooks/hook-checklint/tsconfig.json +0 -15
  35. package/hooks/hook-checkpoint/tsconfig.json +0 -25
  36. package/hooks/hook-checksecurity/tsconfig.json +0 -15
  37. package/hooks/hook-checktasks/tsconfig.json +0 -20
  38. package/hooks/hook-checktests/tsconfig.json +0 -15
  39. package/hooks/hook-conflict-detect/tsconfig.json +0 -25
  40. package/hooks/hook-contextrefresh/tsconfig.json +0 -25
  41. package/hooks/hook-desktopnotify/tsconfig.json +0 -25
  42. package/hooks/hook-dm-inject/tsconfig.json +0 -25
  43. package/hooks/hook-envsetup/tsconfig.json +0 -25
  44. package/hooks/hook-failure-to-task/tsconfig.json +0 -25
  45. package/hooks/hook-filelock/tsconfig.json +0 -25
  46. package/hooks/hook-fleet-blockers-gate/src/hook.test.ts +0 -302
  47. package/hooks/hook-fleet-blockers-gate/tsconfig.json +0 -25
  48. package/hooks/hook-fleet-catchup/src/hook.test.ts +0 -156
  49. package/hooks/hook-fleet-catchup/tsconfig.json +0 -25
  50. package/hooks/hook-gitguard/tsconfig.json +0 -25
  51. package/hooks/hook-knowledge-context/src/hook.test.ts +0 -379
  52. package/hooks/hook-packageage/tsconfig.json +0 -25
  53. package/hooks/hook-permissionguard/tsconfig.json +0 -25
  54. package/hooks/hook-phonenotify/tsconfig.json +0 -25
  55. package/hooks/hook-precompact/tsconfig.json +0 -25
  56. package/hooks/hook-protectfiles/tsconfig.json +0 -25
  57. package/hooks/hook-scanoutput/src/hook.test.ts +0 -217
  58. package/hooks/hook-spiral-detector/src/hook.test.ts +0 -72
  59. package/hooks/hook-stylescheck/tsconfig.json +0 -25
  60. package/hooks/hook-typecheck-gate/tsconfig.json +0 -25
  61. package/hooks/hook-workspace-repos-guard/src/hook.test.ts +0 -466
  62. package/hooks/hook-workspace-repos-guard/tsconfig.json +0 -21
  63. package/hooks/mention-context/src/hook.test.ts +0 -68
package/README.md CHANGED
@@ -130,7 +130,32 @@ HOOKS_LOCAL=1 hooks list # accepted alias
130
130
 
131
131
  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
132
 
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`.
133
+ **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.
134
+
135
+ **`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.
136
+
137
+ 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).
138
+
139
+ **MCP server (`hooks-mcp`).** One package, four surfaces: the stdio MCP server is the `hooks-mcp` bin (34 tools).
140
+
141
+ ```bash
142
+ bun install -g @hasna/hooks # then "command": "hooks-mcp" in your agent's mcpServers
143
+ bunx -p @hasna/hooks hooks-mcp # no global install
144
+ hooks mcp --stdio # same server through the CLI; --sse / --http for the shared transports
145
+ ```
146
+
147
+ `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.
148
+
149
+ **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`.
150
+
151
+ ```ts
152
+ import { createHooksClient } from "@hasna/hooks/sdk";
153
+
154
+ const registry = createHooksClient(); // throws REMOTE_API_CONFIG_MISSING with nothing configured
155
+ const catalog = await registry.catalog(); // GET <origin>/api/v1/catalog
156
+ const lock = await registry.lock(); // GET <origin>/api/v1/lock
157
+ const artifact = await registry.artifact("gitguard", lock.hooks.gitguard.version);
158
+ ```
134
159
 
135
160
  ```bash
136
161
  hooks init --cloudflare --api-url https://registry.example.com --api-key <vault-key-name>
@@ -205,7 +230,7 @@ the data layer, so it is no longer expressed as one.
205
230
  | `HASNA_HOOKS_API_KEY_OVERRIDE` | Deliberate per-run key override (tier 1). |
206
231
  | `HASNA_HOOKS_API_KEY_REF` | Vault ITEM KEY name; resolved through `@hasna/secrets` at request time. Never a value. |
207
232
  | `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. |
233
+ | `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
234
  | `HASNA_STATION` | Keychain account when reading `hasna.credentials.hooks.*`. |
210
235
  | `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
236
  | `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 +238,12 @@ the data layer, so it is no longer expressed as one.
213
238
 
214
239
  ## Runtime model
215
240
 
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.
241
+ This package is an npm CLI (`hooks`), a stdio MCP server (`hooks-mcp`), a local
242
+ registry server (`hooks-serve`) and an importable hosted client (`@hasna/hooks/sdk`).
243
+ Installing and running hooks needs nothing deployed anywhere, but the on-box SQLite
244
+ store is never a silent default: every client surface either resolves a registry
245
+ credential (hosted route — no local store is opened) or is told `HASNA_HOOKS_LOCAL=1`
246
+ (local mode — announced on stderr); with neither it exits non-zero and creates nothing.
219
247
 
220
248
  ## Data Directory
221
249