@proletariat/cli 0.3.102 → 0.3.103
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/dist/lib/orchestrate/engine.d.ts +19 -39
- package/dist/lib/orchestrate/engine.js +51 -215
- package/dist/lib/orchestrate/engine.js.map +1 -1
- package/dist/lib/orchestrate/types.d.ts +3 -11
- package/dist/lib/orchestrate/types.js +1 -2
- package/dist/lib/orchestrate/types.js.map +1 -1
- package/dist/lib/work-lifecycle/hooks/executor.js +2 -0
- package/dist/lib/work-lifecycle/hooks/executor.js.map +1 -1
- package/dist/lib/work-lifecycle/hooks/index.d.ts +5 -3
- package/dist/lib/work-lifecycle/hooks/index.js +3 -2
- package/dist/lib/work-lifecycle/hooks/index.js.map +1 -1
- package/dist/lib/work-lifecycle/hooks/manager.d.ts +93 -8
- package/dist/lib/work-lifecycle/hooks/manager.js +248 -20
- package/dist/lib/work-lifecycle/hooks/manager.js.map +1 -1
- package/dist/lib/work-lifecycle/hooks/storage.d.ts +1 -0
- package/dist/lib/work-lifecycle/hooks/storage.js +28 -6
- package/dist/lib/work-lifecycle/hooks/storage.js.map +1 -1
- package/dist/lib/work-lifecycle/hooks/types.d.ts +37 -0
- package/dist/lib/work-lifecycle/hooks/types.js +2 -0
- package/dist/lib/work-lifecycle/hooks/types.js.map +1 -1
- package/dist/lib/work-lifecycle/index.d.ts +2 -1
- package/dist/lib/work-lifecycle/index.js +1 -1
- package/dist/lib/work-lifecycle/index.js.map +1 -1
- package/oclif.manifest.json +1018 -1018
- package/package.json +1 -1
|
@@ -1,22 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Work Lifecycle Hook Manager
|
|
3
3
|
*
|
|
4
|
+
* The single hook execution system for the entire application.
|
|
4
5
|
* Subscribes to work lifecycle events on the global EventBus and
|
|
5
|
-
* executes matching hook configurations from the database
|
|
6
|
+
* executes matching hook configurations from the database with
|
|
7
|
+
* mode-aware behavior (auto/confirm/notify/off).
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* Used by both the interactive CLI (with default auto mode) and
|
|
10
|
+
* the orchestrate daemon (with full mode/callback support).
|
|
11
|
+
*
|
|
12
|
+
* Hooks are fire-and-forget when triggered via EventBus: execution
|
|
13
|
+
* failures are logged but never block the caller or break the event
|
|
14
|
+
* emission chain.
|
|
9
15
|
*/
|
|
10
16
|
import type Database from 'better-sqlite3';
|
|
17
|
+
import { type HookExecutionResult, type HookActionHandler, type WorkHookConfig } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Options for creating a HookManager.
|
|
20
|
+
*/
|
|
21
|
+
export interface HookManagerOptions {
|
|
22
|
+
/** Database connection */
|
|
23
|
+
db: Database.Database;
|
|
24
|
+
/** Logger function */
|
|
25
|
+
log?: (msg: string) => void;
|
|
26
|
+
/** Callback for confirm-mode hooks (returns true to approve) */
|
|
27
|
+
onConfirm?: (hookName: string, event: string, action: string) => Promise<boolean>;
|
|
28
|
+
/** Callback for notifications (notify-mode hooks) */
|
|
29
|
+
onNotify?: (hookName: string, event: string, action: string, result: HookExecutionResult) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Built-in action handlers (e.g., merge-pr, spawn-agent).
|
|
32
|
+
* When a hook's action resolves to a key in this map, the handler
|
|
33
|
+
* is called instead of shell/webhook/log execution.
|
|
34
|
+
*/
|
|
35
|
+
actionHandlers?: Record<string, HookActionHandler>;
|
|
36
|
+
}
|
|
37
|
+
interface PendingConfirmation {
|
|
38
|
+
hookName: string;
|
|
39
|
+
event: string;
|
|
40
|
+
action: string;
|
|
41
|
+
ctx: Record<string, unknown>;
|
|
42
|
+
config?: Record<string, unknown>;
|
|
43
|
+
}
|
|
11
44
|
/**
|
|
12
45
|
* HookManager loads hook configs from the database and subscribes to
|
|
13
46
|
* the global EventBus. When a hookable event fires, it finds all
|
|
14
|
-
* enabled hooks for that event and executes them.
|
|
47
|
+
* enabled hooks for that event and executes them with mode-aware behavior.
|
|
15
48
|
*/
|
|
16
49
|
export declare class HookManager {
|
|
17
50
|
private unsubscribers;
|
|
18
51
|
private hookStorage;
|
|
19
|
-
|
|
52
|
+
private db;
|
|
53
|
+
private log;
|
|
54
|
+
private onConfirm?;
|
|
55
|
+
private onNotify?;
|
|
56
|
+
private actionHandlers;
|
|
57
|
+
private _pendingConfirmations;
|
|
58
|
+
constructor(options: HookManagerOptions);
|
|
20
59
|
/**
|
|
21
60
|
* Start listening for hookable events on the global EventBus.
|
|
22
61
|
* For each event, looks up enabled hooks and executes them.
|
|
@@ -27,17 +66,63 @@ export declare class HookManager {
|
|
|
27
66
|
*/
|
|
28
67
|
stop(): void;
|
|
29
68
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
69
|
+
* Fire an event explicitly (used by orchestrate daemon and `prlt hook fire`).
|
|
70
|
+
* Returns the execution results for all matching hooks.
|
|
71
|
+
*/
|
|
72
|
+
fireEvent(event: string, eventData: Record<string, unknown>): Promise<HookExecutionResult[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Get pending confirmations for hooks in confirm mode.
|
|
75
|
+
*/
|
|
76
|
+
getPendingConfirmations(): PendingConfirmation[];
|
|
77
|
+
/**
|
|
78
|
+
* Approve a pending confirmation and execute it.
|
|
79
|
+
*/
|
|
80
|
+
approveConfirmation(index: number): Promise<HookExecutionResult | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Deny a pending confirmation.
|
|
83
|
+
*/
|
|
84
|
+
denyConfirmation(index: number): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Build a context object from raw event data.
|
|
87
|
+
* Normalizes common field names for built-in action handlers.
|
|
88
|
+
*
|
|
89
|
+
* Public so it can be tested in isolation.
|
|
90
|
+
*/
|
|
91
|
+
static buildContext(eventName: string, data: Record<string, unknown>): Record<string, unknown>;
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the action name from a hook config and a set of known action handlers.
|
|
94
|
+
*
|
|
95
|
+
* - If the action_value contains `--action <name>`, extracts the name
|
|
96
|
+
* - If the action_value is a known built-in action, uses it directly
|
|
97
|
+
* - Otherwise uses the raw action_value (shell command)
|
|
98
|
+
*
|
|
99
|
+
* Public so it can be tested in isolation.
|
|
100
|
+
*/
|
|
101
|
+
static resolveActionName(hook: WorkHookConfig, knownActions?: Record<string, unknown>): string;
|
|
102
|
+
/**
|
|
103
|
+
* Handle an event by finding and executing all matching enabled hooks.
|
|
104
|
+
* Supports mode-aware execution: auto, confirm, notify, off.
|
|
32
105
|
*/
|
|
33
106
|
private handleEvent;
|
|
107
|
+
/**
|
|
108
|
+
* Execute a hook action — either via a built-in handler or the standard executor.
|
|
109
|
+
*/
|
|
110
|
+
private executeHookAction;
|
|
111
|
+
/**
|
|
112
|
+
* Execute an action by name (used for approved confirmations).
|
|
113
|
+
*/
|
|
114
|
+
private executeActionByName;
|
|
34
115
|
}
|
|
35
116
|
/**
|
|
36
117
|
* Initialize and start the hook manager.
|
|
37
118
|
* Safe to call multiple times — subsequent calls are no-ops.
|
|
119
|
+
*
|
|
120
|
+
* When called with just a db (interactive CLI), hooks default to auto mode.
|
|
121
|
+
* Pass additional options for mode-aware execution (orchestrate daemon).
|
|
38
122
|
*/
|
|
39
|
-
export declare function initHookManager(db: Database.Database): HookManager;
|
|
123
|
+
export declare function initHookManager(db: Database.Database, options?: Omit<HookManagerOptions, 'db'>): HookManager;
|
|
40
124
|
/**
|
|
41
125
|
* Stop the hook manager (primarily for testing).
|
|
42
126
|
*/
|
|
43
127
|
export declare function stopHookManager(): void;
|
|
128
|
+
export {};
|
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Work Lifecycle Hook Manager
|
|
3
3
|
*
|
|
4
|
+
* The single hook execution system for the entire application.
|
|
4
5
|
* Subscribes to work lifecycle events on the global EventBus and
|
|
5
|
-
* executes matching hook configurations from the database
|
|
6
|
+
* executes matching hook configurations from the database with
|
|
7
|
+
* mode-aware behavior (auto/confirm/notify/off).
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* Used by both the interactive CLI (with default auto mode) and
|
|
10
|
+
* the orchestrate daemon (with full mode/callback support).
|
|
11
|
+
*
|
|
12
|
+
* Hooks are fire-and-forget when triggered via EventBus: execution
|
|
13
|
+
* failures are logged but never block the caller or break the event
|
|
14
|
+
* emission chain.
|
|
9
15
|
*/
|
|
16
|
+
import { execSync } from 'node:child_process';
|
|
10
17
|
import { getEventBus } from '../../events/event-bus.js';
|
|
11
18
|
import { WorkHookStorage } from './storage.js';
|
|
12
19
|
import { executeHook } from './executor.js';
|
|
13
|
-
import { HOOKABLE_EVENTS } from './types.js';
|
|
20
|
+
import { HOOKABLE_EVENTS, } from './types.js';
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Manager
|
|
23
|
+
// =============================================================================
|
|
14
24
|
/**
|
|
15
25
|
* HookManager loads hook configs from the database and subscribes to
|
|
16
26
|
* the global EventBus. When a hookable event fires, it finds all
|
|
17
|
-
* enabled hooks for that event and executes them.
|
|
27
|
+
* enabled hooks for that event and executes them with mode-aware behavior.
|
|
18
28
|
*/
|
|
19
29
|
export class HookManager {
|
|
20
30
|
unsubscribers = [];
|
|
21
31
|
hookStorage;
|
|
22
|
-
|
|
23
|
-
|
|
32
|
+
db;
|
|
33
|
+
log;
|
|
34
|
+
onConfirm;
|
|
35
|
+
onNotify;
|
|
36
|
+
actionHandlers;
|
|
37
|
+
_pendingConfirmations = [];
|
|
38
|
+
constructor(options) {
|
|
39
|
+
this.db = options.db;
|
|
40
|
+
this.hookStorage = new WorkHookStorage(options.db);
|
|
41
|
+
this.log = options.log ?? (() => { });
|
|
42
|
+
this.onConfirm = options.onConfirm;
|
|
43
|
+
this.onNotify = options.onNotify;
|
|
44
|
+
this.actionHandlers = options.actionHandlers ?? {};
|
|
24
45
|
}
|
|
25
46
|
/**
|
|
26
47
|
* Start listening for hookable events on the global EventBus.
|
|
@@ -30,7 +51,7 @@ export class HookManager {
|
|
|
30
51
|
const bus = getEventBus();
|
|
31
52
|
for (const eventName of HOOKABLE_EVENTS) {
|
|
32
53
|
this.unsubscribers.push(bus.on(eventName, (payload) => {
|
|
33
|
-
this.handleEvent(eventName, payload);
|
|
54
|
+
void this.handleEvent(eventName, payload);
|
|
34
55
|
}));
|
|
35
56
|
}
|
|
36
57
|
}
|
|
@@ -42,27 +63,231 @@ export class HookManager {
|
|
|
42
63
|
unsub();
|
|
43
64
|
}
|
|
44
65
|
this.unsubscribers = [];
|
|
66
|
+
this._pendingConfirmations = [];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Fire an event explicitly (used by orchestrate daemon and `prlt hook fire`).
|
|
70
|
+
* Returns the execution results for all matching hooks.
|
|
71
|
+
*/
|
|
72
|
+
async fireEvent(event, eventData) {
|
|
73
|
+
return this.handleEvent(event, eventData);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get pending confirmations for hooks in confirm mode.
|
|
77
|
+
*/
|
|
78
|
+
getPendingConfirmations() {
|
|
79
|
+
return [...this._pendingConfirmations];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Approve a pending confirmation and execute it.
|
|
83
|
+
*/
|
|
84
|
+
async approveConfirmation(index) {
|
|
85
|
+
if (index < 0 || index >= this._pendingConfirmations.length)
|
|
86
|
+
return null;
|
|
87
|
+
const pending = this._pendingConfirmations.splice(index, 1)[0];
|
|
88
|
+
const result = this.executeActionByName(pending.action, pending.ctx, pending.config);
|
|
89
|
+
this.log(`[hooks] Approved: ${pending.hookName} → ${pending.action} (${result.success ? 'success' : 'failed'})`);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Deny a pending confirmation.
|
|
94
|
+
*/
|
|
95
|
+
denyConfirmation(index) {
|
|
96
|
+
if (index < 0 || index >= this._pendingConfirmations.length)
|
|
97
|
+
return false;
|
|
98
|
+
const pending = this._pendingConfirmations.splice(index, 1)[0];
|
|
99
|
+
this.log(`[hooks] Denied: ${pending.hookName} → ${pending.action}`);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
// ===========================================================================
|
|
103
|
+
// Testable Utilities (public for PRLT-1223 test suite)
|
|
104
|
+
// ===========================================================================
|
|
105
|
+
/**
|
|
106
|
+
* Build a context object from raw event data.
|
|
107
|
+
* Normalizes common field names for built-in action handlers.
|
|
108
|
+
*
|
|
109
|
+
* Public so it can be tested in isolation.
|
|
110
|
+
*/
|
|
111
|
+
static buildContext(eventName, data) {
|
|
112
|
+
return {
|
|
113
|
+
event: eventName,
|
|
114
|
+
ticket: (data.ticketId ?? data.workItemId ?? data.ticket),
|
|
115
|
+
pr: (data.prNumber ?? data.pr),
|
|
116
|
+
branch: data.branch,
|
|
117
|
+
agent: (data.agentName ?? data.agent ?? data.sessionId),
|
|
118
|
+
container: data.containerId,
|
|
119
|
+
executionId: data.executionId,
|
|
120
|
+
prUrl: data.prUrl,
|
|
121
|
+
projectId: data.projectId,
|
|
122
|
+
...data,
|
|
123
|
+
};
|
|
45
124
|
}
|
|
46
125
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
126
|
+
* Resolve the action name from a hook config and a set of known action handlers.
|
|
127
|
+
*
|
|
128
|
+
* - If the action_value contains `--action <name>`, extracts the name
|
|
129
|
+
* - If the action_value is a known built-in action, uses it directly
|
|
130
|
+
* - Otherwise uses the raw action_value (shell command)
|
|
131
|
+
*
|
|
132
|
+
* Public so it can be tested in isolation.
|
|
49
133
|
*/
|
|
50
|
-
|
|
134
|
+
static resolveActionName(hook, knownActions = {}) {
|
|
135
|
+
// If the action_value contains --action, extract the action name
|
|
136
|
+
const actionMatch = hook.actionValue.match(/--action\s+(\S+)/);
|
|
137
|
+
if (actionMatch)
|
|
138
|
+
return actionMatch[1];
|
|
139
|
+
// If it's a known built-in action name directly
|
|
140
|
+
if (knownActions[hook.actionValue])
|
|
141
|
+
return hook.actionValue;
|
|
142
|
+
// Otherwise it's a raw shell command — use the action_value as-is
|
|
143
|
+
return hook.actionValue;
|
|
144
|
+
}
|
|
145
|
+
// ===========================================================================
|
|
146
|
+
// Private
|
|
147
|
+
// ===========================================================================
|
|
148
|
+
/**
|
|
149
|
+
* Handle an event by finding and executing all matching enabled hooks.
|
|
150
|
+
* Supports mode-aware execution: auto, confirm, notify, off.
|
|
151
|
+
*/
|
|
152
|
+
async handleEvent(eventName, eventData) {
|
|
153
|
+
const results = [];
|
|
51
154
|
try {
|
|
52
155
|
const hooks = this.hookStorage.list({ event: eventName, enabled: true });
|
|
53
156
|
if (hooks.length === 0)
|
|
54
|
-
return;
|
|
157
|
+
return results;
|
|
158
|
+
// Build context from the payload
|
|
159
|
+
const ctx = HookManager.buildContext(eventName, eventData);
|
|
55
160
|
for (const hook of hooks) {
|
|
56
|
-
|
|
57
|
-
|
|
161
|
+
const mode = hook.mode || 'auto';
|
|
162
|
+
const actionName = HookManager.resolveActionName(hook, this.actionHandlers);
|
|
163
|
+
// --- off: skip silently ---
|
|
164
|
+
if (mode === 'off') {
|
|
165
|
+
results.push({
|
|
166
|
+
hookId: hook.id,
|
|
167
|
+
hookName: hook.name,
|
|
168
|
+
action: actionName,
|
|
169
|
+
success: true,
|
|
170
|
+
durationMs: 0,
|
|
171
|
+
skipped: true,
|
|
172
|
+
});
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
// --- confirm: require approval ---
|
|
176
|
+
if (mode === 'confirm') {
|
|
177
|
+
if (this.onConfirm) {
|
|
178
|
+
const approved = await this.onConfirm(hook.name, eventName, actionName);
|
|
179
|
+
if (!approved) {
|
|
180
|
+
this.log(`[hooks] Skipped (not confirmed): ${hook.name} → ${actionName}`);
|
|
181
|
+
results.push({
|
|
182
|
+
hookId: hook.id,
|
|
183
|
+
hookName: hook.name,
|
|
184
|
+
action: actionName,
|
|
185
|
+
success: true,
|
|
186
|
+
durationMs: 0,
|
|
187
|
+
skipped: true,
|
|
188
|
+
});
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
// Approved — fall through to execution
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
// No confirm handler — queue for later approval
|
|
195
|
+
this._pendingConfirmations.push({
|
|
196
|
+
hookName: hook.name,
|
|
197
|
+
event: eventName,
|
|
198
|
+
action: actionName,
|
|
199
|
+
ctx,
|
|
200
|
+
config: hook.config ?? undefined,
|
|
201
|
+
});
|
|
202
|
+
this.log(`[hooks] Queued for confirmation: ${hook.name} → ${actionName}`);
|
|
203
|
+
results.push({
|
|
204
|
+
hookId: hook.id,
|
|
205
|
+
hookName: hook.name,
|
|
206
|
+
action: actionName,
|
|
207
|
+
success: true,
|
|
208
|
+
durationMs: 0,
|
|
209
|
+
awaitingConfirmation: true,
|
|
210
|
+
});
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
58
213
|
}
|
|
59
|
-
|
|
60
|
-
|
|
214
|
+
// --- auto / notify / confirmed: execute ---
|
|
215
|
+
const result = this.executeHookAction(hook, eventName, eventData, ctx);
|
|
216
|
+
results.push(result);
|
|
217
|
+
this.log(`[hooks] ${hook.name} → ${actionName}: ${result.success ? 'success' : `failed: ${result.error}`} (${result.durationMs}ms)`);
|
|
218
|
+
// For notify mode, also fire the notification callback
|
|
219
|
+
if (mode === 'notify' && this.onNotify) {
|
|
220
|
+
this.onNotify(hook.name, eventName, actionName, result);
|
|
61
221
|
}
|
|
62
222
|
}
|
|
63
223
|
}
|
|
64
|
-
catch {
|
|
65
|
-
|
|
224
|
+
catch (err) {
|
|
225
|
+
this.log(`[hooks] Error handling event ${eventName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
226
|
+
}
|
|
227
|
+
return results;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Execute a hook action — either via a built-in handler or the standard executor.
|
|
231
|
+
*/
|
|
232
|
+
executeHookAction(hook, eventName, eventData, ctx) {
|
|
233
|
+
const actionName = HookManager.resolveActionName(hook, this.actionHandlers);
|
|
234
|
+
// Try built-in action handler first
|
|
235
|
+
if (this.actionHandlers[actionName]) {
|
|
236
|
+
const handlerResult = this.actionHandlers[actionName](ctx, hook.config ?? undefined);
|
|
237
|
+
return {
|
|
238
|
+
hookId: hook.id,
|
|
239
|
+
hookName: hook.name,
|
|
240
|
+
action: handlerResult.action,
|
|
241
|
+
success: handlerResult.success,
|
|
242
|
+
error: handlerResult.error,
|
|
243
|
+
durationMs: handlerResult.durationMs,
|
|
244
|
+
skipped: handlerResult.skipped,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// For shell/webhook/log hooks, use the standard executor
|
|
248
|
+
const result = executeHook(hook, eventName, eventData);
|
|
249
|
+
return {
|
|
250
|
+
...result,
|
|
251
|
+
action: actionName,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Execute an action by name (used for approved confirmations).
|
|
256
|
+
*/
|
|
257
|
+
executeActionByName(actionName, ctx, config) {
|
|
258
|
+
// Try built-in action handler first
|
|
259
|
+
if (this.actionHandlers[actionName]) {
|
|
260
|
+
const handlerResult = this.actionHandlers[actionName](ctx, config);
|
|
261
|
+
return {
|
|
262
|
+
hookId: '',
|
|
263
|
+
hookName: '',
|
|
264
|
+
action: handlerResult.action,
|
|
265
|
+
success: handlerResult.success,
|
|
266
|
+
error: handlerResult.error,
|
|
267
|
+
durationMs: handlerResult.durationMs,
|
|
268
|
+
skipped: handlerResult.skipped,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// Fallback to shell execution
|
|
272
|
+
const start = Date.now();
|
|
273
|
+
try {
|
|
274
|
+
const env = {
|
|
275
|
+
...process.env,
|
|
276
|
+
PRLT_HOOK_EVENT: ctx.event ?? '',
|
|
277
|
+
PRLT_HOOK_TICKET: ctx.ticket ?? '',
|
|
278
|
+
PRLT_HOOK_PR: ctx.pr ? String(ctx.pr) : '',
|
|
279
|
+
PRLT_HOOK_BRANCH: ctx.branch ?? '',
|
|
280
|
+
PRLT_HOOK_AGENT: ctx.agent ?? '',
|
|
281
|
+
};
|
|
282
|
+
execSync(actionName, { env, timeout: 30_000, stdio: 'pipe' });
|
|
283
|
+
return { hookId: '', hookName: '', action: actionName, success: true, durationMs: Date.now() - start };
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
return {
|
|
287
|
+
hookId: '', hookName: '', action: actionName, success: false,
|
|
288
|
+
error: err instanceof Error ? err.message : String(err),
|
|
289
|
+
durationMs: Date.now() - start,
|
|
290
|
+
};
|
|
66
291
|
}
|
|
67
292
|
}
|
|
68
293
|
}
|
|
@@ -73,10 +298,13 @@ let _manager;
|
|
|
73
298
|
/**
|
|
74
299
|
* Initialize and start the hook manager.
|
|
75
300
|
* Safe to call multiple times — subsequent calls are no-ops.
|
|
301
|
+
*
|
|
302
|
+
* When called with just a db (interactive CLI), hooks default to auto mode.
|
|
303
|
+
* Pass additional options for mode-aware execution (orchestrate daemon).
|
|
76
304
|
*/
|
|
77
|
-
export function initHookManager(db) {
|
|
305
|
+
export function initHookManager(db, options) {
|
|
78
306
|
if (!_manager) {
|
|
79
|
-
_manager = new HookManager(db);
|
|
307
|
+
_manager = new HookManager({ db, ...options });
|
|
80
308
|
_manager.start();
|
|
81
309
|
}
|
|
82
310
|
return _manager;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../src/lib/work-lifecycle/hooks/manager.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../src/lib/work-lifecycle/hooks/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ export declare class WorkHookStorage {
|
|
|
24
24
|
constructor(db: Database.Database);
|
|
25
25
|
/**
|
|
26
26
|
* List all hooks, optionally filtered by event name or enabled status.
|
|
27
|
+
* Returns hooks ordered by priority (ascending), then creation time.
|
|
27
28
|
*/
|
|
28
29
|
list(options?: {
|
|
29
30
|
event?: HookableEvent;
|
|
@@ -36,6 +36,15 @@ export function ensureHooksTable(db) {
|
|
|
36
36
|
* Convert a database row to a WorkHookConfig.
|
|
37
37
|
*/
|
|
38
38
|
function rowToConfig(row) {
|
|
39
|
+
let config = null;
|
|
40
|
+
if (row.config) {
|
|
41
|
+
try {
|
|
42
|
+
config = JSON.parse(row.config);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Invalid JSON — ignore
|
|
46
|
+
}
|
|
47
|
+
}
|
|
39
48
|
return {
|
|
40
49
|
id: row.id,
|
|
41
50
|
name: row.name,
|
|
@@ -45,6 +54,9 @@ function rowToConfig(row) {
|
|
|
45
54
|
enabled: row.enabled === 1,
|
|
46
55
|
description: row.description,
|
|
47
56
|
createdAt: row.created_at,
|
|
57
|
+
mode: row.mode || 'auto',
|
|
58
|
+
priority: row.priority ?? 0,
|
|
59
|
+
config,
|
|
48
60
|
};
|
|
49
61
|
}
|
|
50
62
|
/**
|
|
@@ -58,21 +70,31 @@ export class WorkHookStorage {
|
|
|
58
70
|
}
|
|
59
71
|
/**
|
|
60
72
|
* List all hooks, optionally filtered by event name or enabled status.
|
|
73
|
+
* Returns hooks ordered by priority (ascending), then creation time.
|
|
61
74
|
*/
|
|
62
75
|
list(options) {
|
|
63
|
-
let sql = `SELECT * FROM ${HOOKS_TABLE} WHERE 1=1`;
|
|
64
76
|
const params = [];
|
|
77
|
+
let where = ' WHERE 1=1';
|
|
65
78
|
if (options?.event) {
|
|
66
|
-
|
|
79
|
+
where += ' AND event = ?';
|
|
67
80
|
params.push(options.event);
|
|
68
81
|
}
|
|
69
82
|
if (options?.enabled !== undefined) {
|
|
70
|
-
|
|
83
|
+
where += ' AND enabled = ?';
|
|
71
84
|
params.push(options.enabled ? 1 : 0);
|
|
72
85
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
// Try extended query with mode/priority/config columns first
|
|
87
|
+
try {
|
|
88
|
+
const sql = `SELECT id, name, event, action_type, action_value, enabled, description, created_at, mode, priority, config FROM ${HOOKS_TABLE}${where} ORDER BY priority ASC, created_at ASC`;
|
|
89
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
90
|
+
return rows.map(rowToConfig);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Fallback without mode/priority/config (pre-migration)
|
|
94
|
+
const sql = `SELECT id, name, event, action_type, action_value, enabled, description, created_at FROM ${HOOKS_TABLE}${where} ORDER BY created_at ASC`;
|
|
95
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
96
|
+
return rows.map(rowToConfig);
|
|
97
|
+
}
|
|
76
98
|
}
|
|
77
99
|
/**
|
|
78
100
|
* Get a single hook by ID.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/lib/work-lifecycle/hooks/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAIxC,iCAAiC;AACjC,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAA;AAE3C,qCAAqC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG;+BACH,WAAW;;;;;;;;;;CAUzC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;2DAC0B,WAAW;6DACT,WAAW;CACvE,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAqB;IACpD,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAC3B,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;AAC5B,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,GAAgB;IACnC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,KAAK,EAAE,GAAG,CAAC,KAAsB;QACjC,UAAU,EAAE,GAAG,CAAC,WAA6B;QAC7C,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,CAAC;QAC1B,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,SAAS,EAAE,GAAG,CAAC,UAAU;
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/lib/work-lifecycle/hooks/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,17 @@ export declare const HOOKABLE_EVENTS: HookableEvent[];
|
|
|
22
22
|
* - log: Write a message to stdout (useful for notifications/debugging)
|
|
23
23
|
*/
|
|
24
24
|
export type HookActionType = 'shell' | 'webhook' | 'log';
|
|
25
|
+
/**
|
|
26
|
+
* Automation mode for a hook.
|
|
27
|
+
*
|
|
28
|
+
* - auto: fires immediately, no human needed
|
|
29
|
+
* - confirm: pauses, waits for approval before executing
|
|
30
|
+
* - notify: fires immediately but also sends a notification
|
|
31
|
+
* - off: disabled, skipped silently
|
|
32
|
+
*/
|
|
33
|
+
export type HookMode = 'auto' | 'confirm' | 'notify' | 'off';
|
|
34
|
+
/** All valid hook modes. */
|
|
35
|
+
export declare const HOOK_MODES: HookMode[];
|
|
25
36
|
/**
|
|
26
37
|
* Persisted hook configuration stored in the database.
|
|
27
38
|
*/
|
|
@@ -42,6 +53,12 @@ export interface WorkHookConfig {
|
|
|
42
53
|
description: string | null;
|
|
43
54
|
/** When the hook was created */
|
|
44
55
|
createdAt: string;
|
|
56
|
+
/** Automation mode (auto/confirm/notify/off) */
|
|
57
|
+
mode: HookMode;
|
|
58
|
+
/** Execution priority (lower = higher priority) */
|
|
59
|
+
priority: number;
|
|
60
|
+
/** Optional JSON config for built-in actions */
|
|
61
|
+
config: Record<string, unknown> | null;
|
|
45
62
|
}
|
|
46
63
|
/**
|
|
47
64
|
* Row shape from the database (snake_case columns).
|
|
@@ -55,15 +72,35 @@ export interface WorkHookRow {
|
|
|
55
72
|
enabled: number;
|
|
56
73
|
description: string | null;
|
|
57
74
|
created_at: string;
|
|
75
|
+
mode: string | null;
|
|
76
|
+
priority: number | null;
|
|
77
|
+
config: string | null;
|
|
58
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Handler function for built-in actions injected into HookManager.
|
|
81
|
+
* Receives event context and optional per-hook config, returns an execution result.
|
|
82
|
+
*/
|
|
83
|
+
export type HookActionHandler = (ctx: Record<string, unknown>, config?: Record<string, unknown>) => {
|
|
84
|
+
action: string;
|
|
85
|
+
success: boolean;
|
|
86
|
+
error?: string;
|
|
87
|
+
durationMs: number;
|
|
88
|
+
skipped?: boolean;
|
|
89
|
+
};
|
|
59
90
|
/**
|
|
60
91
|
* Result of executing a single hook.
|
|
61
92
|
*/
|
|
62
93
|
export interface HookExecutionResult {
|
|
63
94
|
hookId: string;
|
|
64
95
|
hookName: string;
|
|
96
|
+
/** The resolved action name (built-in action or raw command) */
|
|
97
|
+
action: string;
|
|
65
98
|
success: boolean;
|
|
66
99
|
error?: string;
|
|
67
100
|
/** Duration in ms */
|
|
68
101
|
durationMs: number;
|
|
102
|
+
/** True when hook was skipped (mode=off or confirm denied) */
|
|
103
|
+
skipped?: boolean;
|
|
104
|
+
/** True when hook is queued for confirmation */
|
|
105
|
+
awaitingConfirmation?: boolean;
|
|
69
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/work-lifecycle/hooks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+BH,+CAA+C;AAC/C,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C,cAAc;IACd,qBAAqB;IACrB,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,aAAa;IACb,cAAc;IACd,cAAc;IACd,cAAc;IACd,mBAAmB;IACnB,iBAAiB;IACjB,kBAAkB;IAClB,eAAe;IACf,oBAAoB;IACpB,eAAe;IACf,sBAAsB;CACvB,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/work-lifecycle/hooks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+BH,+CAA+C;AAC/C,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C,cAAc;IACd,qBAAqB;IACrB,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,aAAa;IACb,cAAc;IACd,cAAc;IACd,cAAc;IACd,mBAAmB;IACnB,iBAAiB;IACjB,kBAAkB;IAClB,eAAe;IACf,oBAAoB;IACpB,eAAe;IACf,sBAAsB;CACvB,CAAA;AAqBD,4BAA4B;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAe,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA"}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export type { WorkEventSource, WorkStartedEvent, WorkStatusChangedEvent, WorkPRCreatedEvent, WorkCompletedEvent, } from './events.js';
|
|
9
9
|
export { WorkLifecycleAdapter, initWorkLifecycleAdapter, stopWorkLifecycleAdapter, } from './adapter.js';
|
|
10
|
-
export { initHookManager, stopHookManager, } from './hooks/index.js';
|
|
10
|
+
export { initHookManager, stopHookManager, HookManager, } from './hooks/index.js';
|
|
11
|
+
export type { HookManagerOptions } from './hooks/index.js';
|
|
11
12
|
export { handlePostExecutionTransition, type PostExecutionContext, type PostExecutionResult, } from './post-execution.js';
|
|
12
13
|
export { validateCommits, tryValidateCommits, type CommitValidationResult, } from '../execution/commit-validation.js';
|
|
13
14
|
export { WorkflowRuleEvaluator, initWorkflowRuleEvaluator, stopWorkflowRuleEvaluator, } from './rule-evaluator.js';
|