wogiflow 1.0.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.
Files changed (221) hide show
  1. package/.workflow/agents/reviewer.md +81 -0
  2. package/.workflow/agents/security.md +94 -0
  3. package/.workflow/agents/story-writer.md +58 -0
  4. package/.workflow/bridges/base-bridge.js +395 -0
  5. package/.workflow/bridges/claude-bridge.js +434 -0
  6. package/.workflow/bridges/index.js +130 -0
  7. package/.workflow/lib/assumption-detector.js +481 -0
  8. package/.workflow/lib/config-substitution.js +371 -0
  9. package/.workflow/lib/failure-categories.js +478 -0
  10. package/.workflow/state/app-map.md.template +15 -0
  11. package/.workflow/state/architecture.md.template +24 -0
  12. package/.workflow/state/component-index.json.template +5 -0
  13. package/.workflow/state/decisions.md.template +15 -0
  14. package/.workflow/state/feedback-patterns.md.template +9 -0
  15. package/.workflow/state/knowledge-sync.json.template +6 -0
  16. package/.workflow/state/progress.md.template +14 -0
  17. package/.workflow/state/ready.json.template +7 -0
  18. package/.workflow/state/request-log.md.template +14 -0
  19. package/.workflow/state/session-state.json.template +11 -0
  20. package/.workflow/state/stack.md.template +33 -0
  21. package/.workflow/state/testing.md.template +36 -0
  22. package/.workflow/templates/claude-md.hbs +257 -0
  23. package/.workflow/templates/correction-report.md +67 -0
  24. package/.workflow/templates/gemini-md.hbs +52 -0
  25. package/README.md +1802 -0
  26. package/bin/flow +205 -0
  27. package/lib/index.js +33 -0
  28. package/lib/installer.js +467 -0
  29. package/lib/release-channel.js +269 -0
  30. package/lib/skill-registry.js +526 -0
  31. package/lib/upgrader.js +401 -0
  32. package/lib/utils.js +305 -0
  33. package/package.json +64 -0
  34. package/scripts/flow +985 -0
  35. package/scripts/flow-adaptive-learning.js +1259 -0
  36. package/scripts/flow-aggregate.js +488 -0
  37. package/scripts/flow-archive +133 -0
  38. package/scripts/flow-auto-context.js +1015 -0
  39. package/scripts/flow-auto-learn.js +615 -0
  40. package/scripts/flow-bridge.js +223 -0
  41. package/scripts/flow-browser-suggest.js +316 -0
  42. package/scripts/flow-bug.js +247 -0
  43. package/scripts/flow-cascade.js +711 -0
  44. package/scripts/flow-changelog +85 -0
  45. package/scripts/flow-checkpoint.js +483 -0
  46. package/scripts/flow-cli.js +403 -0
  47. package/scripts/flow-code-intelligence.js +760 -0
  48. package/scripts/flow-complexity.js +502 -0
  49. package/scripts/flow-config-set.js +152 -0
  50. package/scripts/flow-constants.js +157 -0
  51. package/scripts/flow-context +152 -0
  52. package/scripts/flow-context-init.js +482 -0
  53. package/scripts/flow-context-monitor.js +384 -0
  54. package/scripts/flow-context-scoring.js +886 -0
  55. package/scripts/flow-correct.js +458 -0
  56. package/scripts/flow-damage-control.js +985 -0
  57. package/scripts/flow-deps +101 -0
  58. package/scripts/flow-diff.js +700 -0
  59. package/scripts/flow-done +151 -0
  60. package/scripts/flow-done.js +489 -0
  61. package/scripts/flow-durable-session.js +1541 -0
  62. package/scripts/flow-entropy-monitor.js +345 -0
  63. package/scripts/flow-export-profile +349 -0
  64. package/scripts/flow-export-scanner.js +1046 -0
  65. package/scripts/flow-figma-confirm.js +400 -0
  66. package/scripts/flow-figma-extract.js +496 -0
  67. package/scripts/flow-figma-generate.js +683 -0
  68. package/scripts/flow-figma-index.js +909 -0
  69. package/scripts/flow-figma-match.js +617 -0
  70. package/scripts/flow-figma-mcp-server.js +518 -0
  71. package/scripts/flow-figma-pipeline.js +414 -0
  72. package/scripts/flow-file-ops.js +301 -0
  73. package/scripts/flow-gate-confidence.js +825 -0
  74. package/scripts/flow-guided-edit.js +659 -0
  75. package/scripts/flow-health +185 -0
  76. package/scripts/flow-health.js +413 -0
  77. package/scripts/flow-hooks.js +556 -0
  78. package/scripts/flow-http-client.js +249 -0
  79. package/scripts/flow-hybrid-detect.js +167 -0
  80. package/scripts/flow-hybrid-interactive.js +591 -0
  81. package/scripts/flow-hybrid-test.js +152 -0
  82. package/scripts/flow-import-profile +439 -0
  83. package/scripts/flow-init +253 -0
  84. package/scripts/flow-instruction-richness.js +827 -0
  85. package/scripts/flow-jira-integration.js +579 -0
  86. package/scripts/flow-knowledge-router.js +522 -0
  87. package/scripts/flow-knowledge-sync.js +589 -0
  88. package/scripts/flow-linear-integration.js +631 -0
  89. package/scripts/flow-links.js +774 -0
  90. package/scripts/flow-log-manager.js +559 -0
  91. package/scripts/flow-loop-enforcer.js +1246 -0
  92. package/scripts/flow-loop-retry-learning.js +630 -0
  93. package/scripts/flow-lsp.js +923 -0
  94. package/scripts/flow-map-index +348 -0
  95. package/scripts/flow-map-sync +201 -0
  96. package/scripts/flow-memory-blocks.js +668 -0
  97. package/scripts/flow-memory-compactor.js +350 -0
  98. package/scripts/flow-memory-db.js +1110 -0
  99. package/scripts/flow-memory-sync.js +484 -0
  100. package/scripts/flow-metrics.js +353 -0
  101. package/scripts/flow-migrate-ids.js +370 -0
  102. package/scripts/flow-model-adapter.js +802 -0
  103. package/scripts/flow-model-router.js +884 -0
  104. package/scripts/flow-models.js +1231 -0
  105. package/scripts/flow-morning.js +517 -0
  106. package/scripts/flow-multi-approach.js +660 -0
  107. package/scripts/flow-new-feature +86 -0
  108. package/scripts/flow-onboard +1042 -0
  109. package/scripts/flow-orchestrate-llm.js +459 -0
  110. package/scripts/flow-orchestrate.js +3592 -0
  111. package/scripts/flow-output.js +123 -0
  112. package/scripts/flow-parallel-detector.js +399 -0
  113. package/scripts/flow-parallel-dispatch.js +987 -0
  114. package/scripts/flow-parallel.js +428 -0
  115. package/scripts/flow-pattern-enforcer.js +600 -0
  116. package/scripts/flow-prd-manager.js +282 -0
  117. package/scripts/flow-progress.js +323 -0
  118. package/scripts/flow-project-analyzer.js +975 -0
  119. package/scripts/flow-prompt-composer.js +487 -0
  120. package/scripts/flow-providers.js +1381 -0
  121. package/scripts/flow-queue.js +308 -0
  122. package/scripts/flow-ready +82 -0
  123. package/scripts/flow-ready.js +189 -0
  124. package/scripts/flow-regression.js +396 -0
  125. package/scripts/flow-response-parser.js +450 -0
  126. package/scripts/flow-resume.js +284 -0
  127. package/scripts/flow-rules-sync.js +439 -0
  128. package/scripts/flow-run-trace.js +718 -0
  129. package/scripts/flow-safety.js +587 -0
  130. package/scripts/flow-search +104 -0
  131. package/scripts/flow-security.js +481 -0
  132. package/scripts/flow-session-end +106 -0
  133. package/scripts/flow-session-end.js +437 -0
  134. package/scripts/flow-session-state.js +671 -0
  135. package/scripts/flow-setup-hooks +216 -0
  136. package/scripts/flow-setup-hooks.js +377 -0
  137. package/scripts/flow-skill-create.js +329 -0
  138. package/scripts/flow-skill-creator.js +572 -0
  139. package/scripts/flow-skill-generator.js +1046 -0
  140. package/scripts/flow-skill-learn.js +880 -0
  141. package/scripts/flow-skill-matcher.js +578 -0
  142. package/scripts/flow-spec-generator.js +820 -0
  143. package/scripts/flow-stack-wizard.js +895 -0
  144. package/scripts/flow-standup +162 -0
  145. package/scripts/flow-start +74 -0
  146. package/scripts/flow-start.js +235 -0
  147. package/scripts/flow-status +110 -0
  148. package/scripts/flow-status.js +301 -0
  149. package/scripts/flow-step-browser.js +83 -0
  150. package/scripts/flow-step-changelog.js +217 -0
  151. package/scripts/flow-step-comments.js +306 -0
  152. package/scripts/flow-step-complexity.js +234 -0
  153. package/scripts/flow-step-coverage.js +218 -0
  154. package/scripts/flow-step-knowledge.js +193 -0
  155. package/scripts/flow-step-pr-tests.js +364 -0
  156. package/scripts/flow-step-regression.js +89 -0
  157. package/scripts/flow-step-review.js +516 -0
  158. package/scripts/flow-step-security.js +162 -0
  159. package/scripts/flow-step-silent-failures.js +290 -0
  160. package/scripts/flow-step-simplifier.js +346 -0
  161. package/scripts/flow-story +105 -0
  162. package/scripts/flow-story.js +500 -0
  163. package/scripts/flow-suspend.js +252 -0
  164. package/scripts/flow-sync-daemon.js +654 -0
  165. package/scripts/flow-task-analyzer.js +606 -0
  166. package/scripts/flow-team-dashboard.js +748 -0
  167. package/scripts/flow-team-sync.js +752 -0
  168. package/scripts/flow-team.js +977 -0
  169. package/scripts/flow-tech-options.js +528 -0
  170. package/scripts/flow-templates.js +812 -0
  171. package/scripts/flow-tiered-learning.js +728 -0
  172. package/scripts/flow-trace +204 -0
  173. package/scripts/flow-transcript-chunking.js +1106 -0
  174. package/scripts/flow-transcript-digest.js +7918 -0
  175. package/scripts/flow-transcript-language.js +465 -0
  176. package/scripts/flow-transcript-parsing.js +1085 -0
  177. package/scripts/flow-transcript-stories.js +2194 -0
  178. package/scripts/flow-update-map +224 -0
  179. package/scripts/flow-utils.js +2242 -0
  180. package/scripts/flow-verification.js +644 -0
  181. package/scripts/flow-verify.js +1177 -0
  182. package/scripts/flow-voice-input.js +638 -0
  183. package/scripts/flow-watch +168 -0
  184. package/scripts/flow-workflow-steps.js +521 -0
  185. package/scripts/flow-workflow.js +1029 -0
  186. package/scripts/flow-worktree.js +489 -0
  187. package/scripts/hooks/adapters/base-adapter.js +102 -0
  188. package/scripts/hooks/adapters/claude-code.js +359 -0
  189. package/scripts/hooks/adapters/index.js +79 -0
  190. package/scripts/hooks/core/component-check.js +341 -0
  191. package/scripts/hooks/core/index.js +35 -0
  192. package/scripts/hooks/core/loop-check.js +241 -0
  193. package/scripts/hooks/core/session-context.js +294 -0
  194. package/scripts/hooks/core/task-gate.js +177 -0
  195. package/scripts/hooks/core/validation.js +230 -0
  196. package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
  197. package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
  198. package/scripts/hooks/entry/claude-code/session-end.js +87 -0
  199. package/scripts/hooks/entry/claude-code/session-start.js +46 -0
  200. package/scripts/hooks/entry/claude-code/stop.js +43 -0
  201. package/scripts/postinstall.js +139 -0
  202. package/templates/browser-test-flow.json +56 -0
  203. package/templates/bug-report.md +43 -0
  204. package/templates/component-detail.md +42 -0
  205. package/templates/component.stories.tsx +49 -0
  206. package/templates/context/constraints.md +83 -0
  207. package/templates/context/conventions.md +177 -0
  208. package/templates/context/stack.md +60 -0
  209. package/templates/correction-report.md +90 -0
  210. package/templates/feature-proposal.md +35 -0
  211. package/templates/hybrid/_base.md +254 -0
  212. package/templates/hybrid/_patterns.md +45 -0
  213. package/templates/hybrid/create-component.md +127 -0
  214. package/templates/hybrid/create-file.md +56 -0
  215. package/templates/hybrid/create-hook.md +145 -0
  216. package/templates/hybrid/create-service.md +70 -0
  217. package/templates/hybrid/fix-bug.md +33 -0
  218. package/templates/hybrid/modify-file.md +55 -0
  219. package/templates/story.md +68 -0
  220. package/templates/task.json +56 -0
  221. package/templates/trace.md +69 -0
