claude-flow-novice 1.5.17 → 1.5.19

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.
Files changed (24) hide show
  1. package/.claude-flow-novice/dist/config/hooks/post-edit-pipeline.js +1837 -0
  2. package/.claude-flow-novice/dist/src/hooks/communication-integrated-post-edit.js +673 -0
  3. package/.claude-flow-novice/dist/src/hooks/enhanced/experience-adaptation-hooks.js +347 -0
  4. package/.claude-flow-novice/dist/src/hooks/enhanced/personalization-hooks.js +118 -0
  5. package/.claude-flow-novice/dist/src/hooks/enhanced-post-edit-pipeline.js +2044 -0
  6. package/.claude-flow-novice/dist/src/hooks/filter-integration.js +542 -0
  7. package/.claude-flow-novice/dist/src/hooks/guidance-hooks.js +629 -0
  8. package/.claude-flow-novice/dist/src/hooks/index.ts +239 -0
  9. package/.claude-flow-novice/dist/src/hooks/managers/enhanced-hook-manager.js +200 -0
  10. package/.claude-flow-novice/dist/src/hooks/resilient-hook-system.js +812 -0
  11. package/CHANGELOG.md +22 -0
  12. package/config/hooks/post-edit-pipeline.js +30 -0
  13. package/package.json +2 -1
  14. package/src/cli/simple-commands/init/templates/CLAUDE.md +38 -6
  15. package/src/hooks/communication-integrated-post-edit.js +673 -0
  16. package/src/hooks/enhanced/experience-adaptation-hooks.js +347 -0
  17. package/src/hooks/enhanced/personalization-hooks.js +118 -0
  18. package/src/hooks/enhanced-hooks-cli.js +168 -0
  19. package/src/hooks/enhanced-post-edit-pipeline.js +2044 -0
  20. package/src/hooks/filter-integration.js +542 -0
  21. package/src/hooks/guidance-hooks.js +629 -0
  22. package/src/hooks/index.ts +239 -0
  23. package/src/hooks/managers/enhanced-hook-manager.js +200 -0
  24. package/src/hooks/resilient-hook-system.js +812 -0
