avorelo 0.4.0-rc.1 → 0.4.0-rc.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/package.json +1 -1
- package/scripts/lib/hook-apply.js +50 -38
package/package.json
CHANGED
|
@@ -19,12 +19,12 @@ const AVORELO_HOOK_MARKER = "_avorelo_managed";
|
|
|
19
19
|
// The lifecycle-hook commands that Avorelo manages
|
|
20
20
|
// Uses npx to resolve the binary from the project's node_modules
|
|
21
21
|
const AVORELO_LIFECYCLE_COMMANDS = Object.freeze([
|
|
22
|
-
{ event: "SessionStart", command: "npx avorelo lifecycle-hook session-start --json", blocking: false },
|
|
23
|
-
{ event: "UserPromptSubmit", command: "npx avorelo lifecycle-hook user-prompt-submit --json", blocking: false },
|
|
24
|
-
{ event: "PreToolUse", command: "npx avorelo lifecycle-hook pre-tool-use --json", blocking: true },
|
|
25
|
-
{ event: "PostToolUse", command: "npx avorelo lifecycle-hook post-tool-use --json", blocking: false },
|
|
26
|
-
{ event: "Stop", command: "npx avorelo lifecycle-hook stop --json", blocking: true },
|
|
27
|
-
{ event: "SessionEnd", command: "npx avorelo lifecycle-hook session-end --json", blocking: false },
|
|
22
|
+
{ event: "SessionStart", command: "npx avorelo lifecycle-hook session-start --json", blocking: false, matcher: "" },
|
|
23
|
+
{ event: "UserPromptSubmit", command: "npx avorelo lifecycle-hook user-prompt-submit --json", blocking: false, matcher: "" },
|
|
24
|
+
{ event: "PreToolUse", command: "npx avorelo lifecycle-hook pre-tool-use --json", blocking: true, matcher: "" },
|
|
25
|
+
{ event: "PostToolUse", command: "npx avorelo lifecycle-hook post-tool-use --json", blocking: false, matcher: "" },
|
|
26
|
+
{ event: "Stop", command: "npx avorelo lifecycle-hook stop --json", blocking: true, matcher: "" },
|
|
27
|
+
{ event: "SessionEnd", command: "npx avorelo lifecycle-hook session-end --json", blocking: false, matcher: "" },
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
30
|
// Supported host configs
|
|
@@ -110,26 +110,31 @@ function parseExistingConfig(configAbsPath, format) {
|
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
112
|
* Check if a hook entry is Avorelo-managed.
|
|
113
|
-
*
|
|
113
|
+
* Supports both nested format ({matcher, hooks: [...]}) and flat format ({type, command}).
|
|
114
114
|
*/
|
|
115
115
|
function isAvoreloManagedHook(entry) {
|
|
116
116
|
if (!entry || typeof entry !== "object") return false;
|
|
117
|
-
// Check marker field
|
|
118
117
|
if (entry[AVORELO_HOOK_MARKER] === true) return true;
|
|
119
|
-
|
|
118
|
+
if (Array.isArray(entry.hooks)) {
|
|
119
|
+
return entry.hooks.some((h) => h && typeof h.command === "string" && h.command.includes("avorelo lifecycle-hook"));
|
|
120
|
+
}
|
|
120
121
|
const cmd = entry.command || "";
|
|
121
|
-
return
|
|
122
|
+
return cmd.includes("avorelo lifecycle-hook");
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
/**
|
|
125
126
|
* Build the Avorelo hook entries for Claude Code settings.json format.
|
|
126
|
-
*
|
|
127
|
+
* Claude Code v2.1+ expects: {matcher: string, hooks: [{type, command}]}
|
|
127
128
|
*/
|
|
128
129
|
function buildClaudeCodeHookEntries() {
|
|
129
130
|
return AVORELO_LIFECYCLE_COMMANDS.map((lc) => ({
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
matcher: lc.matcher,
|
|
132
|
+
hooks: [
|
|
133
|
+
{
|
|
134
|
+
type: "command",
|
|
135
|
+
command: lc.command,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
133
138
|
[AVORELO_HOOK_MARKER]: true,
|
|
134
139
|
_event: lc.event,
|
|
135
140
|
}));
|
|
@@ -157,7 +162,6 @@ function mergeClaudeCodeConfig(existingData) {
|
|
|
157
162
|
? base.hooks
|
|
158
163
|
: {};
|
|
159
164
|
|
|
160
|
-
// Claude Code settings.json uses nested format: { hooks: { PreToolUse: [...], PostToolUse: [...] } }
|
|
161
165
|
const merged = { ...existingHooks };
|
|
162
166
|
const avoreloEntries = buildClaudeCodeHookEntries();
|
|
163
167
|
|
|
@@ -204,8 +208,9 @@ function removeAvoreloHooks(existingData, format) {
|
|
|
204
208
|
: {};
|
|
205
209
|
const cleaned = {};
|
|
206
210
|
for (const [event, entries] of Object.entries(hooks)) {
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
if (!Array.isArray(entries)) { cleaned[event] = entries; continue; }
|
|
212
|
+
const kept = entries.filter((h) => !isAvoreloManagedHook(h));
|
|
213
|
+
if (kept.length > 0) cleaned[event] = kept;
|
|
209
214
|
}
|
|
210
215
|
return { ...existingData, hooks: cleaned };
|
|
211
216
|
}
|
|
@@ -546,35 +551,41 @@ function validateAppliedHooks(cwd, options = {}) {
|
|
|
546
551
|
continue;
|
|
547
552
|
}
|
|
548
553
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
554
|
+
const hooksByEvent = data.hooks && typeof data.hooks === "object" && !Array.isArray(data.hooks)
|
|
555
|
+
? data.hooks : {};
|
|
556
|
+
let avoreloEventCount = 0;
|
|
557
|
+
const foundEvents = [];
|
|
558
|
+
const allEntries = [];
|
|
559
|
+
|
|
560
|
+
for (const [event, entries] of Object.entries(hooksByEvent)) {
|
|
561
|
+
if (!Array.isArray(entries)) continue;
|
|
562
|
+
for (const entry of entries) {
|
|
563
|
+
allEntries.push({ ...entry, _validationEvent: event });
|
|
564
|
+
if (isAvoreloManagedHook(entry)) {
|
|
565
|
+
avoreloEventCount++;
|
|
566
|
+
foundEvents.push(event);
|
|
556
567
|
}
|
|
557
568
|
}
|
|
558
569
|
}
|
|
559
|
-
|
|
570
|
+
|
|
560
571
|
const expectedCount = AVORELO_LIFECYCLE_COMMANDS.length;
|
|
561
572
|
const missingEvents = AVORELO_LIFECYCLE_COMMANDS
|
|
562
|
-
.filter((lc) => !
|
|
573
|
+
.filter((lc) => !foundEvents.includes(lc.event))
|
|
563
574
|
.map((lc) => lc.event);
|
|
564
575
|
|
|
565
576
|
const duplicates = AVORELO_LIFECYCLE_COMMANDS
|
|
566
|
-
.filter((lc) =>
|
|
577
|
+
.filter((lc) => foundEvents.filter((e) => e === lc.event).length > 1)
|
|
567
578
|
.map((lc) => lc.event);
|
|
568
579
|
|
|
569
580
|
validations.push({
|
|
570
581
|
host: hostKey,
|
|
571
|
-
status:
|
|
582
|
+
status: avoreloEventCount >= expectedCount && missingEvents.length === 0 ? "valid" : "incomplete",
|
|
572
583
|
configPath: hostConf.configPath,
|
|
573
|
-
avoreloHookCount:
|
|
584
|
+
avoreloHookCount: avoreloEventCount,
|
|
574
585
|
expectedCount,
|
|
575
586
|
missingEvents,
|
|
576
587
|
duplicates,
|
|
577
|
-
userHookCount:
|
|
588
|
+
userHookCount: allEntries.length - avoreloEventCount,
|
|
578
589
|
});
|
|
579
590
|
}
|
|
580
591
|
|
|
@@ -788,18 +799,19 @@ function runHookDoctor(cwd, options = {}) {
|
|
|
788
799
|
continue;
|
|
789
800
|
}
|
|
790
801
|
|
|
802
|
+
const hooksByEvent = data.hooks && typeof data.hooks === "object" && !Array.isArray(data.hooks)
|
|
803
|
+
? data.hooks : {};
|
|
804
|
+
const avoreloEvents = [];
|
|
791
805
|
let flatHooks = [];
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (
|
|
797
|
-
for (const entry of entries) flatHooks.push({ ...entry, _event: event });
|
|
798
|
-
}
|
|
806
|
+
for (const [event, entries] of Object.entries(hooksByEvent)) {
|
|
807
|
+
if (!Array.isArray(entries)) continue;
|
|
808
|
+
for (const entry of entries) {
|
|
809
|
+
flatHooks.push({ ...entry, _event: event });
|
|
810
|
+
if (isAvoreloManagedHook(entry)) avoreloEvents.push(event);
|
|
799
811
|
}
|
|
800
812
|
}
|
|
801
813
|
const avoreloHooks = flatHooks.filter(isAvoreloManagedHook);
|
|
802
|
-
const hasMissing = AVORELO_LIFECYCLE_COMMANDS.some((lc) => !
|
|
814
|
+
const hasMissing = AVORELO_LIFECYCLE_COMMANDS.some((lc) => !avoreloEvents.includes(lc.event));
|
|
803
815
|
|
|
804
816
|
if (avoreloHooks.length === 0) {
|
|
805
817
|
checks.push({ id: "hooks_installed", host: hostKey, status: "warn", message: "No Avorelo hooks found in config. Run `hooks apply --yes` to install." });
|