@@ -0,0 +1,556 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - CLI Hooks Manager
5
+ *
6
+ * Multi-CLI hook manager supporting Claude Code, Gemini, Codex, etc.
7
+ *
8
+ * Usage:
9
+ * flow hooks setup # Install hooks for configured targets
10
+ * flow hooks setup --target claude-code # Install for specific CLI
11
+ * flow hooks remove # Remove all hooks
12
+ * flow hooks remove --target claude-code
13
+ * flow hooks status # Show hook status
14
+ * flow hooks test <hook> # Test a hook with sample input
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const {
20
+ getProjectRoot,
21
+ getConfig,
22
+ color,
23
+ success,
24
+ warn,
25
+ error
26
+ } = require('./flow-utils');
27
+
28
+ const { getAdapter, getAllAdapters, getAvailableAdapters } = require('./hooks/adapters');
29
+
30
+ const PROJECT_ROOT = getProjectRoot();
31
+ const HOOK_MARKER = '// WOGI_FLOW_MANAGED_HOOKS';
32
+
33
+ // ============================================================
34
+ // Configuration
35
+ // ============================================================
36
+
37
+ /**
38
+ * Get hooks configuration
39
+ */
40
+ function getHooksConfig() {
41
+ const config = getConfig();
42
+ return config.hooks || {
43
+ enabled: true,
44
+ targets: ['claude-code'],
45
+ gracefulDegradation: true,
46
+ timeout: 5000,
47
+ rules: {
48
+ taskGating: { enabled: true, blockWithoutTask: true },
49
+ validation: { enabled: true, runAfterEdit: true },
50
+ loopEnforcement: { enabled: true },
51
+ componentReuse: { enabled: true, threshold: 80 },
52
+ sessionContext: { enabled: true, loadSuspendedTasks: true },
53
+ autoLogging: { enabled: true }
54
+ }
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Get target CLIs to install hooks for
60
+ */
61
+ function getTargets(specificTarget = null) {
62
+ if (specificTarget) {
63
+ return [specificTarget];
64
+ }
65
+ const config = getHooksConfig();
66
+ return config.targets || ['claude-code'];
67
+ }
68
+
69
+ // ============================================================
70
+ // Setup / Install
71
+ // ============================================================
72
+
73
+ /**
74
+ * Install hooks for a specific target CLI
75
+ */
76
+ function installForTarget(targetName) {
77
+ const adapter = getAdapter(targetName);
78
+ if (!adapter) {
79
+ error(`Unknown target: ${targetName}`);
80
+ return false;
81
+ }
82
+
83
+ if (!adapter.isAvailable()) {
84
+ warn(`${targetName} not detected in project (skipping)`);
85
+ return false;
86
+ }
87
+
88
+ console.log(` Installing hooks for ${targetName}...`);
89
+
90
+ const config = getHooksConfig();
91
+ const hooksConfig = adapter.generateConfig(config.rules, PROJECT_ROOT);
92
+
93
+ // For Claude Code, we need to merge into settings.local.json
94
+ if (targetName === 'claude-code') {
95
+ return installClaudeCodeHooks(adapter, hooksConfig);
96
+ }
97
+
98
+ // For other CLIs, implement their specific installation
99
+ warn(` ${targetName} installation not yet implemented`);
100
+ return false;
101
+ }
102
+
103
+ /**
104
+ * Install Claude Code hooks into settings.local.json
105
+ */
106
+ function installClaudeCodeHooks(adapter, hooksConfig) {
107
+ const configPath = adapter.getLocalConfigPath();
108
+ const configDir = path.dirname(configPath);
109
+
110
+ // Ensure .claude directory exists
111
+ if (!fs.existsSync(configDir)) {
112
+ fs.mkdirSync(configDir, { recursive: true });
113
+ }
114
+
115
+ // Read existing config
116
+ let existingConfig = {};
117
+ if (fs.existsSync(configPath)) {
118
+ try {
119
+ const content = fs.readFileSync(configPath, 'utf-8');
120
+ existingConfig = JSON.parse(content);
121
+ } catch (err) {
122
+ warn(` Could not parse existing config, will create new`);
123
+ }
124
+ }
125
+
126
+ // Check if we're overwriting non-Wogi hooks
127
+ if (existingConfig.hooks && !existingConfig._wogiFlowManaged) {
128
+ // Backup existing
129
+ const backupPath = configPath + '.backup';
130
+ fs.writeFileSync(backupPath, JSON.stringify(existingConfig, null, 2));
131
+ warn(` Backed up existing hooks to ${path.basename(backupPath)}`);
132
+ }
133
+
134
+ // Merge hooks
135
+ const newConfig = {
136
+ ...existingConfig,
137
+ hooks: hooksConfig.hooks,
138
+ _wogiFlowManaged: true,
139
+ _wogiFlowVersion: '1.0.0'
140
+ };
141
+
142
+ // Write config
143
+ fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2));
144
+ console.log(` ${color('green', '✓')} Hooks written to ${path.relative(PROJECT_ROOT, configPath)}`);
145
+
146
+ return true;
147
+ }
148
+
149
+ /**
150
+ * Install hooks for all configured targets
151
+ */
152
+ function setupHooks(options = {}) {
153
+ const { target, force } = options;
154
+
155
+ console.log(color('cyan', '🪝 Setting Up CLI Hooks'));
156
+ console.log('');
157
+
158
+ const config = getHooksConfig();
159
+
160
+ if (!config.enabled) {
161
+ warn('Hooks are disabled in config (hooks.enabled = false)');
162
+ return;
163
+ }
164
+
165
+ const targets = getTargets(target);
166
+ const results = [];
167
+
168
+ for (const t of targets) {
169
+ const success = installForTarget(t);
170
+ results.push({ target: t, success });
171
+ }
172
+
173
+ console.log('');
174
+
175
+ const successCount = results.filter(r => r.success).length;
176
+ if (successCount > 0) {
177
+ success(`Installed hooks for ${successCount} CLI${successCount !== 1 ? 's' : ''}`);
178
+ } else {
179
+ warn('No hooks were installed');
180
+ }
181
+
182
+ // Show what was configured
183
+ console.log('');
184
+ console.log(color('dim', 'Configured rules:'));
185
+ for (const [rule, settings] of Object.entries(config.rules || {})) {
186
+ const enabled = settings.enabled !== false;
187
+ const icon = enabled ? color('green', '✓') : color('dim', '○');
188
+ console.log(` ${icon} ${rule}`);
189
+ }
190
+ }
191
+
192
+ // ============================================================
193
+ // Remove
194
+ // ============================================================
195
+
196
+ /**
197
+ * Remove hooks for a specific target
198
+ */
199
+ function removeForTarget(targetName) {
200
+ const adapter = getAdapter(targetName);
201
+ if (!adapter) {
202
+ warn(`Unknown target: ${targetName}`);
203
+ return false;
204
+ }
205
+
206
+ console.log(` Removing hooks for ${targetName}...`);
207
+
208
+ if (targetName === 'claude-code') {
209
+ return removeClaudeCodeHooks(adapter);
210
+ }
211
+
212
+ warn(` ${targetName} removal not yet implemented`);
213
+ return false;
214
+ }
215
+
216
+ /**
217
+ * Remove Claude Code hooks from settings.local.json
218
+ */
219
+ function removeClaudeCodeHooks(adapter) {
220
+ const configPath = adapter.getLocalConfigPath();
221
+
222
+ if (!fs.existsSync(configPath)) {
223
+ console.log(` ${color('dim', '-')} No config file found`);
224
+ return true;
225
+ }
226
+
227
+ try {
228
+ const content = fs.readFileSync(configPath, 'utf-8');
229
+ const config = JSON.parse(content);
230
+
231
+ if (!config._wogiFlowManaged) {
232
+ warn(` Config not managed by Wogi Flow (skipping)`);
233
+ return false;
234
+ }
235
+
236
+ // Remove hooks and our marker
237
+ delete config.hooks;
238
+ delete config._wogiFlowManaged;
239
+ delete config._wogiFlowVersion;
240
+
241
+ // Check if config is now empty
242
+ if (Object.keys(config).length === 0) {
243
+ fs.unlinkSync(configPath);
244
+ console.log(` ${color('green', '✓')} Removed ${path.basename(configPath)}`);
245
+ } else {
246
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
247
+ console.log(` ${color('green', '✓')} Removed hooks from ${path.basename(configPath)}`);
248
+ }
249
+
250
+ // Restore backup if exists
251
+ const backupPath = configPath + '.backup';
252
+ if (fs.existsSync(backupPath)) {
253
+ const backupContent = fs.readFileSync(backupPath, 'utf-8');
254
+ const backupConfig = JSON.parse(backupContent);
255
+ if (backupConfig.hooks) {
256
+ const finalConfig = { ...config, hooks: backupConfig.hooks };
257
+ fs.writeFileSync(configPath, JSON.stringify(finalConfig, null, 2));
258
+ fs.unlinkSync(backupPath);
259
+ console.log(` ${color('green', '✓')} Restored original hooks from backup`);
260
+ }
261
+ }
262
+
263
+ return true;
264
+ } catch (err) {
265
+ error(` Failed to remove: ${err.message}`);
266
+ return false;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Remove all hooks
272
+ */
273
+ function removeHooks(options = {}) {
274
+ const { target } = options;
275
+
276
+ console.log(color('cyan', '🪝 Removing CLI Hooks'));
277
+ console.log('');
278
+
279
+ const targets = getTargets(target);
280
+ const results = [];
281
+
282
+ for (const t of targets) {
283
+ const success = removeForTarget(t);
284
+ results.push({ target: t, success });
285
+ }
286
+
287
+ console.log('');
288
+
289
+ const successCount = results.filter(r => r.success).length;
290
+ if (successCount > 0) {
291
+ success(`Removed hooks from ${successCount} CLI${successCount !== 1 ? 's' : ''}`);
292
+ }
293
+ }
294
+
295
+ // ============================================================
296
+ // Status
297
+ // ============================================================
298
+
299
+ /**
300
+ * Show hook status
301
+ */
302
+ function showStatus() {
303
+ console.log(color('cyan', '🪝 CLI Hooks Status'));
304
+ console.log('');
305
+
306
+ const config = getHooksConfig();
307
+
308
+ // Overall status
309
+ console.log(`Hooks enabled: ${config.enabled !== false ? color('green', 'Yes') : color('red', 'No')}`);
310
+ console.log(`Configured targets: ${(config.targets || ['claude-code']).join(', ')}`);
311
+ console.log('');
312
+
313
+ // Per-target status
314
+ console.log('Target Status:');
315
+ const allAdapters = getAllAdapters();
316
+
317
+ for (const [name, adapter] of Object.entries(allAdapters)) {
318
+ const available = adapter.isAvailable();
319
+ const installed = checkIfInstalled(adapter);
320
+
321
+ let status;
322
+ if (!available) {
323
+ status = color('dim', 'Not detected');
324
+ } else if (installed) {
325
+ status = color('green', 'Installed');
326
+ } else {
327
+ status = color('yellow', 'Available (not installed)');
328
+ }
329
+
330
+ console.log(` ${name}: ${status}`);
331
+ }
332
+
333
+ console.log('');
334
+
335
+ // Rule status
336
+ console.log('Rules:');
337
+ for (const [rule, settings] of Object.entries(config.rules || {})) {
338
+ const enabled = settings?.enabled !== false;
339
+ const icon = enabled ? color('green', '✓') : color('dim', '○');
340
+ console.log(` ${icon} ${rule}`);
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Check if hooks are installed for an adapter
346
+ */
347
+ function checkIfInstalled(adapter) {
348
+ if (adapter.name === 'claude-code') {
349
+ const configPath = adapter.getLocalConfigPath();
350
+ if (!fs.existsSync(configPath)) {
351
+ return false;
352
+ }
353
+ try {
354
+ const content = fs.readFileSync(configPath, 'utf-8');
355
+ const config = JSON.parse(content);
356
+ return config._wogiFlowManaged === true;
357
+ } catch {
358
+ return false;
359
+ }
360
+ }
361
+ return false;
362
+ }
363
+
364
+ // ============================================================
365
+ // Test
366
+ // ============================================================
367
+
368
+ /**
369
+ * Test a hook with sample input
370
+ */
371
+ async function testHook(hookName) {
372
+ console.log(color('cyan', `🧪 Testing Hook: ${hookName}`));
373
+ console.log('');
374
+
375
+ const testInputs = {
376
+ 'session-start': { hook_event_name: 'SessionStart', source: 'startup' },
377
+ 'pre-tool-use': {
378
+ hook_event_name: 'PreToolUse',
379
+ tool_name: 'Edit',
380
+ tool_input: { file_path: 'src/test.ts' }
381
+ },
382
+ 'post-tool-use': {
383
+ hook_event_name: 'PostToolUse',
384
+ tool_name: 'Edit',
385
+ tool_input: { file_path: 'src/test.ts' },
386
+ tool_response: { success: true }
387
+ },
388
+ 'stop': { hook_event_name: 'Stop' },
389
+ 'session-end': { hook_event_name: 'SessionEnd', reason: 'manual' }
390
+ };
391
+
392
+ const input = testInputs[hookName];
393
+ if (!input) {
394
+ error(`Unknown hook: ${hookName}`);
395
+ console.log('Available hooks: ' + Object.keys(testInputs).join(', '));
396
+ return;
397
+ }
398
+
399
+ console.log('Input:', JSON.stringify(input, null, 2));
400
+ console.log('');
401
+
402
+ // Run the hook
403
+ const hookPath = path.join(__dirname, 'hooks', 'entry', 'claude-code', `${hookName}.js`);
404
+ if (!fs.existsSync(hookPath)) {
405
+ error(`Hook script not found: ${hookPath}`);
406
+ return;
407
+ }
408
+
409
+ const { spawn } = require('child_process');
410
+ const proc = spawn('node', [hookPath], {
411
+ cwd: PROJECT_ROOT,
412
+ stdio: ['pipe', 'pipe', 'pipe']
413
+ });
414
+
415
+ proc.stdin.write(JSON.stringify(input));
416
+ proc.stdin.end();
417
+
418
+ let stdout = '';
419
+ let stderr = '';
420
+
421
+ proc.stdout.on('data', (data) => { stdout += data; });
422
+ proc.stderr.on('data', (data) => { stderr += data; });
423
+
424
+ proc.on('close', (code) => {
425
+ console.log(`Exit code: ${code}`);
426
+ if (stderr) {
427
+ console.log('Stderr:', stderr);
428
+ }
429
+ if (stdout) {
430
+ console.log('Output:');
431
+ try {
432
+ const output = JSON.parse(stdout);
433
+ console.log(JSON.stringify(output, null, 2));
434
+ } catch {
435
+ console.log(stdout);
436
+ }
437
+ }
438
+ });
439
+ }
440
+
441
+ // ============================================================
442
+ // Help
443
+ // ============================================================
444
+
445
+ function showHelp() {
446
+ console.log(`
447
+ Wogi Flow - CLI Hooks Manager
448
+
449
+ Manage hooks for AI CLI tools (Claude Code, Gemini, Codex, etc.)
450
+
451
+ Usage:
452
+ flow hooks setup Install hooks for configured targets
453
+ flow hooks setup --target X Install for specific CLI
454
+ flow hooks remove Remove all hooks
455
+ flow hooks remove --target X Remove for specific CLI
456
+ flow hooks status Show hook status
457
+ flow hooks test <hook> Test a hook
458
+
459
+ Available targets:
460
+ claude-code Claude Code CLI (primary)
461
+ gemini Gemini CLI (future)
462
+ codex Codex CLI (future)
463
+
464
+ Configuration:
465
+ Configure hooks in .workflow/config.json under "hooks":
466
+
467
+ {
468
+ "hooks": {
469
+ "enabled": true,
470
+ "targets": ["claude-code"],
471
+ "rules": {
472
+ "taskGating": { "enabled": true },
473
+ "validation": { "enabled": true },
474
+ "loopEnforcement": { "enabled": true },
475
+ "componentReuse": { "enabled": true },
476
+ "sessionContext": { "enabled": true },
477
+ "autoLogging": { "enabled": true }
478
+ }
479
+ }
480
+ }
481
+
482
+ Test hooks:
483
+ flow hooks test session-start
484
+ flow hooks test pre-tool-use
485
+ flow hooks test post-tool-use
486
+ flow hooks test stop
487
+ flow hooks test session-end
488
+ `);
489
+ }
490
+
491
+ // ============================================================
492
+ // CLI
493
+ // ============================================================
494
+
495
+ function main() {
496
+ const args = process.argv.slice(2);
497
+ const command = args[0];
498
+
499
+ // Parse options
500
+ const options = {};
501
+ for (let i = 1; i < args.length; i++) {
502
+ if (args[i] === '--target' && args[i + 1]) {
503
+ options.target = args[i + 1];
504
+ i++;
505
+ } else if (args[i] === '--force') {
506
+ options.force = true;
507
+ }
508
+ }
509
+
510
+ switch (command) {
511
+ case 'setup':
512
+ case 'install':
513
+ setupHooks(options);
514
+ break;
515
+ case 'remove':
516
+ case 'uninstall':
517
+ removeHooks(options);
518
+ break;
519
+ case 'status':
520
+ showStatus();
521
+ break;
522
+ case 'test':
523
+ testHook(args[1]);
524
+ break;
525
+ case 'help':
526
+ case '--help':
527
+ case '-h':
528
+ showHelp();
529
+ break;
530
+ default:
531
+ if (command) {
532
+ error(`Unknown command: ${command}`);
533
+ }
534
+ showHelp();
535
+ process.exit(command ? 1 : 0);
536
+ }
537
+ }
538
+
539
+ // ============================================================
540
+ // Exports
541
+ // ============================================================
542
+
543
+ module.exports = {
544
+ getHooksConfig,
545
+ setupHooks,
546
+ removeHooks,
547
+ showStatus,
548
+ testHook,
549
+ installForTarget,
550
+ removeForTarget,
551
+ checkIfInstalled
552
+ };
553
+
554
+ if (require.main === module) {
555
+ main();
556
+ }