auriga-cli 1.25.0 → 1.27.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 +20 -24
- package/README.zh-CN.md +21 -24
- package/dist/api-types.d.ts +24 -16
- package/dist/apply-handlers.js +29 -26
- package/dist/catalog.d.ts +1 -2
- package/dist/catalog.json +15 -6
- package/dist/cli.d.ts +20 -0
- package/dist/cli.js +169 -48
- package/dist/guide.js +15 -12
- package/dist/help.js +10 -28
- package/dist/plugins.d.ts +9 -0
- package/dist/plugins.js +20 -2
- package/dist/preset.d.ts +38 -0
- package/dist/preset.js +84 -0
- package/dist/scan-catalog.js +2 -6
- package/dist/server.d.ts +7 -4
- package/dist/server.js +18 -7
- package/dist/state.d.ts +1 -6
- package/dist/state.js +0 -104
- package/dist/types.d.ts +1 -1
- package/dist/types.js +0 -1
- package/dist/utils.d.ts +7 -1
- package/package.json +5 -5
- package/dist/hooks.d.ts +0 -236
- package/dist/hooks.js +0 -965
package/dist/hooks.d.ts
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { type InstallOpts } from "./utils.js";
|
|
2
|
-
export interface HookDep {
|
|
3
|
-
name: string;
|
|
4
|
-
via: "brew";
|
|
5
|
-
optional?: boolean;
|
|
6
|
-
}
|
|
7
|
-
export interface HookSettingsEvent {
|
|
8
|
-
event: string;
|
|
9
|
-
/** Tool-name / regex filter; mapped onto the container-level
|
|
10
|
-
* `matcher` field in settings.json. Absent → every tool fires. */
|
|
11
|
-
matcher?: string;
|
|
12
|
-
/** Permission-rule-syntax filter — mapped onto the nested action-level
|
|
13
|
-
* `if` field in settings.json. Format: `<ToolName>(<substring>)`, e.g.
|
|
14
|
-
* `Bash(gh pr create)` — see IF_RE for the exact grammar. Lets the
|
|
15
|
-
* Claude Code runtime skip hook dispatch when the tool input doesn't
|
|
16
|
-
* match, avoiding a Node subprocess spawn per unrelated call.
|
|
17
|
-
* Absent → no registry-level content filter (the hook script runs
|
|
18
|
-
* for every invocation that passed `matcher`). */
|
|
19
|
-
if?: string;
|
|
20
|
-
}
|
|
21
|
-
export interface HookDef {
|
|
22
|
-
name: string;
|
|
23
|
-
description: string;
|
|
24
|
-
runtimePlatforms: string[];
|
|
25
|
-
settingsEvents: HookSettingsEvent[];
|
|
26
|
-
command: string;
|
|
27
|
-
files: string[];
|
|
28
|
-
preserveFiles?: string[];
|
|
29
|
-
deps?: HookDep[];
|
|
30
|
-
marker: string;
|
|
31
|
-
/**
|
|
32
|
-
* Per-hook customization hints rendered in the post-install summary.
|
|
33
|
-
* The literal `{hookDir}` is substituted with the hook's resolved
|
|
34
|
-
* install directory at print time. Empty / omitted → installer falls
|
|
35
|
-
* back to a generic "see <dir>/README.md" pointer.
|
|
36
|
-
*/
|
|
37
|
-
customizeHints?: string[];
|
|
38
|
-
/**
|
|
39
|
-
* Whether the hook is part of the default-on set. `false` makes the
|
|
40
|
-
* hook opt-in: non-interactive `install hooks` with no `--hook` filter
|
|
41
|
-
* skips it, and the interactive checkbox leaves it unchecked. Absent
|
|
42
|
-
* / `true` → installed by default. Used for hooks with intrusive
|
|
43
|
-
* side effects (OS notifications, brew deps, platform constraints)
|
|
44
|
-
* that users probably want to pick up consciously.
|
|
45
|
-
*/
|
|
46
|
-
defaultOn?: boolean;
|
|
47
|
-
}
|
|
48
|
-
export interface HooksConfig {
|
|
49
|
-
hooks: HookDef[];
|
|
50
|
-
}
|
|
51
|
-
export interface SettingsHookAction {
|
|
52
|
-
type: "command";
|
|
53
|
-
command: string;
|
|
54
|
-
_marker?: string;
|
|
55
|
-
/** Per-action permission-rule filter (Claude Code ≥ 2026-04 schema).
|
|
56
|
-
* Format: `<ToolName>(<substring>)`. Older runtimes ignore unknown
|
|
57
|
-
* fields, so emitting this is forward-safe. */
|
|
58
|
-
if?: string;
|
|
59
|
-
}
|
|
60
|
-
export interface SettingsHookGroup {
|
|
61
|
-
matcher?: string;
|
|
62
|
-
hooks: SettingsHookAction[];
|
|
63
|
-
}
|
|
64
|
-
export interface SettingsFile {
|
|
65
|
-
hooks?: Record<string, SettingsHookGroup[]>;
|
|
66
|
-
[key: string]: unknown;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Pure, idempotent settings merge. Deep-clones input, dedupes by two
|
|
70
|
-
* checks in priority order:
|
|
71
|
-
*
|
|
72
|
-
* 1. sentinel `_marker` field — primary key. Survives path drift, lets
|
|
73
|
-
* a future uninstall command find our entries unambiguously.
|
|
74
|
-
* 2. command-string equality — secondary, catches the case where the
|
|
75
|
-
* user (or another tool) already added an equivalent entry by hand
|
|
76
|
-
* and never wrote our marker. Without this fallback we would happily
|
|
77
|
-
* append a duplicate next to it and the hook would fire twice.
|
|
78
|
-
*
|
|
79
|
-
* `options.matcher` writes to the container-level `matcher` (tool-name
|
|
80
|
-
* filter); `options.ifRule` writes to the action-level `if` (permission-
|
|
81
|
-
* rule substring filter, Claude Code ≥ 2026-04). Either or both may be
|
|
82
|
-
* absent.
|
|
83
|
-
*
|
|
84
|
-
* Upgrade path: if an entry with our marker already exists but its
|
|
85
|
-
* matcher / if disagrees with the desired values, we update those two
|
|
86
|
-
* fields in place (preserving everything else — command, sibling
|
|
87
|
-
* actions, the user's other groups — untouched). This is the path for
|
|
88
|
-
* a user who installed an older registry version and re-runs the
|
|
89
|
-
* installer after hooks.json changed. Pure no-op when the existing
|
|
90
|
-
* fields already match.
|
|
91
|
-
*
|
|
92
|
-
* Inputs are defense-in-depth revalidated here against IF_RE + the
|
|
93
|
-
* event-name regex even though registry callers already passed
|
|
94
|
-
* loadHooksConfig, so a direct library caller can't write malformed
|
|
95
|
-
* values into settings.json by bypassing the registry loader.
|
|
96
|
-
*
|
|
97
|
-
* Throws if `settings.hooks[event]` exists but is not an array — that
|
|
98
|
-
* means the user has hand-edited their settings into a shape we do not
|
|
99
|
-
* recognize, and silently replacing it with an empty array would lose
|
|
100
|
-
* data. Callers should catch and surface the error to the user.
|
|
101
|
-
*/
|
|
102
|
-
export declare function addHookToSettings(settings: SettingsFile, event: string, command: string, marker: string, options?: {
|
|
103
|
-
matcher?: string;
|
|
104
|
-
ifRule?: string;
|
|
105
|
-
}): {
|
|
106
|
-
settings: SettingsFile;
|
|
107
|
-
mutated: boolean;
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* Pure inverse of addHookToSettings: removes every action carrying
|
|
111
|
-
* `_marker` from every event in the settings tree. Returns the mutated
|
|
112
|
-
* copy and the count of actions removed. If a group becomes empty after
|
|
113
|
-
* removal, the whole group is dropped; if an event becomes empty, the
|
|
114
|
-
* event key is dropped.
|
|
115
|
-
*/
|
|
116
|
-
export declare function removeHookFromSettings(settings: SettingsFile, marker: string): {
|
|
117
|
-
settings: SettingsFile;
|
|
118
|
-
removed: number;
|
|
119
|
-
};
|
|
120
|
-
type Scope = "project-local" | "project" | "user";
|
|
121
|
-
/**
|
|
122
|
-
* Non-interactive scope map for hooks.
|
|
123
|
-
*
|
|
124
|
-
* Non-interactive surface only knows about two values — `project` (the
|
|
125
|
-
* default) and `user`. `project-local` exists only in the TTY menu; it's
|
|
126
|
-
* a per-developer uncommitted scope and carries enough "did you really
|
|
127
|
-
* mean this?" surface area that we gate it behind an interactive
|
|
128
|
-
* confirmation rather than exposing it as a CLI flag value.
|
|
129
|
-
*
|
|
130
|
-
* Exported so `tests/hooks.test.ts` can lock the contract down as a
|
|
131
|
-
* unit test.
|
|
132
|
-
*/
|
|
133
|
-
export declare function mapNonInteractiveScope(scope: string | undefined): Scope;
|
|
134
|
-
export declare function depBinary(dep: HookDep): string;
|
|
135
|
-
export declare function loadHooksConfig(packageRoot: string): HooksConfig;
|
|
136
|
-
export interface InstallHookResult {
|
|
137
|
-
hook: string;
|
|
138
|
-
written: number;
|
|
139
|
-
preserved: number;
|
|
140
|
-
scope: Scope;
|
|
141
|
-
hookDir: string;
|
|
142
|
-
settingsPath: string;
|
|
143
|
-
settingsMutated: boolean;
|
|
144
|
-
settingsError?: string;
|
|
145
|
-
aborted?: string;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Non-interactive single-hook install. Driven by installHooks (which
|
|
149
|
-
* collects user choices via prompts) and by tools/verify-hooks.mjs (which
|
|
150
|
-
* exercises the install path end-to-end without prompts).
|
|
151
|
-
*
|
|
152
|
-
* Failure ordering matters: deps run first (no state changes), then
|
|
153
|
-
* settings is read AND parsed (still no state changes), and only after
|
|
154
|
-
* parsing succeeds do we touch the filesystem to copy hook files. A
|
|
155
|
-
* malformed settings file therefore aborts cleanly and leaves nothing
|
|
156
|
-
* behind.
|
|
157
|
-
*/
|
|
158
|
-
export declare function installHook(hook: HookDef, scope: Scope, projectBase: string, packageRoot: string): Promise<InstallHookResult>;
|
|
159
|
-
/**
|
|
160
|
-
* Scan all 3 scope settings files for a hook's marker, returning every
|
|
161
|
-
* scope where the marker is currently present and is NOT the scope the
|
|
162
|
-
* caller is about to install into. Used by installHooks to detect
|
|
163
|
-
* cross-scope leftovers from a previous install — which would cause the
|
|
164
|
-
* hook to fire multiple times if not cleaned up.
|
|
165
|
-
*
|
|
166
|
-
* Pure-ish: reads files but does not mutate. Silently skips files that
|
|
167
|
-
* fail to parse — surfacing those errors is the install path's job.
|
|
168
|
-
*/
|
|
169
|
-
export interface StaleScope {
|
|
170
|
-
scope: Scope;
|
|
171
|
-
settingsPath: string;
|
|
172
|
-
count: number;
|
|
173
|
-
}
|
|
174
|
-
export declare function findStaleScopes(hook: HookDef, currentScope: Scope, projectBase: string): StaleScope[];
|
|
175
|
-
/**
|
|
176
|
-
* Remove every action carrying `hook.marker` from the given scope's
|
|
177
|
-
* settings file. Atomic write, snapshot-once .bak. Returns the count of
|
|
178
|
-
* actions removed (0 if nothing matched or file did not exist).
|
|
179
|
-
*/
|
|
180
|
-
export declare function cleanHookFromScope(hook: HookDef, scope: Scope, projectBase: string): {
|
|
181
|
-
removed: number;
|
|
182
|
-
settingsPath: string;
|
|
183
|
-
};
|
|
184
|
-
/**
|
|
185
|
-
* Non-interactive selection resolver for hooks.
|
|
186
|
-
*
|
|
187
|
-
* Diverges from resolvePluginSelection in the no-filter case. Hooks can
|
|
188
|
-
* carry intrusive side effects (OS notifications, brew deps), so the
|
|
189
|
-
* safe default is NOT "install everything". Three cases:
|
|
190
|
-
*
|
|
191
|
-
* - undefined (no --hook passed) → default-on set (filter on defaultOn !== false)
|
|
192
|
-
* - ["*"] (explicit opt-in to everything) → full compatible set
|
|
193
|
-
* - explicit names → exactly those (even if defaultOn is false)
|
|
194
|
-
*/
|
|
195
|
-
export declare function resolveHookSelection(compatible: HookDef[], selected: string[] | undefined): HookDef[];
|
|
196
|
-
/**
|
|
197
|
-
* Given the full registry and the platform-filtered compatible subset,
|
|
198
|
-
* return the names in `selected` that refer to real hooks but aren't
|
|
199
|
-
* available on the current platform. Empty result means the selection
|
|
200
|
-
* is either fully compatible or references unknown hooks (that case is
|
|
201
|
-
* left to the catalog validator — we don't pretend unknown names are
|
|
202
|
-
* platform issues).
|
|
203
|
-
*/
|
|
204
|
-
export declare function findIncompatibleExplicit(all: HookDef[], compatible: HookDef[], selected: string[]): string[];
|
|
205
|
-
export declare function installHooks(packageRoot: string, opts: InstallOpts): Promise<void>;
|
|
206
|
-
/**
|
|
207
|
-
* Uninstall a single hook. Defaults to project scope; explicit
|
|
208
|
-
* `scope:"user"` cleans `~/.claude/...` instead.
|
|
209
|
-
*
|
|
210
|
-
* Project scope (default):
|
|
211
|
-
* - rm `<cwd>/.claude/hooks/<name>/` directory.
|
|
212
|
-
* - Strip the hook's marker from `<cwd>/.claude/settings.json` AND
|
|
213
|
-
* `<cwd>/.claude/settings.local.json` (project + project-local share
|
|
214
|
-
* the on-disk hook dir, so cleaning both settings files keeps users
|
|
215
|
-
* who switched scopes from accumulating dangling registrations).
|
|
216
|
-
*
|
|
217
|
-
* User scope:
|
|
218
|
-
* - rm `~/.claude/hooks/<name>/` directory.
|
|
219
|
-
* - Strip the hook's marker from `~/.claude/settings.json`.
|
|
220
|
-
* - Project files are NOT touched.
|
|
221
|
-
*
|
|
222
|
-
* Marker discovery: tries the live registry at `<cwd>` (or the npx
|
|
223
|
-
* package root if that fails) so we use the same marker the install path
|
|
224
|
-
* stamped in. If the registry can't resolve the hook (renamed / removed
|
|
225
|
-
* upstream), we fall back to a `auriga:<name>` convention — every shipped
|
|
226
|
-
* hook to date follows it, so the fallback is reliable for the common
|
|
227
|
-
* case.
|
|
228
|
-
*
|
|
229
|
-
* Idempotent: missing hook dir / missing settings / absent marker → no-op.
|
|
230
|
-
*/
|
|
231
|
-
export declare function uninstallHook(name: string, opts: {
|
|
232
|
-
cwd: string;
|
|
233
|
-
scope?: "project" | "user";
|
|
234
|
-
onLog?: (line: string) => void;
|
|
235
|
-
}): Promise<void>;
|
|
236
|
-
export {};
|