@hasna/hooks 0.4.1 → 0.6.0
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 +96 -12
- package/bin/index.js +2089 -470
- package/bin/serve.js +5248 -0
- package/dist/cf/provision.d.ts +24 -0
- package/dist/config.d.ts +18 -0
- package/dist/db/legacy-import.d.ts +1 -1
- package/dist/db/migrations/004_hooks_table.d.ts +9 -0
- package/dist/db/pg-migrations.d.ts +1 -1
- package/dist/db/storage-sync.d.ts +26 -6
- package/dist/index.d.ts +18 -2
- package/dist/index.js +5341 -286
- package/dist/lib/custom-install.d.ts +19 -0
- package/dist/lib/manifest.d.ts +70 -0
- package/dist/lib/resolve.d.ts +19 -0
- package/dist/lib/run.d.ts +37 -0
- package/dist/lib/store.d.ts +69 -0
- package/dist/lib/sync.d.ts +35 -0
- package/dist/serve.d.ts +36 -0
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +133 -42
- package/hooks/codewith-native-common.test.ts +1521 -3
- package/hooks/codewith-native-common.ts +1627 -37
- package/hooks/hook-scanoutput/README.md +151 -0
- package/hooks/hook-scanoutput/package.json +12 -0
- package/hooks/hook-scanoutput/src/hook.test.ts +217 -0
- package/hooks/hook-scanoutput/src/hook.ts +319 -0
- package/hooks/mention-context/README.md +109 -0
- package/hooks/mention-context/package.json +9 -0
- package/hooks/mention-context/src/hasna-mention-context.py +1218 -0
- package/hooks/mention-context/src/hasna-mention-warm.py +521 -0
- package/hooks/mention-context/src/hook.test.ts +68 -0
- package/hooks/mention-context/src/test_run_capture.py +345 -0
- package/hooks/pre-bash/README.md +72 -2
- package/hooks/worktree-guard/README.md +9 -2
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -67,10 +67,21 @@ hooks install session-start prompt-guard pre-bash worktree-guard stop-sync knowl
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
The scoped destructive-operation guard does not block every cleanup command. It
|
|
70
|
-
blocks resolved shell/file-tool targets that threaten
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
blocks resolved shell/file-tool targets that threaten `/` or a system root
|
|
71
|
+
(`/usr`, `/etc`, `/bin`, `/lib`, `/var`, `/boot`, `/home`, `/Users`, and the
|
|
72
|
+
other FHS and macOS equivalents), `~/.hasna`, configured workspace roots, Hasna
|
|
73
|
+
division/scope roots, or active repo/worktree roots, including recursive `rm`,
|
|
74
|
+
`rsync --delete`, destructive `find`, and destructive `git clean` / `git reset
|
|
75
|
+
--hard` forms.
|
|
76
|
+
|
|
77
|
+
It also blocks by *shape*: a destructive target containing a command
|
|
78
|
+
substitution or variable expansion immediately followed by `/` is checked as the
|
|
79
|
+
shell would render it if that expansion returned empty, so
|
|
80
|
+
`rm -rf "$(anything)"/*` and `rm -rf "$VAR"/*` are refused whatever the
|
|
81
|
+
expansion is. Wrapped forms (`bash -c`, `su -c`, `eval`, `ssh host '…'`) are
|
|
82
|
+
unwrapped first. See [`hooks/pre-bash/README.md`](hooks/pre-bash/README.md) for
|
|
83
|
+
the full rules, the deliberate exemptions (`${VAR:?}`, bare `"$(cmd)"` with no
|
|
84
|
+
trailing separator), and the recommended safe form.
|
|
74
85
|
|
|
75
86
|
Apply that fragment through `open-configs` or the managed config renderer. A
|
|
76
87
|
direct write path exists only for explicit local/test use:
|
|
@@ -79,14 +90,67 @@ direct write path exists only for explicit local/test use:
|
|
|
79
90
|
hooks install knowledge-context --target codewith --apply-codewith --codewith-config /tmp/codewith-config.toml
|
|
80
91
|
```
|
|
81
92
|
|
|
93
|
+
## Custom and remote hooks
|
|
94
|
+
|
|
95
|
+
A hook is defined by a manifest — `{ name, version, description, events, script, args?, timeout_ms? }` — where `script` is a relative path or inline content. Hooks come from three sources: the bundled registry, a user custom directory, or a remote registry.
|
|
96
|
+
|
|
97
|
+
**Install custom hooks** from a local directory, a git URL, or a manifest URL:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
hooks install ./my-hook # directory with manifest.json
|
|
101
|
+
hooks install git@github.com:org/hook-repo.git
|
|
102
|
+
hooks install https://example.com/hooks/my-hook/manifest.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Custom hooks land in `~/.hasna/hooks/hooks/<name>/`. A custom hook with the same name as a bundled hook takes precedence (visible in `hooks info <name>`).
|
|
106
|
+
|
|
107
|
+
**Trust model.** Every hook script is pinned by sha256 in `~/.hasna/hooks/hooks.lock` and the SQLite `hooks` table. `hooks run` verifies the script hash before executing; if the script changed, the run is refused:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
hooks trust <name> # re-pin the current script content
|
|
111
|
+
hooks update # re-register hooks and refresh pins
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Registry server.** `hooks serve` exposes the local store over HTTP — catalog, artifacts, and the published lock:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
hooks serve --port 39428 --api-key "$HASNA_HOOKS_API_KEY"
|
|
118
|
+
# GET /health, GET /api/v1/catalog, GET /api/v1/hooks/:name/:version,
|
|
119
|
+
# PUT /api/v1/hooks (publish, requires the key), GET /api/v1/lock
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Cloudflare registry (opt-in).** Presence of an API URL selects the remote registry; absence means local. There is no mode concept.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
hooks init --cloudflare --api-url https://registry.example.com --api-key <vault-key-name>
|
|
126
|
+
hooks sync # fetch catalog + lock from the API, verify sha256, update the local store
|
|
127
|
+
hooks sync --dry-run # print the plan without changing anything
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`hooks init --cloudflare` stores the API URL and a vault key NAME in `~/.hasna/hooks/config.json` — never the key value. Serve with the key resolved from the vault:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
secrets exec <vault-key-name> --as HASNA_HOOKS_API_KEY -- hooks serve
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Cloudflare provisioning.** `hooks cf deploy` creates the D1 database and R2 bucket via the Cloudflare API, then prints the exact wrangler commands for the worker upload (the worker needs the workerd target, which only wrangler can bundle):
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
export CF_API_TOKEN=... # resolve from the vault, never paste the value
|
|
140
|
+
hooks cf deploy --account-id <id> --dry-run # plan first
|
|
141
|
+
hooks cf deploy --account-id <id>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The worker (`src/cf/worker.ts`) implements the same API routes against D1 + R2, with artifacts at `hook_artifacts/<name>/<version>.json`. See `src/cf/wrangler.toml.example`.
|
|
145
|
+
|
|
82
146
|
## Storage
|
|
83
147
|
|
|
84
148
|
Hooks stores data locally by default in `~/.hasna/hooks/` and uses SQLite
|
|
85
149
|
directly for hook event history. The package owns its database schema and
|
|
86
150
|
migrations; it does not depend on the deprecated shared runtime or its CLI.
|
|
87
|
-
The repo includes its own PostgreSQL migration definitions for optional
|
|
88
|
-
storage
|
|
89
|
-
data.
|
|
151
|
+
The repo includes its own PostgreSQL migration definitions for the optional
|
|
152
|
+
`hooks storage push|pull|sync` commands. Use the `hooks log` commands to inspect
|
|
153
|
+
local hook event data.
|
|
90
154
|
|
|
91
155
|
```bash
|
|
92
156
|
hooks storage status --json
|
|
@@ -96,14 +160,34 @@ hooks storage sync --json
|
|
|
96
160
|
```
|
|
97
161
|
|
|
98
162
|
Configure database storage with `HASNA_HOOKS_DATABASE_URL` or fallback
|
|
99
|
-
`HOOKS_DATABASE_URL`.
|
|
100
|
-
|
|
101
|
-
|
|
163
|
+
`HOOKS_DATABASE_URL`.
|
|
164
|
+
|
|
165
|
+
### Storage backend
|
|
166
|
+
|
|
167
|
+
Hooks storage has one setting with two values: **which data backend**, not where
|
|
168
|
+
anything is deployed.
|
|
169
|
+
|
|
170
|
+
| `HASNA_HOOKS_STORAGE_BACKEND` (fallback `HOOKS_STORAGE_BACKEND`) | meaning |
|
|
171
|
+
| --- | --- |
|
|
172
|
+
| `sqlite` | the on-box SQLite file in `~/.hasna/hooks/` (default) |
|
|
173
|
+
| `postgresql` | the PostgreSQL database named by `HASNA_HOOKS_DATABASE_URL` |
|
|
174
|
+
|
|
175
|
+
Leave it unset and the backend is inferred exactly as before: `postgresql` when a
|
|
176
|
+
database URL is configured, `sqlite` otherwise. An unrecognised value is an
|
|
177
|
+
error, not a silent fall back to SQLite.
|
|
178
|
+
|
|
179
|
+
The former deployment-mode variables `HASNA_HOOKS_STORAGE_MODE` and
|
|
180
|
+
`HOOKS_STORAGE_MODE`, and their `local` / `hybrid` / `remote` / `self-hosted` /
|
|
181
|
+
`cloud` values, are **retired**. They are not read; setting one raises an error
|
|
182
|
+
naming the replacement variable and the backend to use (`local` became `sqlite`,
|
|
183
|
+
everything else became `postgresql`). Deployment location was never a property of
|
|
184
|
+
the data layer, so it is no longer expressed as one.
|
|
102
185
|
|
|
103
186
|
## Runtime model
|
|
104
187
|
|
|
105
|
-
This package is an npm
|
|
106
|
-
|
|
188
|
+
This package is an npm CLI, MCP server, and static dashboard package. Installing
|
|
189
|
+
and running hooks needs nothing deployed anywhere — the SQLite backend is the
|
|
190
|
+
default and requires no server.
|
|
107
191
|
|
|
108
192
|
## Data Directory
|
|
109
193
|
|