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,659 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Guided Edit Mode
5
+ *
6
+ * Step-by-step guided editing for multi-file changes.
7
+ * Inspired by Augment Code's "Next Edit" feature.
8
+ *
9
+ * Use cases:
10
+ * - Large refactors (rename component across 20 files)
11
+ * - Library upgrades (update imports everywhere)
12
+ * - Schema changes (add field to entity + DTOs + validators)
13
+ *
14
+ * Usage:
15
+ * node scripts/flow-guided-edit.js start "rename Button to BaseButton"
16
+ * node scripts/flow-guided-edit.js next # Show next file
17
+ * node scripts/flow-guided-edit.js approve # Approve current
18
+ * node scripts/flow-guided-edit.js reject # Reject current
19
+ * node scripts/flow-guided-edit.js status # Show progress
20
+ * node scripts/flow-guided-edit.js abort # Cancel session
21
+ */
22
+
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+ const { execSync } = require('child_process');
26
+ const {
27
+ getProjectRoot,
28
+ getConfig,
29
+ PATHS,
30
+ color,
31
+ success,
32
+ warn,
33
+ error,
34
+ readFile,
35
+ writeFile,
36
+ writeJson
37
+ } = require('./flow-utils');
38
+
39
+ const PROJECT_ROOT = getProjectRoot();
40
+ const SESSION_FILE = path.join(PATHS.state, 'guided-edit-session.json');
41
+
42
+ // ============================================================
43
+ // Session Management
44
+ // ============================================================
45
+
46
+ /**
47
+ * Load current guided edit session
48
+ */
49
+ function loadSession() {
50
+ if (!fs.existsSync(SESSION_FILE)) {
51
+ return null;
52
+ }
53
+ try {
54
+ return JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Save guided edit session
62
+ */
63
+ function saveSession(session) {
64
+ writeJson(SESSION_FILE, session);
65
+ }
66
+
67
+ /**
68
+ * Clear guided edit session
69
+ */
70
+ function clearSession() {
71
+ if (fs.existsSync(SESSION_FILE)) {
72
+ fs.unlinkSync(SESSION_FILE);
73
+ }
74
+ }
75
+
76
+ // ============================================================
77
+ // File Analysis
78
+ // ============================================================
79
+
80
+ /**
81
+ * Extract search pattern from description
82
+ * Returns { search: string, replace: string, type: 'rename'|'find'|'pattern' }
83
+ */
84
+ function parseDescription(description) {
85
+ const desc = description.trim();
86
+
87
+ // Pattern: "rename X to Y"
88
+ const renameMatch = desc.match(/rename\s+['"]?(\w+)['"]?\s+to\s+['"]?(\w+)['"]?/i);
89
+ if (renameMatch) {
90
+ return {
91
+ type: 'rename',
92
+ search: renameMatch[1],
93
+ replace: renameMatch[2],
94
+ description: desc
95
+ };
96
+ }
97
+
98
+ // Pattern: "replace X with Y"
99
+ const replaceMatch = desc.match(/replace\s+['"]?([^'"]+)['"]?\s+with\s+['"]?([^'"]+)['"]?/i);
100
+ if (replaceMatch) {
101
+ return {
102
+ type: 'replace',
103
+ search: replaceMatch[1],
104
+ replace: replaceMatch[2],
105
+ description: desc
106
+ };
107
+ }
108
+
109
+ // Pattern: "find X" - just search
110
+ const findMatch = desc.match(/find\s+['"]?([^'"]+)['"]?/i);
111
+ if (findMatch) {
112
+ return {
113
+ type: 'find',
114
+ search: findMatch[1],
115
+ replace: null,
116
+ description: desc
117
+ };
118
+ }
119
+
120
+ // Pattern: "update X" - just search for X
121
+ const updateMatch = desc.match(/update\s+['"]?(\w+)['"]?/i);
122
+ if (updateMatch) {
123
+ return {
124
+ type: 'update',
125
+ search: updateMatch[1],
126
+ replace: null,
127
+ description: desc
128
+ };
129
+ }
130
+
131
+ // Default: treat entire description as search term
132
+ return {
133
+ type: 'search',
134
+ search: desc,
135
+ replace: null,
136
+ description: desc
137
+ };
138
+ }
139
+
140
+ /**
141
+ * Find all files containing the search pattern
142
+ */
143
+ function findAffectedFiles(search, options = {}) {
144
+ const config = getConfig();
145
+
146
+ // Determine source directory: options > config > src > project root
147
+ // But verify the directory exists before using it
148
+ let srcDir = null;
149
+
150
+ // Try options first
151
+ if (options.srcDir) {
152
+ srcDir = path.isAbsolute(options.srcDir) ? options.srcDir : path.join(PROJECT_ROOT, options.srcDir);
153
+ }
154
+
155
+ // Try config
156
+ if (!srcDir || !fs.existsSync(srcDir)) {
157
+ const configSrcDir = config.guidedEdit?.srcDir;
158
+ if (configSrcDir) {
159
+ const resolved = path.isAbsolute(configSrcDir) ? configSrcDir : path.join(PROJECT_ROOT, configSrcDir);
160
+ if (fs.existsSync(resolved)) {
161
+ srcDir = resolved;
162
+ }
163
+ }
164
+ }
165
+
166
+ // Fallback to src/ or project root
167
+ if (!srcDir || !fs.existsSync(srcDir)) {
168
+ const defaultSrc = path.join(PROJECT_ROOT, 'src');
169
+ srcDir = fs.existsSync(defaultSrc) ? defaultSrc : PROJECT_ROOT;
170
+ }
171
+
172
+ const extensions = options.extensions || config.guidedEdit?.extensions || ['ts', 'tsx', 'js', 'jsx', 'vue', 'svelte'];
173
+
174
+ const results = [];
175
+
176
+ try {
177
+ const extPattern = extensions.map(e => `--include="*.${e}"`).join(' ');
178
+ const output = execSync(
179
+ `grep -rl "${search}" ${extPattern} "${srcDir}" 2>/dev/null`,
180
+ { encoding: 'utf-8', timeout: 30000 }
181
+ );
182
+
183
+ const files = output.split('\n').filter(f => f.trim());
184
+
185
+ for (const file of files) {
186
+ try {
187
+ const content = fs.readFileSync(file, 'utf-8');
188
+ const lines = content.split('\n');
189
+ const matches = [];
190
+
191
+ for (let i = 0; i < lines.length; i++) {
192
+ if (lines[i].includes(search)) {
193
+ matches.push({
194
+ line: i + 1,
195
+ content: lines[i].trim().substring(0, 100)
196
+ });
197
+ }
198
+ }
199
+
200
+ results.push({
201
+ path: path.relative(PROJECT_ROOT, file),
202
+ absolutePath: file,
203
+ matchCount: matches.length,
204
+ matches: matches.slice(0, 5), // First 5 matches
205
+ status: 'pending'
206
+ });
207
+ } catch {
208
+ // Skip files that can't be read
209
+ }
210
+ }
211
+ } catch {
212
+ // No matches or grep failed
213
+ }
214
+
215
+ // Sort by match count (more matches first)
216
+ results.sort((a, b) => b.matchCount - a.matchCount);
217
+
218
+ return results;
219
+ }
220
+
221
+ /**
222
+ * Generate a preview of changes for a file
223
+ */
224
+ function generatePreview(file, search, replace) {
225
+ if (!replace) {
226
+ return { before: null, after: null, diff: null };
227
+ }
228
+
229
+ try {
230
+ const content = fs.readFileSync(file.absolutePath, 'utf-8');
231
+ const newContent = content.replace(new RegExp(search, 'g'), replace);
232
+
233
+ if (content === newContent) {
234
+ return { before: content, after: content, diff: null, unchanged: true };
235
+ }
236
+
237
+ // Generate simple diff
238
+ const oldLines = content.split('\n');
239
+ const newLines = newContent.split('\n');
240
+ const diff = [];
241
+
242
+ for (let i = 0; i < Math.max(oldLines.length, newLines.length); i++) {
243
+ if (oldLines[i] !== newLines[i]) {
244
+ if (oldLines[i]) diff.push(`- ${oldLines[i]}`);
245
+ if (newLines[i]) diff.push(`+ ${newLines[i]}`);
246
+ }
247
+ }
248
+
249
+ return {
250
+ before: content,
251
+ after: newContent,
252
+ diff: diff.slice(0, 20).join('\n') + (diff.length > 20 ? '\n...' : '')
253
+ };
254
+ } catch (err) {
255
+ return { error: err.message };
256
+ }
257
+ }
258
+
259
+ // ============================================================
260
+ // Session Operations
261
+ // ============================================================
262
+
263
+ /**
264
+ * Start a new guided edit session
265
+ */
266
+ function startSession(description, options = {}) {
267
+ const existing = loadSession();
268
+ if (existing) {
269
+ error('A guided edit session is already in progress');
270
+ console.log(color('dim', `Description: "${existing.description}"`));
271
+ console.log(color('dim', `Progress: ${existing.files.filter(f => f.status !== 'pending').length}/${existing.files.length}`));
272
+ console.log('');
273
+ console.log('Run: node scripts/flow-guided-edit.js abort to cancel');
274
+ console.log(' node scripts/flow-guided-edit.js status to see progress');
275
+ return null;
276
+ }
277
+
278
+ const parsed = parseDescription(description);
279
+ console.log(color('cyan', '🔍 Analyzing change...'));
280
+ console.log(` Type: ${parsed.type}`);
281
+ console.log(` Search: "${parsed.search}"`);
282
+ if (parsed.replace) {
283
+ console.log(` Replace: "${parsed.replace}"`);
284
+ }
285
+ console.log('');
286
+
287
+ const files = findAffectedFiles(parsed.search, options);
288
+
289
+ if (files.length === 0) {
290
+ warn(`No files found containing "${parsed.search}"`);
291
+ return null;
292
+ }
293
+
294
+ console.log(color('green', `Found ${files.length} file(s) to review:`));
295
+ for (const file of files.slice(0, 10)) {
296
+ console.log(` ${file.path} (${file.matchCount} match${file.matchCount > 1 ? 'es' : ''})`);
297
+ }
298
+ if (files.length > 10) {
299
+ console.log(color('dim', ` ... and ${files.length - 10} more`));
300
+ }
301
+ console.log('');
302
+
303
+ const session = {
304
+ id: `ge-${Date.now()}`,
305
+ description: parsed.description,
306
+ type: parsed.type,
307
+ search: parsed.search,
308
+ replace: parsed.replace,
309
+ files,
310
+ currentIndex: 0,
311
+ startedAt: new Date().toISOString(),
312
+ stats: {
313
+ approved: 0,
314
+ rejected: 0,
315
+ skipped: 0
316
+ }
317
+ };
318
+
319
+ saveSession(session);
320
+ success('Guided edit session started');
321
+ console.log('');
322
+ console.log('Commands:');
323
+ console.log(` ${color('cyan', 'next')} - Show next file to review`);
324
+ console.log(` ${color('green', 'approve')} - Approve and apply change`);
325
+ console.log(` ${color('yellow', 'reject')} - Reject and skip file`);
326
+ console.log(` ${color('dim', 'status')} - Show progress`);
327
+ console.log(` ${color('red', 'abort')} - Cancel session`);
328
+
329
+ return session;
330
+ }
331
+
332
+ /**
333
+ * Show the next file to review
334
+ */
335
+ function showNext() {
336
+ const session = loadSession();
337
+ if (!session) {
338
+ error('No guided edit session in progress');
339
+ return null;
340
+ }
341
+
342
+ // Find next pending file
343
+ const pending = session.files.filter(f => f.status === 'pending');
344
+ if (pending.length === 0) {
345
+ success('All files reviewed!');
346
+ showSummary(session);
347
+ return null;
348
+ }
349
+
350
+ const file = pending[0];
351
+ const preview = generatePreview(file, session.search, session.replace);
352
+
353
+ console.log(color('cyan', '─'.repeat(60)));
354
+ console.log(color('cyan', `📄 File ${session.files.length - pending.length + 1}/${session.files.length}`));
355
+ console.log(color('cyan', '─'.repeat(60)));
356
+ console.log(`Path: ${file.path}`);
357
+ console.log(`Matches: ${file.matchCount}`);
358
+ console.log('');
359
+
360
+ if (file.matches && file.matches.length > 0) {
361
+ console.log(color('dim', 'Match locations:'));
362
+ for (const match of file.matches) {
363
+ console.log(color('dim', ` Line ${match.line}: ${match.content}`));
364
+ }
365
+ console.log('');
366
+ }
367
+
368
+ if (preview.diff) {
369
+ console.log(color('yellow', 'Proposed changes:'));
370
+ console.log(preview.diff);
371
+ console.log('');
372
+ } else if (preview.unchanged) {
373
+ console.log(color('dim', '(No actual changes needed - pattern not found in replaceable context)'));
374
+ console.log('');
375
+ }
376
+
377
+ console.log(color('cyan', '─'.repeat(60)));
378
+ console.log(`[${color('green', 'a')}]pprove [${color('yellow', 'r')}]eject [${color('dim', 's')}]kip [${color('red', 'q')}]uit`);
379
+
380
+ return { session, file, preview };
381
+ }
382
+
383
+ /**
384
+ * Approve the current file's changes
385
+ */
386
+ function approveFile() {
387
+ const session = loadSession();
388
+ if (!session) {
389
+ error('No guided edit session in progress');
390
+ return false;
391
+ }
392
+
393
+ const pending = session.files.filter(f => f.status === 'pending');
394
+ if (pending.length === 0) {
395
+ warn('No pending files to approve');
396
+ return false;
397
+ }
398
+
399
+ const file = pending[0];
400
+
401
+ // Apply the change if we have a replacement
402
+ if (session.replace) {
403
+ try {
404
+ const content = fs.readFileSync(file.absolutePath, 'utf-8');
405
+ const newContent = content.replace(new RegExp(session.search, 'g'), session.replace);
406
+ fs.writeFileSync(file.absolutePath, newContent);
407
+ } catch (err) {
408
+ error(`Failed to apply changes: ${err.message}`);
409
+ return false;
410
+ }
411
+ }
412
+
413
+ file.status = 'approved';
414
+ session.stats.approved++;
415
+ saveSession(session);
416
+
417
+ success(`Approved: ${file.path}`);
418
+ return true;
419
+ }
420
+
421
+ /**
422
+ * Reject the current file's changes
423
+ */
424
+ function rejectFile() {
425
+ const session = loadSession();
426
+ if (!session) {
427
+ error('No guided edit session in progress');
428
+ return false;
429
+ }
430
+
431
+ const pending = session.files.filter(f => f.status === 'pending');
432
+ if (pending.length === 0) {
433
+ warn('No pending files to reject');
434
+ return false;
435
+ }
436
+
437
+ const file = pending[0];
438
+ file.status = 'rejected';
439
+ session.stats.rejected++;
440
+ saveSession(session);
441
+
442
+ warn(`Rejected: ${file.path}`);
443
+ return true;
444
+ }
445
+
446
+ /**
447
+ * Skip the current file
448
+ */
449
+ function skipFile() {
450
+ const session = loadSession();
451
+ if (!session) {
452
+ error('No guided edit session in progress');
453
+ return false;
454
+ }
455
+
456
+ const pending = session.files.filter(f => f.status === 'pending');
457
+ if (pending.length === 0) {
458
+ warn('No pending files to skip');
459
+ return false;
460
+ }
461
+
462
+ const file = pending[0];
463
+ file.status = 'skipped';
464
+ session.stats.skipped++;
465
+ saveSession(session);
466
+
467
+ console.log(color('dim', `Skipped: ${file.path}`));
468
+ return true;
469
+ }
470
+
471
+ /**
472
+ * Show session status
473
+ */
474
+ function showStatus() {
475
+ const session = loadSession();
476
+ if (!session) {
477
+ console.log(color('dim', 'No guided edit session in progress'));
478
+ return null;
479
+ }
480
+
481
+ const pending = session.files.filter(f => f.status === 'pending').length;
482
+ const reviewed = session.files.length - pending;
483
+
484
+ console.log(color('cyan', '─'.repeat(40)));
485
+ console.log(color('cyan', '📊 Guided Edit Status'));
486
+ console.log(color('cyan', '─'.repeat(40)));
487
+ console.log(`Description: "${session.description}"`);
488
+ console.log(`Type: ${session.type}`);
489
+ console.log(`Search: "${session.search}"`);
490
+ if (session.replace) {
491
+ console.log(`Replace: "${session.replace}"`);
492
+ }
493
+ console.log('');
494
+ console.log(`Progress: ${reviewed}/${session.files.length} files reviewed`);
495
+ console.log(` ${color('green', '✓')} Approved: ${session.stats.approved}`);
496
+ console.log(` ${color('yellow', '✗')} Rejected: ${session.stats.rejected}`);
497
+ console.log(` ${color('dim', '○')} Skipped: ${session.stats.skipped}`);
498
+ console.log(` ${color('cyan', '•')} Pending: ${pending}`);
499
+ console.log('');
500
+
501
+ return session;
502
+ }
503
+
504
+ /**
505
+ * Show summary after completion
506
+ */
507
+ function showSummary(session) {
508
+ console.log('');
509
+ console.log(color('cyan', '═'.repeat(40)));
510
+ console.log(color('cyan', '📊 Session Complete'));
511
+ console.log(color('cyan', '═'.repeat(40)));
512
+ console.log(` ${color('green', '✓')} Approved: ${session.stats.approved}`);
513
+ console.log(` ${color('yellow', '✗')} Rejected: ${session.stats.rejected}`);
514
+ console.log(` ${color('dim', '○')} Skipped: ${session.stats.skipped}`);
515
+ console.log('');
516
+
517
+ if (session.stats.approved > 0) {
518
+ console.log(color('dim', 'Changes have been applied. Review and commit when ready.'));
519
+ }
520
+
521
+ // Clear session
522
+ clearSession();
523
+ }
524
+
525
+ /**
526
+ * Abort the current session
527
+ */
528
+ function abortSession() {
529
+ const session = loadSession();
530
+ if (!session) {
531
+ console.log(color('dim', 'No session to abort'));
532
+ return;
533
+ }
534
+
535
+ showStatus();
536
+ clearSession();
537
+ warn('Session aborted');
538
+ }
539
+
540
+ // ============================================================
541
+ // CLI
542
+ // ============================================================
543
+
544
+ function showHelp() {
545
+ console.log(`
546
+ Wogi Flow - Guided Edit Mode
547
+
548
+ Step-by-step guided editing for multi-file changes.
549
+
550
+ Usage:
551
+ flow guided-edit start "description" Start a new guided edit session
552
+ flow guided-edit next Show next file to review
553
+ flow guided-edit approve Approve and apply current file's changes
554
+ flow guided-edit reject Reject current file's changes
555
+ flow guided-edit skip Skip current file
556
+ flow guided-edit status Show progress
557
+ flow guided-edit abort Cancel session
558
+
559
+ Examples:
560
+ flow guided-edit start "rename Button to BaseButton"
561
+ flow guided-edit start "replace console.log with logger.debug"
562
+ flow guided-edit start "find deprecated API calls"
563
+
564
+ The session tracks progress across files. Use 'approve' to apply changes,
565
+ 'reject' to skip without changes, or 'skip' to review later.
566
+ `);
567
+ }
568
+
569
+ function main() {
570
+ const args = process.argv.slice(2);
571
+ const command = args[0];
572
+
573
+ if (!command || command === '--help' || command === '-h') {
574
+ showHelp();
575
+ process.exit(0);
576
+ }
577
+
578
+ switch (command) {
579
+ case 'start': {
580
+ const description = args.slice(1).join(' ');
581
+ if (!description) {
582
+ error('Please provide a description');
583
+ console.log('Example: flow guided-edit start "rename Button to BaseButton"');
584
+ process.exit(1);
585
+ }
586
+ startSession(description);
587
+ break;
588
+ }
589
+
590
+ case 'next':
591
+ case 'n':
592
+ showNext();
593
+ break;
594
+
595
+ case 'approve':
596
+ case 'a':
597
+ case 'yes':
598
+ case 'y':
599
+ if (approveFile()) {
600
+ showNext();
601
+ }
602
+ break;
603
+
604
+ case 'reject':
605
+ case 'r':
606
+ case 'no':
607
+ if (rejectFile()) {
608
+ showNext();
609
+ }
610
+ break;
611
+
612
+ case 'skip':
613
+ case 's':
614
+ if (skipFile()) {
615
+ showNext();
616
+ }
617
+ break;
618
+
619
+ case 'status':
620
+ showStatus();
621
+ break;
622
+
623
+ case 'abort':
624
+ case 'cancel':
625
+ case 'q':
626
+ abortSession();
627
+ break;
628
+
629
+ default:
630
+ error(`Unknown command: ${command}`);
631
+ showHelp();
632
+ process.exit(1);
633
+ }
634
+ }
635
+
636
+ // ============================================================
637
+ // Exports
638
+ // ============================================================
639
+
640
+ module.exports = {
641
+ loadSession,
642
+ saveSession,
643
+ clearSession,
644
+ parseDescription,
645
+ findAffectedFiles,
646
+ generatePreview,
647
+ startSession,
648
+ showNext,
649
+ approveFile,
650
+ rejectFile,
651
+ skipFile,
652
+ showStatus,
653
+ abortSession,
654
+ SESSION_FILE
655
+ };
656
+
657
+ if (require.main === module) {
658
+ main();
659
+ }