@@ -0,0 +1,542 @@
1
+ /**
2
+ * Filter Integration Hooks
3
+ * Intercepts document generation and applies filtering during agent operations
4
+ */
5
+
6
+ import { ContentFilters } from '../filters/content-filters.js';
7
+ import { ToneProcessors } from '../filters/tone-processors.js';
8
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
9
+ import { join, dirname } from 'path';
10
+
11
+ class FilterIntegrationHooks {
12
+ constructor(projectRoot = process.cwd()) {
13
+ this.projectRoot = projectRoot;
14
+ this.settingsPath = join(projectRoot, '.claude', 'settings.json');
15
+
16
+ this.loadSettings();
17
+
18
+ this.contentFilters = new ContentFilters(this.settings.contentFilters || {});
19
+ this.toneProcessors = new ToneProcessors(this.settings.toneProcessors || {});
20
+
21
+ this.interceptCount = 0;
22
+ this.actionLog = [];
23
+
24
+ this.setupHooks();
25
+ }
26
+
27
+ /**
28
+ * Load settings from .claude/settings.json
29
+ */
30
+ loadSettings() {
31
+ try {
32
+ if (existsSync(this.settingsPath)) {
33
+ const settingsData = readFileSync(this.settingsPath, 'utf8');
34
+ this.settings = JSON.parse(settingsData);
35
+ } else {
36
+ this.settings = this.getDefaultSettings();
37
+ this.saveSettings();
38
+ }
39
+ } catch (error) {
40
+ console.warn('Error loading settings, using defaults:', error.message);
41
+ this.settings = this.getDefaultSettings();
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Get default filter settings
47
+ */
48
+ getDefaultSettings() {
49
+ return {
50
+ contentFilters: {
51
+ enabled: true,
52
+ maxMdFiles: 15,
53
+ allowedDocTypes: ['API', 'README', 'CHANGELOG', 'GUIDE'],
54
+ rootDirectoryProtection: true,
55
+ allowedRootFiles: ['README.md', 'CHANGELOG.md', 'LICENSE.md', 'CONTRIBUTING.md'],
56
+ blockedPatterns: [
57
+ 'IMPLEMENTATION_REPORT',
58
+ 'COMPLETION_SUMMARY',
59
+ 'AGENT_REPORT',
60
+ 'PERFORMANCE_ANALYSIS',
61
+ '^TEMP_',
62
+ '^WORKING_',
63
+ 'STATUS_UPDATE',
64
+ 'PROGRESS_REPORT',
65
+ ],
66
+ },
67
+ toneProcessors: {
68
+ enabled: true,
69
+ defaultPreset: 'professional',
70
+ removeSelfCongratulatory: true,
71
+ simplifyJargon: false,
72
+ focusOnActionable: true,
73
+ customPatterns: {
74
+ 'we have successfully': 'we have',
75
+ 'perfectly implemented': 'implemented',
76
+ 'flawless execution': 'execution',
77
+ 'amazing results': 'good results',
78
+ },
79
+ },
80
+ hooks: {
81
+ preDocumentGeneration: true,
82
+ postAgentMessage: true,
83
+ preFileWrite: true,
84
+ realTimeFiltering: true,
85
+ },
86
+ userPreferences: {
87
+ tonePreset: 'professional',
88
+ maxDocumentLength: 5000,
89
+ allowReports: false,
90
+ consolidateDocuments: true,
91
+ },
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Save settings to .claude/settings.json
97
+ */
98
+ saveSettings() {
99
+ try {
100
+ const settingsDir = dirname(this.settingsPath);
101
+ if (!existsSync(settingsDir)) {
102
+ require('fs').mkdirSync(settingsDir, { recursive: true });
103
+ }
104
+
105
+ writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2));
106
+ } catch (error) {
107
+ console.error('Error saving settings:', error.message);
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Setup integration hooks
113
+ */
114
+ setupHooks() {
115
+ // Hook into global process if available
116
+ if (typeof process !== 'undefined' && process.on) {
117
+ process.on('documentGeneration', (event) => this.handleDocumentGeneration(event));
118
+ process.on('agentMessage', (event) => this.handleAgentMessage(event));
119
+ process.on('fileWrite', (event) => this.handleFileWrite(event));
120
+ }
121
+
122
+ // Register CLI hooks
123
+ this.registerCliHooks();
124
+ }
125
+
126
+ /**
127
+ * Register CLI command hooks
128
+ */
129
+ registerCliHooks() {
130
+ const hookCommands = [
131
+ 'pre-document-generation',
132
+ 'post-agent-message',
133
+ 'pre-file-write',
134
+ 'filter-check',
135
+ ];
136
+
137
+ // This would integrate with the existing hook system
138
+ hookCommands.forEach((command) => {
139
+ this.registerHook(command);
140
+ });
141
+ }
142
+
143
+ /**
144
+ * Register individual hook
145
+ */
146
+ registerHook(hookName) {
147
+ const hookPath = join(this.projectRoot, '.claude', 'hooks', `${hookName}.js`);
148
+
149
+ try {
150
+ if (existsSync(hookPath)) {
151
+ const hookModule = require(hookPath);
152
+ hookModule.addPreProcessor = (processor) => {
153
+ this.addCustomProcessor(hookName, processor);
154
+ };
155
+ }
156
+ } catch (error) {
157
+ // Hook file doesn't exist or has errors, continue silently
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Intercept document generation requests
163
+ */
164
+ interceptDocumentGeneration(filePath, content, metadata = {}) {
165
+ if (!this.settings.contentFilters.enabled) {
166
+ return { allowed: true, content, filePath };
167
+ }
168
+
169
+ this.interceptCount++;
170
+
171
+ const filterResult = this.contentFilters.filterDocumentRequest(filePath, content, metadata);
172
+
173
+ let processedContent = content;
174
+
175
+ // Apply tone processing if document is allowed
176
+ if (filterResult.allowed && this.settings.toneProcessors.enabled) {
177
+ const toneResult = this.toneProcessors.processMessage(
178
+ content,
179
+ this.settings.userPreferences.tonePreset,
180
+ this.settings.userPreferences,
181
+ );
182
+ processedContent = toneResult.processed;
183
+
184
+ // Log tone processing
185
+ if (toneResult.changes.length > 0) {
186
+ this.logAction('TONE_PROCESSED', filePath, {
187
+ changes: toneResult.changes,
188
+ metrics: toneResult.metrics,
189
+ });
190
+ }
191
+ }
192
+
193
+ const result = {
194
+ allowed: filterResult.allowed,
195
+ content: processedContent,
196
+ filePath: filterResult.suggestedPath,
197
+ reason: filterResult.reason,
198
+ modifications: filterResult.modifications,
199
+ originalPath: filePath,
200
+ processed: content !== processedContent,
201
+ };
202
+
203
+ this.logAction('DOCUMENT_INTERCEPT', filePath, result);
204
+
205
+ return result;
206
+ }
207
+
208
+ /**
209
+ * Handle document generation events
210
+ */
211
+ handleDocumentGeneration(event) {
212
+ const { filePath, content, metadata } = event;
213
+ const result = this.interceptDocumentGeneration(filePath, content, metadata);
214
+
215
+ if (!result.allowed) {
216
+ event.preventDefault();
217
+ event.result = result;
218
+ } else if (result.processed || result.filePath !== result.originalPath) {
219
+ event.content = result.content;
220
+ event.filePath = result.filePath;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Process agent messages through tone filters
226
+ */
227
+ processAgentMessage(message, agentType = 'generic', context = {}) {
228
+ if (!this.settings.toneProcessors.enabled) {
229
+ return message;
230
+ }
231
+
232
+ // Determine appropriate tone based on agent type and context
233
+ const tonePreset = this.determineTonePreset(agentType, context);
234
+
235
+ const result = this.toneProcessors.processMessage(
236
+ message,
237
+ tonePreset,
238
+ this.settings.userPreferences,
239
+ );
240
+
241
+ this.logAction('MESSAGE_PROCESSED', agentType, {
242
+ originalLength: message.length,
243
+ processedLength: result.processed.length,
244
+ changes: result.changes,
245
+ tone: tonePreset,
246
+ });
247
+
248
+ return result.processed;
249
+ }
250
+
251
+ /**
252
+ * Handle agent message events
253
+ */
254
+ handleAgentMessage(event) {
255
+ const { message, agentType, context } = event;
256
+ const processedMessage = this.processAgentMessage(message, agentType, context);
257
+
258
+ if (processedMessage !== message) {
259
+ event.message = processedMessage;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Handle file write events
265
+ */
266
+ handleFileWrite(event) {
267
+ const { filePath, content } = event;
268
+
269
+ if (filePath.endsWith('.md') || this.isDocumentationFile(filePath)) {
270
+ const result = this.interceptDocumentGeneration(filePath, content);
271
+
272
+ if (!result.allowed) {
273
+ event.preventDefault();
274
+ event.result = result;
275
+
276
+ // Suggest alternative action
277
+ if (result.suggestedPath) {
278
+ console.warn(`Document generation blocked: ${result.reason}`);
279
+ console.log(`Suggested alternative: ${result.suggestedPath}`);
280
+ }
281
+ } else {
282
+ event.content = result.content;
283
+ event.filePath = result.filePath;
284
+ }
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Real-time filtering middleware
290
+ */
291
+ createFilterMiddleware() {
292
+ return (request, response, next) => {
293
+ // Intercept write operations
294
+ if (request.operation === 'write' && request.filePath) {
295
+ const result = this.interceptDocumentGeneration(
296
+ request.filePath,
297
+ request.content,
298
+ request.metadata,
299
+ );
300
+
301
+ if (!result.allowed) {
302
+ response.status(403).json({
303
+ error: 'Document generation blocked',
304
+ reason: result.reason,
305
+ suggestedPath: result.suggestedPath,
306
+ modifications: result.modifications,
307
+ });
308
+ return;
309
+ }
310
+
311
+ // Update request with processed content
312
+ request.content = result.content;
313
+ request.filePath = result.filePath;
314
+ }
315
+
316
+ next();
317
+ };
318
+ }
319
+
320
+ /**
321
+ * Process multiple documents in batch
322
+ */
323
+ batchProcessDocuments(documents) {
324
+ return documents.map((doc) => ({
325
+ ...doc,
326
+ ...this.interceptDocumentGeneration(doc.filePath, doc.content, doc.metadata),
327
+ }));
328
+ }
329
+
330
+ /**
331
+ * Apply filters to agent task output
332
+ */
333
+ filterTaskOutput(taskId, output, agentType) {
334
+ const processedOutput = {
335
+ messages: [],
336
+ files: [],
337
+ blocked: [],
338
+ modified: [],
339
+ };
340
+
341
+ // Process messages
342
+ if (output.messages) {
343
+ output.messages.forEach((message) => {
344
+ const processed = this.processAgentMessage(message.content, agentType, { taskId });
345
+ processedOutput.messages.push({
346
+ ...message,
347
+ content: processed,
348
+ modified: processed !== message.content,
349
+ });
350
+ });
351
+ }
352
+
353
+ // Process file operations
354
+ if (output.files) {
355
+ output.files.forEach((file) => {
356
+ const result = this.interceptDocumentGeneration(file.path, file.content, {
357
+ taskId,
358
+ agentType,
359
+ });
360
+
361
+ if (result.allowed) {
362
+ processedOutput.files.push({
363
+ ...file,
364
+ path: result.filePath,
365
+ content: result.content,
366
+ modified: result.processed || result.filePath !== file.path,
367
+ });
368
+ } else {
369
+ processedOutput.blocked.push({
370
+ ...file,
371
+ reason: result.reason,
372
+ suggestedPath: result.suggestedPath,
373
+ });
374
+ }
375
+ });
376
+ }
377
+
378
+ this.logAction('TASK_OUTPUT_FILTERED', taskId, {
379
+ agentType,
380
+ messagesProcessed: processedOutput.messages.length,
381
+ filesAllowed: processedOutput.files.length,
382
+ filesBlocked: processedOutput.blocked.length,
383
+ });
384
+
385
+ return processedOutput;
386
+ }
387
+
388
+ // Helper methods
389
+
390
+ determineTonePreset(agentType, context = {}) {
391
+ const agentToneMap = {
392
+ researcher: 'technical',
393
+ coder: 'concise',
394
+ reviewer: 'professional',
395
+ tester: 'professional',
396
+ planner: 'professional',
397
+ 'backend-dev': 'technical',
398
+ 'frontend-dev': 'friendly',
399
+ devops: 'concise',
400
+ generic: this.settings.userPreferences.tonePreset,
401
+ };
402
+
403
+ return agentToneMap[agentType] || this.settings.userPreferences.tonePreset;
404
+ }
405
+
406
+ isDocumentationFile(filePath) {
407
+ const docExtensions = ['.md', '.txt', '.rst', '.adoc'];
408
+ const docPaths = ['/docs/', '/documentation/', '/guides/', '/README'];
409
+
410
+ return (
411
+ docExtensions.some((ext) => filePath.endsWith(ext)) ||
412
+ docPaths.some((path) => filePath.includes(path))
413
+ );
414
+ }
415
+
416
+ logAction(action, target, details = {}) {
417
+ const logEntry = {
418
+ timestamp: new Date().toISOString(),
419
+ action,
420
+ target,
421
+ details,
422
+ id: this.actionLog.length + 1,
423
+ };
424
+
425
+ this.actionLog.push(logEntry);
426
+
427
+ // Keep log manageable
428
+ if (this.actionLog.length > 1000) {
429
+ this.actionLog = this.actionLog.slice(-500);
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Add custom processor
435
+ */
436
+ addCustomProcessor(hookName, processor) {
437
+ if (!this.customProcessors) {
438
+ this.customProcessors = {};
439
+ }
440
+
441
+ if (!this.customProcessors[hookName]) {
442
+ this.customProcessors[hookName] = [];
443
+ }
444
+
445
+ this.customProcessors[hookName].push(processor);
446
+ }
447
+
448
+ /**
449
+ * Get comprehensive statistics
450
+ */
451
+ getFilterStats() {
452
+ return {
453
+ interceptCount: this.interceptCount,
454
+ contentFilters: this.contentFilters.getFilterStats(),
455
+ toneProcessors: this.toneProcessors.getProcessingStats(),
456
+ recentActions: this.actionLog.slice(-20),
457
+ settings: this.settings,
458
+ topBlockedReasons: this.getTopBlockedReasons(),
459
+ };
460
+ }
461
+
462
+ getTopBlockedReasons() {
463
+ const reasonCounts = {};
464
+
465
+ this.actionLog
466
+ .filter((entry) => entry.action === 'DOCUMENT_INTERCEPT' && !entry.details.allowed)
467
+ .forEach((entry) => {
468
+ const reason = entry.details.reason;
469
+ reasonCounts[reason] = (reasonCounts[reason] || 0) + 1;
470
+ });
471
+
472
+ return Object.entries(reasonCounts)
473
+ .sort(([, a], [, b]) => b - a)
474
+ .slice(0, 5)
475
+ .map(([reason, count]) => ({ reason, count }));
476
+ }
477
+
478
+ /**
479
+ * Update user preferences
480
+ */
481
+ updatePreferences(preferences) {
482
+ this.settings.userPreferences = { ...this.settings.userPreferences, ...preferences };
483
+ this.saveSettings();
484
+
485
+ // Update processor configurations
486
+ this.contentFilters.updateLimits(this.settings.contentFilters);
487
+ this.toneProcessors.updateConfig(this.settings.toneProcessors);
488
+ }
489
+
490
+ /**
491
+ * Export filter configuration for auditing
492
+ */
493
+ exportConfiguration() {
494
+ return {
495
+ settings: this.settings,
496
+ stats: this.getFilterStats(),
497
+ contentFiltersConfig: this.contentFilters.exportConfig(),
498
+ toneProcessorsConfig: this.toneProcessors.exportConfig(),
499
+ };
500
+ }
501
+
502
+ /**
503
+ * Reset all filters and logs
504
+ */
505
+ reset() {
506
+ this.contentFilters.reset();
507
+ this.toneProcessors.reset();
508
+ this.actionLog = [];
509
+ this.interceptCount = 0;
510
+ }
511
+
512
+ /**
513
+ * CLI command handlers for integration
514
+ */
515
+ static createCliHandlers(hooks) {
516
+ return {
517
+ 'filter-check': (filePath, content) => {
518
+ return hooks.interceptDocumentGeneration(filePath, content);
519
+ },
520
+
521
+ 'filter-stats': () => {
522
+ return hooks.getFilterStats();
523
+ },
524
+
525
+ 'filter-config': (newConfig) => {
526
+ if (newConfig) {
527
+ hooks.updatePreferences(newConfig);
528
+ return { updated: true, config: hooks.settings };
529
+ }
530
+ return hooks.settings;
531
+ },
532
+
533
+ 'filter-reset': () => {
534
+ hooks.reset();
535
+ return { reset: true };
536
+ },
537
+ };
538
+ }
539
+ }
540
+
541
+ export default FilterIntegrationHooks;
542
+ export { FilterIntegrationHooks };