agileflow 2.78.0 → 2.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -69,6 +69,9 @@ class ClaudeCodeSetup extends BaseIdeSetup {
69
69
  await this.ensureDir(skillsTargetDir);
70
70
  console.log(chalk.dim(` - Skills directory: .claude/skills/ (for user-generated skills)`));
71
71
 
72
+ // Setup damage control hooks
73
+ await this.setupDamageControl(projectDir, agileflowDir, claudeDir, options);
74
+
72
75
  const totalCommands = commandResult.commands + agentResult.commands;
73
76
  const totalSubdirs =
74
77
  commandResult.subdirs + (agentResult.commands > 0 ? 1 : 0) + agentResult.subdirs;
@@ -86,6 +89,130 @@ class ClaudeCodeSetup extends BaseIdeSetup {
86
89
  subdirs: totalSubdirs,
87
90
  };
88
91
  }
92
+
93
+ /**
94
+ * Setup damage control hooks
95
+ * @param {string} projectDir - Project directory
96
+ * @param {string} agileflowDir - AgileFlow installation directory
97
+ * @param {string} claudeDir - .claude directory path
98
+ * @param {Object} options - Setup options
99
+ */
100
+ async setupDamageControl(projectDir, agileflowDir, claudeDir, options = {}) {
101
+ const damageControlSource = path.join(agileflowDir, 'scripts', 'damage-control');
102
+ const damageControlTarget = path.join(claudeDir, 'hooks', 'damage-control');
103
+
104
+ // Check if source exists
105
+ if (!fs.existsSync(damageControlSource)) {
106
+ console.log(chalk.dim(` - Damage control: source not found, skipping`));
107
+ return;
108
+ }
109
+
110
+ // Create hooks directory
111
+ await this.ensureDir(damageControlTarget);
112
+
113
+ // Copy hook scripts
114
+ const scripts = ['bash-tool-damage-control.js', 'edit-tool-damage-control.js', 'write-tool-damage-control.js'];
115
+ for (const script of scripts) {
116
+ const src = path.join(damageControlSource, script);
117
+ const dest = path.join(damageControlTarget, script);
118
+ if (fs.existsSync(src)) {
119
+ await fs.copy(src, dest);
120
+ }
121
+ }
122
+
123
+ // Copy patterns.yaml (preserve existing)
124
+ const patternsSource = path.join(damageControlSource, 'patterns.yaml');
125
+ const patternsTarget = path.join(damageControlTarget, 'patterns.yaml');
126
+ if (fs.existsSync(patternsSource) && !fs.existsSync(patternsTarget)) {
127
+ await fs.copy(patternsSource, patternsTarget);
128
+ console.log(chalk.dim(` - Damage control: patterns.yaml created`));
129
+ } else if (fs.existsSync(patternsTarget)) {
130
+ console.log(chalk.dim(` - Damage control: patterns.yaml preserved`));
131
+ }
132
+
133
+ // Setup hooks in settings.json (unless disabled)
134
+ if (!options.skipDamageControl) {
135
+ await this.setupDamageControlHooks(claudeDir);
136
+ console.log(chalk.dim(` - Damage control: hooks enabled`));
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Add PreToolUse hooks to settings.json
142
+ * @param {string} claudeDir - .claude directory path
143
+ */
144
+ async setupDamageControlHooks(claudeDir) {
145
+ const settingsPath = path.join(claudeDir, 'settings.json');
146
+ let settings = {};
147
+
148
+ // Load existing settings
149
+ if (fs.existsSync(settingsPath)) {
150
+ try {
151
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
152
+ } catch (e) {
153
+ settings = {};
154
+ }
155
+ }
156
+
157
+ // Initialize hooks structure
158
+ if (!settings.hooks) settings.hooks = {};
159
+ if (!settings.hooks.PreToolUse) settings.hooks.PreToolUse = [];
160
+
161
+ // Define damage control hooks
162
+ const damageControlHooks = [
163
+ {
164
+ matcher: 'Bash',
165
+ hooks: [{
166
+ type: 'command',
167
+ command: 'node $CLAUDE_PROJECT_DIR/.claude/hooks/damage-control/bash-tool-damage-control.js',
168
+ timeout: 5000
169
+ }]
170
+ },
171
+ {
172
+ matcher: 'Edit',
173
+ hooks: [{
174
+ type: 'command',
175
+ command: 'node $CLAUDE_PROJECT_DIR/.claude/hooks/damage-control/edit-tool-damage-control.js',
176
+ timeout: 5000
177
+ }]
178
+ },
179
+ {
180
+ matcher: 'Write',
181
+ hooks: [{
182
+ type: 'command',
183
+ command: 'node $CLAUDE_PROJECT_DIR/.claude/hooks/damage-control/write-tool-damage-control.js',
184
+ timeout: 5000
185
+ }]
186
+ }
187
+ ];
188
+
189
+ // Merge with existing hooks (don't duplicate)
190
+ for (const newHook of damageControlHooks) {
191
+ const existingIdx = settings.hooks.PreToolUse.findIndex(h => h.matcher === newHook.matcher);
192
+ if (existingIdx === -1) {
193
+ // No existing matcher, add new
194
+ settings.hooks.PreToolUse.push(newHook);
195
+ } else {
196
+ // Existing matcher, merge hooks array
197
+ const existing = settings.hooks.PreToolUse[existingIdx];
198
+ if (!existing.hooks) existing.hooks = [];
199
+
200
+ // Check if damage control hook already exists
201
+ const dcHook = newHook.hooks[0];
202
+ const hasDcHook = existing.hooks.some(h =>
203
+ h.type === 'command' && h.command && h.command.includes('damage-control')
204
+ );
205
+
206
+ if (!hasDcHook) {
207
+ // Add at beginning for priority
208
+ existing.hooks.unshift(dcHook);
209
+ }
210
+ }
211
+ }
212
+
213
+ // Write settings
214
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
215
+ }
89
216
  }
90
217
 
91
218
  module.exports = { ClaudeCodeSetup };