@planu/cli 0.97.0 → 0.97.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.
- package/dist/tools/start-hooks/configure.d.ts +4 -0
- package/dist/tools/start-hooks/configure.d.ts.map +1 -0
- package/dist/tools/start-hooks/configure.js +122 -0
- package/dist/tools/start-hooks/configure.js.map +1 -0
- package/dist/tools/start-hooks/engine.d.ts +13 -0
- package/dist/tools/start-hooks/engine.d.ts.map +1 -0
- package/dist/tools/start-hooks/engine.js +314 -0
- package/dist/tools/start-hooks/engine.js.map +1 -0
- package/dist/tools/start-hooks.d.ts +2 -23
- package/dist/tools/start-hooks.d.ts.map +1 -1
- package/dist/tools/start-hooks.js +4 -516
- package/dist/tools/start-hooks.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../src/tools/start-hooks/configure.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CA6CzF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// tools/start-hooks/configure.ts — handleConfigureHooks + plan-mode integration + template apply.
|
|
2
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { generateHookTemplate, mergeHookConfig } from '../../engine/hooks/hook-templates.js';
|
|
5
|
+
import { buildPlanModeHookScripts } from '../../engine/hooks/plan-mode-scripts.js';
|
|
6
|
+
import { ConfigLoader } from '../../engine/hooks/config-loader.js';
|
|
7
|
+
import { getConfigLoaderInstance, getEngineInstance } from './engine.js';
|
|
8
|
+
export async function handleConfigureHooks(args) {
|
|
9
|
+
if (args.action === 'enable-plan-mode-integration') {
|
|
10
|
+
return enablePlanModeIntegration(args.projectPath);
|
|
11
|
+
}
|
|
12
|
+
if (args.template) {
|
|
13
|
+
return applyHookTemplate(args);
|
|
14
|
+
}
|
|
15
|
+
const configLoader = getConfigLoaderInstance();
|
|
16
|
+
if (!configLoader) {
|
|
17
|
+
const loader = new ConfigLoader(args.projectPath);
|
|
18
|
+
const config = await loader.load();
|
|
19
|
+
loader.close();
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: 'text',
|
|
24
|
+
text: JSON.stringify({ message: 'Hook engine not running. Current config:', config }, null, 2),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const config = await configLoader.load();
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
{
|
|
33
|
+
type: 'text',
|
|
34
|
+
text: JSON.stringify({
|
|
35
|
+
message: 'Configuration reloaded',
|
|
36
|
+
config,
|
|
37
|
+
engineRunning: getEngineInstance()?.status().running ?? false,
|
|
38
|
+
}, null, 2),
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async function enablePlanModeIntegration(projectPath) {
|
|
44
|
+
const hooksDir = join(projectPath, '.claude', 'hooks');
|
|
45
|
+
await mkdir(hooksDir, { recursive: true });
|
|
46
|
+
const scripts = buildPlanModeHookScripts();
|
|
47
|
+
const preHookPath = join(hooksDir, 'planu-pre-plan.sh');
|
|
48
|
+
const postHookPath = join(hooksDir, 'planu-post-plan.sh');
|
|
49
|
+
await writeFile(preHookPath, scripts.preScript, { mode: 0o755 });
|
|
50
|
+
await writeFile(postHookPath, scripts.postScript, { mode: 0o755 });
|
|
51
|
+
const settingsPath = join(projectPath, '.claude', 'settings.json');
|
|
52
|
+
let existing = {};
|
|
53
|
+
try {
|
|
54
|
+
const raw = await readFile(settingsPath, 'utf-8');
|
|
55
|
+
existing = JSON.parse(raw);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// File doesn't exist yet — start from empty
|
|
59
|
+
}
|
|
60
|
+
const preEntry = {
|
|
61
|
+
matcher: 'Task',
|
|
62
|
+
hooks: [{ type: 'command', command: `bash "${preHookPath}"` }],
|
|
63
|
+
};
|
|
64
|
+
const postEntry = {
|
|
65
|
+
matcher: 'exit_plan_mode',
|
|
66
|
+
hooks: [{ type: 'command', command: `bash "${postHookPath}"` }],
|
|
67
|
+
};
|
|
68
|
+
const existingHooks = (existing.hooks ?? {});
|
|
69
|
+
const merged = {
|
|
70
|
+
...existing,
|
|
71
|
+
hooks: {
|
|
72
|
+
...existingHooks,
|
|
73
|
+
PreToolUse: [...(existingHooks.PreToolUse ?? []), preEntry],
|
|
74
|
+
PostToolUse: [...(existingHooks.PostToolUse ?? []), postEntry],
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
78
|
+
const result = {
|
|
79
|
+
action: 'enable-plan-mode-integration',
|
|
80
|
+
preHookPath,
|
|
81
|
+
postHookPath,
|
|
82
|
+
settingsPath,
|
|
83
|
+
message: 'Plan Mode integration enabled. Planu context will be injected automatically when Claude enters Plan Mode.',
|
|
84
|
+
};
|
|
85
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
86
|
+
}
|
|
87
|
+
async function applyHookTemplate(args) {
|
|
88
|
+
/* c8 ignore next 3 */
|
|
89
|
+
if (!args.template) {
|
|
90
|
+
return { content: [{ type: 'text', text: 'template is required' }], isError: true };
|
|
91
|
+
}
|
|
92
|
+
const generated = generateHookTemplate({
|
|
93
|
+
template: args.template,
|
|
94
|
+
notificationMatcher: args.notificationMatcher,
|
|
95
|
+
});
|
|
96
|
+
const settingsPath = join(args.projectPath, '.claude', 'settings.json');
|
|
97
|
+
let existing = {};
|
|
98
|
+
try {
|
|
99
|
+
const raw = await readFile(settingsPath, 'utf-8');
|
|
100
|
+
existing = JSON.parse(raw);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// File doesn't exist yet or is not valid JSON — start from empty object
|
|
104
|
+
}
|
|
105
|
+
const merged = mergeHookConfig(existing, generated);
|
|
106
|
+
await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
107
|
+
return {
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
message: `Hook template '${args.template}' applied`,
|
|
113
|
+
settingsPath,
|
|
114
|
+
description: generated.description,
|
|
115
|
+
mergeInstructions: generated.mergeInstructions,
|
|
116
|
+
generatedConfig: generated.hooks,
|
|
117
|
+
}, null, 2),
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=configure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../../../src/tools/start-hooks/configure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ToolResult } from '../../types/index.js';
|
|
2
|
+
import type { StartHooksInput, StopHooksInput } from '../../types/file-hooks.js';
|
|
3
|
+
import { HookEngine } from '../../engine/hooks/hook-engine.js';
|
|
4
|
+
import { FileWatcher } from '../../engine/hooks/file-watcher.js';
|
|
5
|
+
import { ConfigLoader } from '../../engine/hooks/config-loader.js';
|
|
6
|
+
export declare function getEngineInstance(): HookEngine | null;
|
|
7
|
+
export declare function getWatcherInstance(): FileWatcher | null;
|
|
8
|
+
export declare function getConfigLoaderInstance(): ConfigLoader | null;
|
|
9
|
+
export declare function ensureHooksStarted(projectPath: string): void;
|
|
10
|
+
export declare function handleStartHooks(args: StartHooksInput): Promise<ToolResult>;
|
|
11
|
+
export declare function handleStopHooks(_args: StopHooksInput): Promise<ToolResult>;
|
|
12
|
+
export declare function handleHookStatus(): Promise<ToolResult>;
|
|
13
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/tools/start-hooks/engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAQ,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAGV,eAAe,EACf,cAAc,EAGf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAE/D,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AA0BnE,wBAAgB,iBAAiB,IAAI,UAAU,GAAG,IAAI,CAErD;AAED,wBAAgB,kBAAkB,IAAI,WAAW,GAAG,IAAI,CAEvD;AAED,wBAAgB,uBAAuB,IAAI,YAAY,GAAG,IAAI,CAE7D;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAmB5D;AAMD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAwFjF;AAMD,wBAAsB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAoBhF;AAMD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,UAAU,CAAC,CAkC5D"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
// tools/start-hooks/engine.ts — Singleton state + lifecycle handlers for the hook engine.
|
|
2
|
+
import { HookEngine } from '../../engine/hooks/hook-engine.js';
|
|
3
|
+
import { EventBus } from '../../engine/hooks/event-bus.js';
|
|
4
|
+
import { FileWatcher } from '../../engine/hooks/file-watcher.js';
|
|
5
|
+
import { ConfigLoader } from '../../engine/hooks/config-loader.js';
|
|
6
|
+
import { Debouncer } from '../../engine/hooks/debouncer.js';
|
|
7
|
+
import { handleOnImplChange } from '../../engine/hooks/handlers/on-impl-change.js';
|
|
8
|
+
import { handleOnSpecChange } from '../../engine/hooks/handlers/on-spec-change.js';
|
|
9
|
+
import { handleOnPushCheck, getLastPushCheckResult, } from '../../engine/hooks/handlers/on-push-check.js';
|
|
10
|
+
import { handleOnSecurityCheck, isSecuritySensitiveFile, } from '../../engine/hooks/handlers/on-security-check.js';
|
|
11
|
+
import { subscribeStatusChangeHandler } from '../../engine/hooks/handlers/on-status-change.js';
|
|
12
|
+
import { listSpecs } from '../../storage/spec-store.js';
|
|
13
|
+
import { hashProjectPath } from '../../storage/base-store.js';
|
|
14
|
+
import { analyzeLivingSpec } from '../../engine/living-spec-analyzer.js';
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Singleton state
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
let engineInstance = null;
|
|
19
|
+
let watcherInstance = null;
|
|
20
|
+
let debouncerInstance = null;
|
|
21
|
+
let configLoaderInstance = null;
|
|
22
|
+
export function getEngineInstance() {
|
|
23
|
+
return engineInstance;
|
|
24
|
+
}
|
|
25
|
+
export function getWatcherInstance() {
|
|
26
|
+
return watcherInstance;
|
|
27
|
+
}
|
|
28
|
+
export function getConfigLoaderInstance() {
|
|
29
|
+
return configLoaderInstance;
|
|
30
|
+
}
|
|
31
|
+
export function ensureHooksStarted(projectPath) {
|
|
32
|
+
if (engineInstance?.status().running) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
void handleStartHooks({
|
|
36
|
+
projectPath,
|
|
37
|
+
hooks: [
|
|
38
|
+
'on-save',
|
|
39
|
+
'on-create',
|
|
40
|
+
'on-delete',
|
|
41
|
+
'on-commit',
|
|
42
|
+
'on-impl-change',
|
|
43
|
+
'on-spec-change',
|
|
44
|
+
'on-push-check',
|
|
45
|
+
'on-security-check',
|
|
46
|
+
],
|
|
47
|
+
}).catch(() => {
|
|
48
|
+
// Silently swallow — hooks are best-effort
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Start hooks
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
export async function handleStartHooks(args) {
|
|
55
|
+
if (engineInstance?.status().running) {
|
|
56
|
+
const status = engineInstance.status();
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: JSON.stringify({ message: 'Hook engine already running', ...status }, null, 2),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const projectPath = args.projectPath;
|
|
67
|
+
const enabledHooks = args.hooks ?? [
|
|
68
|
+
'on-save',
|
|
69
|
+
'on-create',
|
|
70
|
+
'on-delete',
|
|
71
|
+
'on-impl-change',
|
|
72
|
+
'on-spec-change',
|
|
73
|
+
'on-security-check',
|
|
74
|
+
];
|
|
75
|
+
configLoaderInstance = new ConfigLoader(projectPath);
|
|
76
|
+
const config = await configLoaderInstance.load();
|
|
77
|
+
const eventBus = new EventBus();
|
|
78
|
+
engineInstance = new HookEngine(eventBus);
|
|
79
|
+
watcherInstance = new FileWatcher({
|
|
80
|
+
rootDir: projectPath,
|
|
81
|
+
include: config.hooks['on-save']?.include,
|
|
82
|
+
exclude: config.hooks['on-save']?.exclude,
|
|
83
|
+
});
|
|
84
|
+
debouncerInstance = new Debouncer((event) => {
|
|
85
|
+
const hookTypes = getApplicableHookTypes(event);
|
|
86
|
+
for (const hookType of hookTypes) {
|
|
87
|
+
if (enabledHooks.includes(hookType)) {
|
|
88
|
+
void engineInstance?.dispatch(event, hookType);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}, { debounceMs: config.debounceMs, rateLimitPerFileMs: config.rateLimitPerFileMs });
|
|
92
|
+
watcherInstance.on('change', (event) => {
|
|
93
|
+
eventBus.emitEvent('file:change', {
|
|
94
|
+
path: event.path,
|
|
95
|
+
type: event.type,
|
|
96
|
+
timestamp: event.timestamp,
|
|
97
|
+
});
|
|
98
|
+
debouncerInstance?.push(event);
|
|
99
|
+
});
|
|
100
|
+
configLoaderInstance.startWatching();
|
|
101
|
+
engineInstance.start();
|
|
102
|
+
watcherInstance.start();
|
|
103
|
+
registerAdvancedHandlers(engineInstance, enabledHooks, projectPath, config);
|
|
104
|
+
const eventBusFromEngine = engineInstance.getEventBus();
|
|
105
|
+
subscribeStatusChangeHandler(eventBusFromEngine,
|
|
106
|
+
/* v8 ignore next 3 */ (_projectId) => Promise.resolve(true));
|
|
107
|
+
return {
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
message: 'Hook engine started',
|
|
113
|
+
projectPath,
|
|
114
|
+
enabledHooks,
|
|
115
|
+
config: {
|
|
116
|
+
debounceMs: config.debounceMs,
|
|
117
|
+
rateLimitPerFileMs: config.rateLimitPerFileMs,
|
|
118
|
+
},
|
|
119
|
+
}, null, 2),
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Stop hooks
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
export async function handleStopHooks(_args) {
|
|
128
|
+
await Promise.resolve();
|
|
129
|
+
if (!engineInstance) {
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: 'text', text: JSON.stringify({ message: 'Hook engine not running' }) }],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
engineInstance.stop();
|
|
135
|
+
watcherInstance?.close();
|
|
136
|
+
debouncerInstance?.dispose();
|
|
137
|
+
configLoaderInstance?.close();
|
|
138
|
+
const message = 'Hook engine stopped and resources cleaned up';
|
|
139
|
+
engineInstance = null;
|
|
140
|
+
watcherInstance = null;
|
|
141
|
+
debouncerInstance = null;
|
|
142
|
+
configLoaderInstance = null;
|
|
143
|
+
return { content: [{ type: 'text', text: JSON.stringify({ message }) }] };
|
|
144
|
+
}
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// Hook status
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
export async function handleHookStatus() {
|
|
149
|
+
await Promise.resolve();
|
|
150
|
+
if (!engineInstance) {
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: 'text',
|
|
155
|
+
text: JSON.stringify({
|
|
156
|
+
running: false,
|
|
157
|
+
activeHooks: [],
|
|
158
|
+
pendingEvents: 0,
|
|
159
|
+
telemetry: {},
|
|
160
|
+
eventHistory: 0,
|
|
161
|
+
}),
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const status = engineInstance.status();
|
|
167
|
+
const eventBus = engineInstance.getEventBus();
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{
|
|
171
|
+
type: 'text',
|
|
172
|
+
text: JSON.stringify({ ...status, eventHistory: eventBus.getFullHistory().length }, null, 2),
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Private helpers
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
function getApplicableHookTypes(event) {
|
|
181
|
+
switch (event.type) {
|
|
182
|
+
case 'modify':
|
|
183
|
+
return ['on-save', 'on-impl-change', 'on-spec-change', 'on-security-check'];
|
|
184
|
+
case 'create':
|
|
185
|
+
return ['on-create', 'on-impl-change', 'on-spec-change', 'on-security-check'];
|
|
186
|
+
case 'delete':
|
|
187
|
+
return ['on-delete'];
|
|
188
|
+
/* v8 ignore next 2 */
|
|
189
|
+
default:
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function specToMinimal(spec) {
|
|
194
|
+
return { id: spec.id, title: spec.title, status: spec.status, progressPath: spec.progressPath };
|
|
195
|
+
}
|
|
196
|
+
function makeAnalyzeSpecFn() {
|
|
197
|
+
return async (minimal, projectPath) => {
|
|
198
|
+
const specLike = {
|
|
199
|
+
id: minimal.id,
|
|
200
|
+
title: minimal.title,
|
|
201
|
+
slug: minimal.id
|
|
202
|
+
.toLowerCase()
|
|
203
|
+
.replace(/^spec-/, '')
|
|
204
|
+
.replace(/\s+/g, '-'),
|
|
205
|
+
status: minimal.status,
|
|
206
|
+
progressPath: minimal.progressPath,
|
|
207
|
+
};
|
|
208
|
+
const report = await analyzeLivingSpec(specLike, projectPath);
|
|
209
|
+
return {
|
|
210
|
+
completionPct: report.completionPercent,
|
|
211
|
+
progressUpdated: report.progressUpdated,
|
|
212
|
+
criterionResults: report.criteria.map((c) => ({
|
|
213
|
+
criterion: c.criterion,
|
|
214
|
+
met: c.status === 'met',
|
|
215
|
+
evidence: c.evidence,
|
|
216
|
+
})),
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function registerAdvancedHandlers(engine, enabledHooks, projectPath, config) {
|
|
221
|
+
if (enabledHooks.includes('on-impl-change')) {
|
|
222
|
+
engine.register({
|
|
223
|
+
name: 'on-impl-change',
|
|
224
|
+
hookType: 'on-impl-change',
|
|
225
|
+
priority: 200,
|
|
226
|
+
execute: async (event) => {
|
|
227
|
+
const projectId = hashProjectPath(projectPath);
|
|
228
|
+
let specs = [];
|
|
229
|
+
try {
|
|
230
|
+
const fullSpecs = await listSpecs(projectId);
|
|
231
|
+
specs = fullSpecs.map(specToMinimal);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// Spec load failure — proceed without analysis
|
|
235
|
+
}
|
|
236
|
+
const analysisResult = await handleOnImplChange(event, projectPath, specs, makeAnalyzeSpecFn(), config.autoMarkDone !== false);
|
|
237
|
+
const firstSpecId = analysisResult
|
|
238
|
+
? (analysisResult.specsAnalyzed[0]?.specId ?? null)
|
|
239
|
+
: null;
|
|
240
|
+
return {
|
|
241
|
+
hook: 'on-save',
|
|
242
|
+
specId: firstSpecId,
|
|
243
|
+
driftDelta: analysisResult ? analysisResult.specsAnalyzed.length : 0,
|
|
244
|
+
hashChanged: event.type === 'modify' || event.type === 'create',
|
|
245
|
+
annotationsValid: analysisResult !== undefined,
|
|
246
|
+
};
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (enabledHooks.includes('on-spec-change')) {
|
|
251
|
+
engine.register({
|
|
252
|
+
name: 'on-spec-change',
|
|
253
|
+
hookType: 'on-spec-change',
|
|
254
|
+
priority: 300,
|
|
255
|
+
execute: async (event) => {
|
|
256
|
+
await handleOnSpecChange(event, projectPath);
|
|
257
|
+
return {
|
|
258
|
+
hook: 'on-save',
|
|
259
|
+
specId: null,
|
|
260
|
+
driftDelta: 0,
|
|
261
|
+
hashChanged: event.type !== 'delete',
|
|
262
|
+
annotationsValid: true,
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (enabledHooks.includes('on-push-check')) {
|
|
268
|
+
engine.register({
|
|
269
|
+
name: 'on-push-check',
|
|
270
|
+
hookType: 'on-push-check',
|
|
271
|
+
priority: 150,
|
|
272
|
+
execute: async (event) => {
|
|
273
|
+
await handleOnPushCheck(event, projectPath);
|
|
274
|
+
const pushResult = getLastPushCheckResult(projectPath);
|
|
275
|
+
const findings = pushResult?.findings ?? [];
|
|
276
|
+
const driftWarnings = findings
|
|
277
|
+
.filter((f) => f.severity === 'warning')
|
|
278
|
+
.map((f) => f.message);
|
|
279
|
+
const HIGH_SEVERITY = ['critical', 'high'];
|
|
280
|
+
return {
|
|
281
|
+
hook: 'on-commit',
|
|
282
|
+
commitHash: event.path,
|
|
283
|
+
reconciledSpecs: [],
|
|
284
|
+
integrityResult: {
|
|
285
|
+
valid: findings.every((f) => !HIGH_SEVERITY.includes(f.severity)),
|
|
286
|
+
errors: findings
|
|
287
|
+
.filter((f) => HIGH_SEVERITY.includes(f.severity))
|
|
288
|
+
.map((f) => f.message),
|
|
289
|
+
},
|
|
290
|
+
driftWarnings,
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (enabledHooks.includes('on-security-check')) {
|
|
296
|
+
engine.register({
|
|
297
|
+
name: 'on-security-check',
|
|
298
|
+
hookType: 'on-security-check',
|
|
299
|
+
priority: 250,
|
|
300
|
+
execute: async (event) => {
|
|
301
|
+
await handleOnSecurityCheck(event, projectPath);
|
|
302
|
+
const isSensitive = isSecuritySensitiveFile(event.path);
|
|
303
|
+
return {
|
|
304
|
+
hook: 'on-save',
|
|
305
|
+
specId: null,
|
|
306
|
+
driftDelta: 0,
|
|
307
|
+
hashChanged: event.type !== 'delete',
|
|
308
|
+
annotationsValid: !isSensitive,
|
|
309
|
+
};
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/tools/start-hooks/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { HookEngine } from '../engine/hooks/hook-engine.js';
|
|
4
|
-
import { FileWatcher } from '../engine/hooks/file-watcher.js';
|
|
5
|
-
/**
|
|
6
|
-
* Get the current engine instance (for testing/internal use).
|
|
7
|
-
*/
|
|
8
|
-
export declare function getEngineInstance(): HookEngine | null;
|
|
9
|
-
/**
|
|
10
|
-
* Auto-start hook engine if not running. Called transparently from the tool
|
|
11
|
-
* pipeline whenever a tool receives a projectPath arg. Idempotent and
|
|
12
|
-
* fire-and-forget — errors are silently swallowed so tool execution is never
|
|
13
|
-
* blocked by hook startup failures.
|
|
14
|
-
*/
|
|
15
|
-
export declare function ensureHooksStarted(projectPath: string): void;
|
|
16
|
-
/**
|
|
17
|
-
* Get the current watcher instance (for testing/internal use).
|
|
18
|
-
*/
|
|
19
|
-
export declare function getWatcherInstance(): FileWatcher | null;
|
|
20
|
-
export declare function handleStartHooks(args: StartHooksInput): Promise<ToolResult>;
|
|
21
|
-
export declare function handleStopHooks(_args: StopHooksInput): Promise<ToolResult>;
|
|
22
|
-
export declare function handleHookStatus(): Promise<ToolResult>;
|
|
23
|
-
export declare function handleConfigureHooks(args: ConfigureHooksInput): Promise<ToolResult>;
|
|
1
|
+
export { getEngineInstance, getWatcherInstance, getConfigLoaderInstance, ensureHooksStarted, handleStartHooks, handleStopHooks, handleHookStatus, } from './start-hooks/engine.js';
|
|
2
|
+
export { handleConfigureHooks } from './start-hooks/configure.js';
|
|
24
3
|
//# sourceMappingURL=start-hooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-hooks.d.ts","sourceRoot":"","sources":["../../src/tools/start-hooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"start-hooks.d.ts","sourceRoot":"","sources":["../../src/tools/start-hooks.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -1,517 +1,5 @@
|
|
|
1
|
-
// tools/start-hooks.ts —
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { buildPlanModeHookScripts } from '../engine/hooks/plan-mode-scripts.js';
|
|
6
|
-
import { HookEngine } from '../engine/hooks/hook-engine.js';
|
|
7
|
-
import { EventBus } from '../engine/hooks/event-bus.js';
|
|
8
|
-
import { FileWatcher } from '../engine/hooks/file-watcher.js';
|
|
9
|
-
import { ConfigLoader } from '../engine/hooks/config-loader.js';
|
|
10
|
-
import { Debouncer } from '../engine/hooks/debouncer.js';
|
|
11
|
-
import { handleOnImplChange } from '../engine/hooks/handlers/on-impl-change.js';
|
|
12
|
-
import { handleOnSpecChange } from '../engine/hooks/handlers/on-spec-change.js';
|
|
13
|
-
import { handleOnPushCheck, getLastPushCheckResult, } from '../engine/hooks/handlers/on-push-check.js';
|
|
14
|
-
import { handleOnSecurityCheck, isSecuritySensitiveFile, } from '../engine/hooks/handlers/on-security-check.js';
|
|
15
|
-
import { subscribeStatusChangeHandler } from '../engine/hooks/handlers/on-status-change.js';
|
|
16
|
-
import { listSpecs } from '../storage/spec-store.js';
|
|
17
|
-
import { hashProjectPath } from '../storage/base-store.js';
|
|
18
|
-
import { analyzeLivingSpec } from '../engine/living-spec-analyzer.js';
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
// Singleton state
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
let engineInstance = null;
|
|
23
|
-
let watcherInstance = null;
|
|
24
|
-
let debouncerInstance = null;
|
|
25
|
-
let configLoaderInstance = null;
|
|
26
|
-
/**
|
|
27
|
-
* Get the current engine instance (for testing/internal use).
|
|
28
|
-
*/
|
|
29
|
-
export function getEngineInstance() {
|
|
30
|
-
return engineInstance;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Auto-start hook engine if not running. Called transparently from the tool
|
|
34
|
-
* pipeline whenever a tool receives a projectPath arg. Idempotent and
|
|
35
|
-
* fire-and-forget — errors are silently swallowed so tool execution is never
|
|
36
|
-
* blocked by hook startup failures.
|
|
37
|
-
*/
|
|
38
|
-
export function ensureHooksStarted(projectPath) {
|
|
39
|
-
if (engineInstance?.status().running) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
// Fire-and-forget — don't block the tool call
|
|
43
|
-
void handleStartHooks({
|
|
44
|
-
projectPath,
|
|
45
|
-
hooks: [
|
|
46
|
-
'on-save',
|
|
47
|
-
'on-create',
|
|
48
|
-
'on-delete',
|
|
49
|
-
'on-commit',
|
|
50
|
-
'on-impl-change',
|
|
51
|
-
'on-spec-change',
|
|
52
|
-
'on-push-check',
|
|
53
|
-
'on-security-check',
|
|
54
|
-
],
|
|
55
|
-
}).catch(() => {
|
|
56
|
-
// Silently swallow — hooks are best-effort
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get the current watcher instance (for testing/internal use).
|
|
61
|
-
*/
|
|
62
|
-
export function getWatcherInstance() {
|
|
63
|
-
return watcherInstance;
|
|
64
|
-
}
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
// Start hooks
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
export async function handleStartHooks(args) {
|
|
69
|
-
// Idempotent — if already running, return status
|
|
70
|
-
if (engineInstance?.status().running) {
|
|
71
|
-
const status = engineInstance.status();
|
|
72
|
-
return {
|
|
73
|
-
content: [
|
|
74
|
-
{
|
|
75
|
-
type: 'text',
|
|
76
|
-
text: JSON.stringify({
|
|
77
|
-
message: 'Hook engine already running',
|
|
78
|
-
...status,
|
|
79
|
-
}, null, 2),
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
const projectPath = args.projectPath;
|
|
85
|
-
const enabledHooks = args.hooks ?? [
|
|
86
|
-
'on-save',
|
|
87
|
-
'on-create',
|
|
88
|
-
'on-delete',
|
|
89
|
-
'on-impl-change',
|
|
90
|
-
'on-spec-change',
|
|
91
|
-
'on-security-check',
|
|
92
|
-
];
|
|
93
|
-
// Load config
|
|
94
|
-
configLoaderInstance = new ConfigLoader(projectPath);
|
|
95
|
-
const config = await configLoaderInstance.load();
|
|
96
|
-
// Create event bus and engine
|
|
97
|
-
const eventBus = new EventBus();
|
|
98
|
-
engineInstance = new HookEngine(eventBus);
|
|
99
|
-
// Create file watcher
|
|
100
|
-
watcherInstance = new FileWatcher({
|
|
101
|
-
rootDir: projectPath,
|
|
102
|
-
include: config.hooks['on-save']?.include,
|
|
103
|
-
exclude: config.hooks['on-save']?.exclude,
|
|
104
|
-
});
|
|
105
|
-
// Create debouncer
|
|
106
|
-
debouncerInstance = new Debouncer((event) => {
|
|
107
|
-
const hookTypes = getApplicableHookTypes(event);
|
|
108
|
-
for (const hookType of hookTypes) {
|
|
109
|
-
if (enabledHooks.includes(hookType)) {
|
|
110
|
-
void engineInstance?.dispatch(event, hookType);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}, {
|
|
114
|
-
debounceMs: config.debounceMs,
|
|
115
|
-
rateLimitPerFileMs: config.rateLimitPerFileMs,
|
|
116
|
-
});
|
|
117
|
-
// Wire watcher -> debouncer
|
|
118
|
-
watcherInstance.on('change', (event) => {
|
|
119
|
-
eventBus.emitEvent('file:change', {
|
|
120
|
-
path: event.path,
|
|
121
|
-
type: event.type,
|
|
122
|
-
timestamp: event.timestamp,
|
|
123
|
-
});
|
|
124
|
-
debouncerInstance?.push(event);
|
|
125
|
-
});
|
|
126
|
-
// Start watching config for live reload
|
|
127
|
-
configLoaderInstance.startWatching();
|
|
128
|
-
// Start engine and watcher
|
|
129
|
-
engineInstance.start();
|
|
130
|
-
watcherInstance.start();
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// Register SPEC-137/138 handlers as HookPluginHandlers
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
const registerAdvancedHandlers = () => {
|
|
135
|
-
/* v8 ignore next 3 */
|
|
136
|
-
if (!engineInstance) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
// SPEC-137: on-impl-change — analyze implementation changes + auto-done
|
|
140
|
-
if (enabledHooks.includes('on-impl-change')) {
|
|
141
|
-
engineInstance.register({
|
|
142
|
-
name: 'on-impl-change',
|
|
143
|
-
hookType: 'on-impl-change',
|
|
144
|
-
priority: 200,
|
|
145
|
-
execute: async (event) => {
|
|
146
|
-
const projectId = hashProjectPath(projectPath);
|
|
147
|
-
let specs = [];
|
|
148
|
-
try {
|
|
149
|
-
const fullSpecs = await listSpecs(projectId);
|
|
150
|
-
specs = fullSpecs.map(specToMinimal);
|
|
151
|
-
}
|
|
152
|
-
catch {
|
|
153
|
-
// Spec load failure — proceed without analysis
|
|
154
|
-
}
|
|
155
|
-
const analysisResult = await handleOnImplChange(event, projectPath, specs, makeAnalyzeSpecFn(), config.autoMarkDone !== false);
|
|
156
|
-
// Use the first analyzed spec's ID if available; null means no related spec was found.
|
|
157
|
-
const firstSpecId = analysisResult
|
|
158
|
-
? (analysisResult.specsAnalyzed[0]?.specId ?? null)
|
|
159
|
-
: null;
|
|
160
|
-
return {
|
|
161
|
-
hook: 'on-save',
|
|
162
|
-
specId: firstSpecId,
|
|
163
|
-
// driftDelta = number of specs analyzed (0 = no drift detected or file not relevant)
|
|
164
|
-
driftDelta: analysisResult ? analysisResult.specsAnalyzed.length : 0,
|
|
165
|
-
// hashChanged: true whenever a source file was actually modified (not a no-op event)
|
|
166
|
-
hashChanged: event.type === 'modify' || event.type === 'create',
|
|
167
|
-
annotationsValid: analysisResult !== undefined,
|
|
168
|
-
};
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
// SPEC-137: on-spec-change — detect spec file edits
|
|
173
|
-
if (enabledHooks.includes('on-spec-change')) {
|
|
174
|
-
engineInstance.register({
|
|
175
|
-
name: 'on-spec-change',
|
|
176
|
-
hookType: 'on-spec-change',
|
|
177
|
-
priority: 300,
|
|
178
|
-
execute: async (event) => {
|
|
179
|
-
await handleOnSpecChange(event, projectPath);
|
|
180
|
-
return {
|
|
181
|
-
hook: 'on-save',
|
|
182
|
-
specId: null,
|
|
183
|
-
// A spec file was saved — the hash of spec content is considered changed.
|
|
184
|
-
driftDelta: 0,
|
|
185
|
-
hashChanged: event.type !== 'delete',
|
|
186
|
-
annotationsValid: true,
|
|
187
|
-
};
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
// SPEC-138: on-push-check — drift detection on commits
|
|
192
|
-
if (enabledHooks.includes('on-push-check')) {
|
|
193
|
-
engineInstance.register({
|
|
194
|
-
name: 'on-push-check',
|
|
195
|
-
hookType: 'on-push-check',
|
|
196
|
-
priority: 150,
|
|
197
|
-
execute: async (event) => {
|
|
198
|
-
await handleOnPushCheck(event, projectPath);
|
|
199
|
-
// Retrieve the push-check result written by the handler for real data.
|
|
200
|
-
const pushResult = getLastPushCheckResult(projectPath);
|
|
201
|
-
const findings = pushResult?.findings ?? [];
|
|
202
|
-
const driftWarnings = findings
|
|
203
|
-
.filter((f) => f.severity === 'warning')
|
|
204
|
-
.map((f) => f.message);
|
|
205
|
-
const HIGH_SEVERITY = ['critical', 'high'];
|
|
206
|
-
return {
|
|
207
|
-
hook: 'on-commit',
|
|
208
|
-
commitHash: event.path, // most accurate commit identifier available from the event
|
|
209
|
-
reconciledSpecs: [],
|
|
210
|
-
integrityResult: {
|
|
211
|
-
valid: findings.every((f) => !HIGH_SEVERITY.includes(f.severity)),
|
|
212
|
-
errors: findings
|
|
213
|
-
.filter((f) => HIGH_SEVERITY.includes(f.severity))
|
|
214
|
-
.map((f) => f.message),
|
|
215
|
-
},
|
|
216
|
-
driftWarnings,
|
|
217
|
-
};
|
|
218
|
-
},
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
// SPEC-138: on-security-check — detect security-sensitive changes
|
|
222
|
-
if (enabledHooks.includes('on-security-check')) {
|
|
223
|
-
engineInstance.register({
|
|
224
|
-
name: 'on-security-check',
|
|
225
|
-
hookType: 'on-security-check',
|
|
226
|
-
priority: 250,
|
|
227
|
-
execute: async (event) => {
|
|
228
|
-
await handleOnSecurityCheck(event, projectPath);
|
|
229
|
-
// annotationsValid = false when the file is security-sensitive, triggering downstream review.
|
|
230
|
-
const isSensitive = isSecuritySensitiveFile(event.path);
|
|
231
|
-
return {
|
|
232
|
-
hook: 'on-save',
|
|
233
|
-
specId: null,
|
|
234
|
-
driftDelta: 0,
|
|
235
|
-
hashChanged: event.type !== 'delete',
|
|
236
|
-
annotationsValid: !isSensitive,
|
|
237
|
-
};
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
registerAdvancedHandlers();
|
|
243
|
-
// SPEC-137: Subscribe on-status-change to EventBus for dashboard regeneration
|
|
244
|
-
const eventBusFromEngine = engineInstance.getEventBus();
|
|
245
|
-
subscribeStatusChangeHandler(eventBusFromEngine,
|
|
246
|
-
/* v8 ignore next 3 */ (_projectId) => {
|
|
247
|
-
// Dashboard regeneration is handled by the existing update-status tool flow
|
|
248
|
-
return Promise.resolve(true);
|
|
249
|
-
});
|
|
250
|
-
return {
|
|
251
|
-
content: [
|
|
252
|
-
{
|
|
253
|
-
type: 'text',
|
|
254
|
-
text: JSON.stringify({
|
|
255
|
-
message: 'Hook engine started',
|
|
256
|
-
projectPath,
|
|
257
|
-
enabledHooks,
|
|
258
|
-
config: {
|
|
259
|
-
debounceMs: config.debounceMs,
|
|
260
|
-
rateLimitPerFileMs: config.rateLimitPerFileMs,
|
|
261
|
-
},
|
|
262
|
-
}, null, 2),
|
|
263
|
-
},
|
|
264
|
-
],
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
// ---------------------------------------------------------------------------
|
|
268
|
-
// Helpers
|
|
269
|
-
// ---------------------------------------------------------------------------
|
|
270
|
-
function getApplicableHookTypes(event) {
|
|
271
|
-
switch (event.type) {
|
|
272
|
-
case 'modify':
|
|
273
|
-
return ['on-save', 'on-impl-change', 'on-spec-change', 'on-security-check'];
|
|
274
|
-
case 'create':
|
|
275
|
-
return ['on-create', 'on-impl-change', 'on-spec-change', 'on-security-check'];
|
|
276
|
-
case 'delete':
|
|
277
|
-
return ['on-delete'];
|
|
278
|
-
/* v8 ignore next 2 */
|
|
279
|
-
default:
|
|
280
|
-
return [];
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// ---------------------------------------------------------------------------
|
|
284
|
-
// Spec analysis helpers
|
|
285
|
-
// ---------------------------------------------------------------------------
|
|
286
|
-
/**
|
|
287
|
-
* Convert a full Spec to the minimal shape required by handleOnImplChange.
|
|
288
|
-
* criterionPaths is not on Spec, so it is omitted (defaults to undefined).
|
|
289
|
-
*/
|
|
290
|
-
function specToMinimal(spec) {
|
|
291
|
-
return {
|
|
292
|
-
id: spec.id,
|
|
293
|
-
title: spec.title,
|
|
294
|
-
status: spec.status,
|
|
295
|
-
progressPath: spec.progressPath,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Build an AnalyzeSpecFn that delegates to living-spec-analyzer.
|
|
300
|
-
* Adapts the full analyzeLivingSpec return type to AnalyzeSpecFnResult.
|
|
301
|
-
*/
|
|
302
|
-
function makeAnalyzeSpecFn() {
|
|
303
|
-
return async (minimal, projectPath) => {
|
|
304
|
-
// Build a minimal Spec shape — living-spec-analyzer only needs id, title, slug, progressPath
|
|
305
|
-
const specLike = {
|
|
306
|
-
id: minimal.id,
|
|
307
|
-
title: minimal.title,
|
|
308
|
-
slug: minimal.id
|
|
309
|
-
.toLowerCase()
|
|
310
|
-
.replace(/^spec-/, '')
|
|
311
|
-
.replace(/\s+/g, '-'),
|
|
312
|
-
status: minimal.status,
|
|
313
|
-
progressPath: minimal.progressPath,
|
|
314
|
-
};
|
|
315
|
-
const report = await analyzeLivingSpec(specLike, projectPath);
|
|
316
|
-
return {
|
|
317
|
-
completionPct: report.completionPercent,
|
|
318
|
-
progressUpdated: report.progressUpdated,
|
|
319
|
-
criterionResults: report.criteria.map((c) => ({
|
|
320
|
-
criterion: c.criterion,
|
|
321
|
-
met: c.status === 'met',
|
|
322
|
-
evidence: c.evidence,
|
|
323
|
-
})),
|
|
324
|
-
};
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
// ---------------------------------------------------------------------------
|
|
328
|
-
// Stop hooks
|
|
329
|
-
// ---------------------------------------------------------------------------
|
|
330
|
-
export async function handleStopHooks(_args) {
|
|
331
|
-
await Promise.resolve(); // Ensure async for safeLicensed wrapper
|
|
332
|
-
if (!engineInstance) {
|
|
333
|
-
return {
|
|
334
|
-
content: [{ type: 'text', text: JSON.stringify({ message: 'Hook engine not running' }) }],
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
engineInstance.stop();
|
|
338
|
-
watcherInstance?.close();
|
|
339
|
-
debouncerInstance?.dispose();
|
|
340
|
-
configLoaderInstance?.close();
|
|
341
|
-
const message = 'Hook engine stopped and resources cleaned up';
|
|
342
|
-
engineInstance = null;
|
|
343
|
-
watcherInstance = null;
|
|
344
|
-
debouncerInstance = null;
|
|
345
|
-
configLoaderInstance = null;
|
|
346
|
-
return {
|
|
347
|
-
content: [{ type: 'text', text: JSON.stringify({ message }) }],
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
// ---------------------------------------------------------------------------
|
|
351
|
-
// Hook status
|
|
352
|
-
// ---------------------------------------------------------------------------
|
|
353
|
-
export async function handleHookStatus() {
|
|
354
|
-
await Promise.resolve(); // Ensure async for safeLicensed wrapper
|
|
355
|
-
if (!engineInstance) {
|
|
356
|
-
return {
|
|
357
|
-
content: [
|
|
358
|
-
{
|
|
359
|
-
type: 'text',
|
|
360
|
-
text: JSON.stringify({
|
|
361
|
-
running: false,
|
|
362
|
-
activeHooks: [],
|
|
363
|
-
pendingEvents: 0,
|
|
364
|
-
telemetry: {},
|
|
365
|
-
eventHistory: 0,
|
|
366
|
-
}),
|
|
367
|
-
},
|
|
368
|
-
],
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
const status = engineInstance.status();
|
|
372
|
-
const eventBus = engineInstance.getEventBus();
|
|
373
|
-
return {
|
|
374
|
-
content: [
|
|
375
|
-
{
|
|
376
|
-
type: 'text',
|
|
377
|
-
text: JSON.stringify({
|
|
378
|
-
...status,
|
|
379
|
-
eventHistory: eventBus.getFullHistory().length,
|
|
380
|
-
}, null, 2),
|
|
381
|
-
},
|
|
382
|
-
],
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
// ---------------------------------------------------------------------------
|
|
386
|
-
// Configure hooks
|
|
387
|
-
// ---------------------------------------------------------------------------
|
|
388
|
-
export async function handleConfigureHooks(args) {
|
|
389
|
-
// SPEC-262 — Plan Mode integration action
|
|
390
|
-
if (args.action === 'enable-plan-mode-integration') {
|
|
391
|
-
return enablePlanModeIntegration(args.projectPath);
|
|
392
|
-
}
|
|
393
|
-
// SPEC-258 — Template mode: generate + merge into .claude/settings.json
|
|
394
|
-
if (args.template) {
|
|
395
|
-
return applyHookTemplate(args);
|
|
396
|
-
}
|
|
397
|
-
if (!configLoaderInstance) {
|
|
398
|
-
// Not running — just load and report current config
|
|
399
|
-
const loader = new ConfigLoader(args.projectPath);
|
|
400
|
-
const config = await loader.load();
|
|
401
|
-
loader.close();
|
|
402
|
-
return {
|
|
403
|
-
content: [
|
|
404
|
-
{
|
|
405
|
-
type: 'text',
|
|
406
|
-
text: JSON.stringify({
|
|
407
|
-
message: 'Hook engine not running. Current config:',
|
|
408
|
-
config,
|
|
409
|
-
}, null, 2),
|
|
410
|
-
},
|
|
411
|
-
],
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
// Reload config
|
|
415
|
-
const config = await configLoaderInstance.load();
|
|
416
|
-
return {
|
|
417
|
-
content: [
|
|
418
|
-
{
|
|
419
|
-
type: 'text',
|
|
420
|
-
text: JSON.stringify({
|
|
421
|
-
message: 'Configuration reloaded',
|
|
422
|
-
config,
|
|
423
|
-
engineRunning: engineInstance?.status().running ?? false,
|
|
424
|
-
}, null, 2),
|
|
425
|
-
},
|
|
426
|
-
],
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
// ---------------------------------------------------------------------------
|
|
430
|
-
// SPEC-262 — Enable Plan Mode integration via Claude Code hooks
|
|
431
|
-
// ---------------------------------------------------------------------------
|
|
432
|
-
async function enablePlanModeIntegration(projectPath) {
|
|
433
|
-
const hooksDir = join(projectPath, '.claude', 'hooks');
|
|
434
|
-
await mkdir(hooksDir, { recursive: true });
|
|
435
|
-
const scripts = buildPlanModeHookScripts();
|
|
436
|
-
const preHookPath = join(hooksDir, 'planu-pre-plan.sh');
|
|
437
|
-
const postHookPath = join(hooksDir, 'planu-post-plan.sh');
|
|
438
|
-
await writeFile(preHookPath, scripts.preScript, { mode: 0o755 });
|
|
439
|
-
await writeFile(postHookPath, scripts.postScript, { mode: 0o755 });
|
|
440
|
-
// Merge PreToolUse / PostToolUse entries into .claude/settings.json
|
|
441
|
-
const settingsPath = join(projectPath, '.claude', 'settings.json');
|
|
442
|
-
let existing = {};
|
|
443
|
-
try {
|
|
444
|
-
const raw = await readFile(settingsPath, 'utf-8');
|
|
445
|
-
existing = JSON.parse(raw);
|
|
446
|
-
}
|
|
447
|
-
catch {
|
|
448
|
-
// File doesn't exist yet — start from empty
|
|
449
|
-
}
|
|
450
|
-
const preEntry = {
|
|
451
|
-
matcher: 'Task',
|
|
452
|
-
hooks: [{ type: 'command', command: `bash "${preHookPath}"` }],
|
|
453
|
-
};
|
|
454
|
-
const postEntry = {
|
|
455
|
-
matcher: 'exit_plan_mode',
|
|
456
|
-
hooks: [{ type: 'command', command: `bash "${postHookPath}"` }],
|
|
457
|
-
};
|
|
458
|
-
const existingHooks = (existing.hooks ?? {});
|
|
459
|
-
const merged = {
|
|
460
|
-
...existing,
|
|
461
|
-
hooks: {
|
|
462
|
-
...existingHooks,
|
|
463
|
-
PreToolUse: [...(existingHooks.PreToolUse ?? []), preEntry],
|
|
464
|
-
PostToolUse: [...(existingHooks.PostToolUse ?? []), postEntry],
|
|
465
|
-
},
|
|
466
|
-
};
|
|
467
|
-
await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
468
|
-
const result = {
|
|
469
|
-
action: 'enable-plan-mode-integration',
|
|
470
|
-
preHookPath,
|
|
471
|
-
postHookPath,
|
|
472
|
-
settingsPath,
|
|
473
|
-
message: 'Plan Mode integration enabled. Planu context will be injected automatically when Claude enters Plan Mode.',
|
|
474
|
-
};
|
|
475
|
-
return {
|
|
476
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
// ---------------------------------------------------------------------------
|
|
480
|
-
// SPEC-258 — Apply Claude Code hook template to .claude/settings.json
|
|
481
|
-
// ---------------------------------------------------------------------------
|
|
482
|
-
async function applyHookTemplate(args) {
|
|
483
|
-
/* c8 ignore next 3 */
|
|
484
|
-
if (!args.template) {
|
|
485
|
-
return { content: [{ type: 'text', text: 'template is required' }], isError: true };
|
|
486
|
-
}
|
|
487
|
-
const generated = generateHookTemplate({
|
|
488
|
-
template: args.template,
|
|
489
|
-
notificationMatcher: args.notificationMatcher,
|
|
490
|
-
});
|
|
491
|
-
const settingsPath = join(args.projectPath, '.claude', 'settings.json');
|
|
492
|
-
let existing = {};
|
|
493
|
-
try {
|
|
494
|
-
const raw = await readFile(settingsPath, 'utf-8');
|
|
495
|
-
existing = JSON.parse(raw);
|
|
496
|
-
}
|
|
497
|
-
catch {
|
|
498
|
-
// File doesn't exist yet or is not valid JSON — start from empty object
|
|
499
|
-
}
|
|
500
|
-
const merged = mergeHookConfig(existing, generated);
|
|
501
|
-
await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
502
|
-
return {
|
|
503
|
-
content: [
|
|
504
|
-
{
|
|
505
|
-
type: 'text',
|
|
506
|
-
text: JSON.stringify({
|
|
507
|
-
message: `Hook template '${args.template}' applied`,
|
|
508
|
-
settingsPath,
|
|
509
|
-
description: generated.description,
|
|
510
|
-
mergeInstructions: generated.mergeInstructions,
|
|
511
|
-
generatedConfig: generated.hooks,
|
|
512
|
-
}, null, 2),
|
|
513
|
-
},
|
|
514
|
-
],
|
|
515
|
-
};
|
|
516
|
-
}
|
|
1
|
+
// tools/start-hooks.ts — Barrel re-export. Implementation split into start-hooks/ subdirectory.
|
|
2
|
+
// Existing imports (register-hooks-tools.ts, safe-handler.ts) continue to work unchanged.
|
|
3
|
+
export { getEngineInstance, getWatcherInstance, getConfigLoaderInstance, ensureHooksStarted, handleStartHooks, handleStopHooks, handleHookStatus, } from './start-hooks/engine.js';
|
|
4
|
+
export { handleConfigureHooks } from './start-hooks/configure.js';
|
|
517
5
|
//# sourceMappingURL=start-hooks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-hooks.js","sourceRoot":"","sources":["../../src/tools/start-hooks.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"start-hooks.js","sourceRoot":"","sources":["../../src/tools/start-hooks.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,0FAA0F;AAE1F,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "0.97.
|
|
3
|
+
"version": "0.97.1",
|
|
4
4
|
"description": "Planu — MCP Server for Spec Driven Development. Manages specs, estimations, reverse engineering, and auto-learning across any language/framework.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|