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,484 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Memory to Instructions Sync
5
+ *
6
+ * Promotes high-relevance facts and patterns to decisions.md
7
+ * This is the "self-editing core memory" feature.
8
+ *
9
+ * Commands:
10
+ * ./scripts/flow memory-sync - Check for patterns to promote
11
+ * ./scripts/flow memory-sync --auto - Auto-promote without asking
12
+ * ./scripts/flow memory-sync --list - List candidates only
13
+ * ./scripts/flow memory-sync --promote <id> - Promote specific fact
14
+ *
15
+ * Part of v1.8.0 - Automatic Memory Management
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const memoryDb = require('./flow-memory-db');
21
+
22
+ // Lazy-load to avoid circular dependency
23
+ let _syncDecisionsToRules = null;
24
+ function syncDecisionsToRules() {
25
+ if (!_syncDecisionsToRules) {
26
+ _syncDecisionsToRules = require('./flow-rules-sync').syncDecisionsToRules;
27
+ }
28
+ return _syncDecisionsToRules();
29
+ }
30
+
31
+ // ============================================================
32
+ // Configuration
33
+ // ============================================================
34
+
35
+ const PROJECT_ROOT = process.env.WOGI_PROJECT_ROOT || process.cwd();
36
+ const CONFIG_PATH = path.join(PROJECT_ROOT, '.workflow', 'config.json');
37
+ const DECISIONS_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'decisions.md');
38
+
39
+ function loadConfig() {
40
+ try {
41
+ if (fs.existsSync(CONFIG_PATH)) {
42
+ return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
43
+ }
44
+ } catch {}
45
+ return {};
46
+ }
47
+
48
+ // ============================================================
49
+ // Output Formatting
50
+ // ============================================================
51
+
52
+ function color(c, text) {
53
+ const colors = {
54
+ red: '\x1b[31m',
55
+ green: '\x1b[32m',
56
+ yellow: '\x1b[33m',
57
+ blue: '\x1b[34m',
58
+ cyan: '\x1b[36m',
59
+ gray: '\x1b[90m',
60
+ reset: '\x1b[0m'
61
+ };
62
+ return `${colors[c] || ''}${text}${colors.reset}`;
63
+ }
64
+
65
+ // ============================================================
66
+ // Pattern Analysis
67
+ // ============================================================
68
+
69
+ /**
70
+ * Extract patterns from facts by category
71
+ */
72
+ async function analyzePatterns() {
73
+ const facts = await memoryDb.getAllFacts();
74
+ const patterns = {};
75
+
76
+ for (const fact of facts) {
77
+ const category = fact.category || 'general';
78
+ if (!patterns[category]) {
79
+ patterns[category] = [];
80
+ }
81
+ patterns[category].push(fact);
82
+ }
83
+
84
+ // Sort each category by relevance/access count
85
+ for (const category of Object.keys(patterns)) {
86
+ patterns[category].sort((a, b) => {
87
+ const scoreA = (a.relevance_score || 0.5) * (1 + (a.access_count || 0) * 0.1);
88
+ const scoreB = (b.relevance_score || 0.5) * (1 + (b.access_count || 0) * 0.1);
89
+ return scoreB - scoreA;
90
+ });
91
+ }
92
+
93
+ return patterns;
94
+ }
95
+
96
+ /**
97
+ * Get current decisions.md content
98
+ */
99
+ function loadDecisions() {
100
+ try {
101
+ if (fs.existsSync(DECISIONS_PATH)) {
102
+ return fs.readFileSync(DECISIONS_PATH, 'utf-8');
103
+ }
104
+ } catch {}
105
+ return '';
106
+ }
107
+
108
+ /**
109
+ * Check if a fact is already in decisions.md
110
+ */
111
+ function isAlreadyInDecisions(fact, decisionsContent) {
112
+ // Simple check - see if key phrases exist
113
+ const keywords = fact.split(/\s+/)
114
+ .filter(w => w.length > 4)
115
+ .slice(0, 5);
116
+
117
+ let matches = 0;
118
+ for (const keyword of keywords) {
119
+ if (decisionsContent.toLowerCase().includes(keyword.toLowerCase())) {
120
+ matches++;
121
+ }
122
+ }
123
+
124
+ // If more than half of keywords match, likely already there
125
+ return matches > keywords.length / 2;
126
+ }
127
+
128
+ /**
129
+ * Format fact for decisions.md
130
+ */
131
+ function formatForDecisions(fact) {
132
+ // Map category to decisions.md section
133
+ const sectionMap = {
134
+ 'naming': 'Naming Conventions',
135
+ 'pattern': 'Coding Patterns',
136
+ 'architecture': 'Architecture Decisions',
137
+ 'styling': 'Styling Rules',
138
+ 'testing': 'Testing Conventions',
139
+ 'error-handling': 'Error Handling',
140
+ 'general': 'General Rules',
141
+ 'api': 'API Patterns',
142
+ 'component': 'Component Patterns'
143
+ };
144
+
145
+ const section = sectionMap[fact.category] || 'Learned Patterns';
146
+
147
+ return {
148
+ section,
149
+ rule: `- ${fact.fact}`,
150
+ source: fact.source_context ? `(Source: ${fact.source_context})` : '(Auto-promoted from memory)'
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Append rule to decisions.md
156
+ */
157
+ function appendToDecisions(formatted, decisionsContent) {
158
+ const lines = decisionsContent.split('\n');
159
+ let sectionIndex = -1;
160
+
161
+ // Find the section
162
+ for (let i = 0; i < lines.length; i++) {
163
+ if (lines[i].includes(formatted.section) && lines[i].startsWith('#')) {
164
+ sectionIndex = i;
165
+ break;
166
+ }
167
+ }
168
+
169
+ if (sectionIndex === -1) {
170
+ // Section doesn't exist, append at end
171
+ return decisionsContent.trim() + `\n\n## ${formatted.section}\n\n${formatted.rule}\n`;
172
+ }
173
+
174
+ // Find end of section (next heading or end of file)
175
+ let insertIndex = lines.length;
176
+ for (let i = sectionIndex + 1; i < lines.length; i++) {
177
+ if (lines[i].startsWith('#')) {
178
+ insertIndex = i;
179
+ break;
180
+ }
181
+ }
182
+
183
+ // Insert before next section
184
+ lines.splice(insertIndex, 0, formatted.rule);
185
+
186
+ return lines.join('\n');
187
+ }
188
+
189
+ // ============================================================
190
+ // Commands
191
+ // ============================================================
192
+
193
+ /**
194
+ * List promotion candidates
195
+ */
196
+ async function listCandidates(config) {
197
+ console.log(color('cyan', '\nPromotion Candidates'));
198
+ console.log('═'.repeat(70));
199
+
200
+ const candidates = await memoryDb.getPromotionCandidates({
201
+ minRelevance: config.automaticPromotion?.minRelevance || 0.8,
202
+ minAccessCount: config.automaticPromotion?.threshold || 3
203
+ });
204
+
205
+ const decisionsContent = loadDecisions();
206
+
207
+ if (candidates.length === 0) {
208
+ console.log(color('gray', '\nNo facts ready for promotion.'));
209
+ console.log('Requirements: 80%+ relevance and 3+ accesses\n');
210
+ return [];
211
+ }
212
+
213
+ // Filter out already-promoted
214
+ const notPromoted = candidates.filter(c =>
215
+ !c.promoted_to && !isAlreadyInDecisions(c.fact, decisionsContent)
216
+ );
217
+
218
+ if (notPromoted.length === 0) {
219
+ console.log(color('green', '\n✓ All high-relevance facts are already promoted!\n'));
220
+ return [];
221
+ }
222
+
223
+ console.log(`\nFound ${color('green', notPromoted.length)} candidates:\n`);
224
+
225
+ for (let i = 0; i < Math.min(notPromoted.length, 15); i++) {
226
+ const c = notPromoted[i];
227
+ const relevance = Math.round((c.relevance_score || 0) * 100);
228
+ const category = c.category || 'general';
229
+
230
+ console.log(`${color('blue', `[${i + 1}]`)} ${c.id}`);
231
+ console.log(` ${c.fact.substring(0, 70)}${c.fact.length > 70 ? '...' : ''}`);
232
+ console.log(` ${color('gray', `Category: ${category} | Relevance: ${relevance}% | Accessed: ${c.access_count || 0}x`)}\n`);
233
+ }
234
+
235
+ if (notPromoted.length > 15) {
236
+ console.log(color('gray', ` ... and ${notPromoted.length - 15} more\n`));
237
+ }
238
+
239
+ return notPromoted;
240
+ }
241
+
242
+ /**
243
+ * Promote a specific fact
244
+ */
245
+ async function promoteFact(factId, dryRun = false) {
246
+ // Get fact details
247
+ const facts = await memoryDb.getAllFacts();
248
+ const fact = facts.find(f => f.id === factId);
249
+
250
+ if (!fact) {
251
+ console.log(color('red', `✗ Fact not found: ${factId}`));
252
+ return false;
253
+ }
254
+
255
+ const decisionsContent = loadDecisions();
256
+
257
+ if (isAlreadyInDecisions(fact.fact, decisionsContent)) {
258
+ console.log(color('yellow', `⚠ Fact appears to already be in decisions.md`));
259
+ console.log(` ${fact.fact.substring(0, 60)}...`);
260
+ return false;
261
+ }
262
+
263
+ const formatted = formatForDecisions(fact);
264
+
265
+ console.log(`\n${color('cyan', 'Promoting to decisions.md:')}`);
266
+ console.log(` Section: ${formatted.section}`);
267
+ console.log(` Rule: ${formatted.rule}`);
268
+
269
+ if (dryRun) {
270
+ console.log(color('yellow', '\n [Dry run - no changes made]'));
271
+ return true;
272
+ }
273
+
274
+ // Update decisions.md
275
+ const newContent = appendToDecisions(formatted, decisionsContent);
276
+ fs.writeFileSync(DECISIONS_PATH, newContent);
277
+
278
+ // Sync to .claude/rules/ for Claude Code integration
279
+ syncDecisionsToRules();
280
+
281
+ // Mark fact as promoted
282
+ await memoryDb.markFactPromoted(factId, 'decisions.md');
283
+
284
+ console.log(color('green', '\n✓ Promoted successfully'));
285
+
286
+ return true;
287
+ }
288
+
289
+ /**
290
+ * Interactive promotion
291
+ */
292
+ async function interactiveSync(config) {
293
+ console.log(color('cyan', '\nMemory to Instructions Sync'));
294
+ console.log('═'.repeat(70));
295
+
296
+ const candidates = await listCandidates(config);
297
+
298
+ if (candidates.length === 0) {
299
+ return { promoted: 0 };
300
+ }
301
+
302
+ console.log(color('yellow', '\nNote: Use --auto to promote without prompts'));
303
+ console.log(' Use --promote <id> to promote specific fact\n');
304
+
305
+ return { candidates: candidates.length };
306
+ }
307
+
308
+ /**
309
+ * Auto-promote all candidates
310
+ */
311
+ async function autoPromote(config) {
312
+ console.log(color('cyan', '\nAuto-Promoting Patterns'));
313
+ console.log('═'.repeat(70));
314
+
315
+ const candidates = await memoryDb.getPromotionCandidates({
316
+ minRelevance: config.automaticPromotion?.minRelevance || 0.8,
317
+ minAccessCount: config.automaticPromotion?.threshold || 3
318
+ });
319
+
320
+ const decisionsContent = loadDecisions();
321
+ let promoted = 0;
322
+ let skipped = 0;
323
+ let currentContent = decisionsContent;
324
+
325
+ for (const candidate of candidates) {
326
+ if (candidate.promoted_to) {
327
+ skipped++;
328
+ continue;
329
+ }
330
+
331
+ if (isAlreadyInDecisions(candidate.fact, currentContent)) {
332
+ // Mark as promoted even if already there
333
+ await memoryDb.markFactPromoted(candidate.id, 'decisions.md');
334
+ skipped++;
335
+ continue;
336
+ }
337
+
338
+ const formatted = formatForDecisions(candidate);
339
+ currentContent = appendToDecisions(formatted, currentContent);
340
+
341
+ await memoryDb.markFactPromoted(candidate.id, 'decisions.md');
342
+ promoted++;
343
+
344
+ console.log(`${color('green', '✓')} Promoted: ${candidate.fact.substring(0, 50)}...`);
345
+ }
346
+
347
+ if (promoted > 0) {
348
+ fs.writeFileSync(DECISIONS_PATH, currentContent);
349
+ // Sync to .claude/rules/ for Claude Code integration
350
+ syncDecisionsToRules();
351
+ await memoryDb.recordMemoryMetric('auto_promote');
352
+ }
353
+
354
+ console.log(`\n${color('cyan', 'Summary')}`);
355
+ console.log(` Promoted: ${promoted}`);
356
+ console.log(` Skipped: ${skipped} (already in decisions.md)\n`);
357
+
358
+ return { promoted, skipped };
359
+ }
360
+
361
+ /**
362
+ * Show sync status
363
+ */
364
+ async function showStatus(config) {
365
+ console.log(color('cyan', '\nMemory Sync Status'));
366
+ console.log('═'.repeat(50));
367
+
368
+ const stats = await memoryDb.getStats();
369
+ const candidates = await memoryDb.getPromotionCandidates({
370
+ minRelevance: config.automaticPromotion?.minRelevance || 0.8,
371
+ minAccessCount: config.automaticPromotion?.threshold || 3
372
+ });
373
+
374
+ const autoEnabled = config.automaticPromotion?.enabled || false;
375
+ const requireApproval = config.automaticPromotion?.requireApproval !== false;
376
+
377
+ console.log(`\n${color('blue', 'Configuration')}`);
378
+ console.log(` Auto-promotion: ${autoEnabled ? color('green', 'Enabled') : color('gray', 'Disabled')}`);
379
+ console.log(` Require approval: ${requireApproval ? 'Yes' : 'No'}`);
380
+ console.log(` Min relevance: ${(config.automaticPromotion?.minRelevance || 0.8) * 100}%`);
381
+ console.log(` Min accesses: ${config.automaticPromotion?.threshold || 3}`);
382
+
383
+ console.log(`\n${color('blue', 'Memory Status')}`);
384
+ console.log(` Total facts: ${stats.facts.total}`);
385
+ console.log(` Candidates: ${candidates.filter(c => !c.promoted_to).length} ready`);
386
+ console.log(` Already promoted: ${candidates.filter(c => c.promoted_to).length}`);
387
+
388
+ console.log(`\n${color('blue', 'decisions.md')}`);
389
+ const decisionsContent = loadDecisions();
390
+ const lines = decisionsContent.split('\n').filter(l => l.trim().startsWith('-')).length;
391
+ console.log(` Rules defined: ${lines}`);
392
+
393
+ console.log('');
394
+ }
395
+
396
+ // ============================================================
397
+ // Main
398
+ // ============================================================
399
+
400
+ async function main() {
401
+ const args = process.argv.slice(2);
402
+ const config = loadConfig();
403
+
404
+ try {
405
+ if (args.includes('--list')) {
406
+ await listCandidates(config);
407
+ } else if (args.includes('--auto')) {
408
+ await autoPromote(config);
409
+ } else if (args.includes('--status')) {
410
+ await showStatus(config);
411
+ } else if (args.includes('--promote')) {
412
+ const idx = args.indexOf('--promote');
413
+ const factId = args[idx + 1];
414
+ if (!factId) {
415
+ console.error(color('red', 'Error: Missing fact ID'));
416
+ console.log('Usage: ./scripts/flow memory-sync --promote <fact_id>');
417
+ process.exit(1);
418
+ }
419
+ const dryRun = args.includes('--dry-run');
420
+ await promoteFact(factId, dryRun);
421
+ } else if (args.includes('--help') || args.includes('-h')) {
422
+ console.log(`
423
+ ${color('cyan', 'Memory to Instructions Sync')}
424
+
425
+ Promotes high-relevance facts from memory to decisions.md
426
+
427
+ Usage: ./scripts/flow memory-sync [options]
428
+
429
+ Options:
430
+ (none) Show candidates and status
431
+ --list List all promotion candidates
432
+ --auto Auto-promote all candidates
433
+ --status Show sync configuration and status
434
+ --promote <id> Promote a specific fact by ID
435
+ --dry-run With --promote, preview without changing
436
+ --help, -h Show this help
437
+
438
+ Promotion Criteria:
439
+ - Relevance score >= 80% (configurable)
440
+ - Access count >= 3 (configurable)
441
+ - Not already in decisions.md
442
+ - Not already marked as promoted
443
+
444
+ Configure in config.json:
445
+ "automaticPromotion": {
446
+ "enabled": true, // Enable auto-promotion
447
+ "threshold": 3, // Min access count
448
+ "minRelevance": 0.8, // Min relevance score
449
+ "requireApproval": true
450
+ }
451
+
452
+ Examples:
453
+ ./scripts/flow memory-sync # Check for patterns
454
+ ./scripts/flow memory-sync --auto # Auto-promote all
455
+ ./scripts/flow memory-sync --promote fact_123_abc
456
+ `);
457
+ } else {
458
+ await interactiveSync(config);
459
+ }
460
+ } catch (error) {
461
+ console.error(color('red', `Error: ${error.message}`));
462
+ if (process.env.DEBUG) console.error(error.stack);
463
+ process.exit(1);
464
+ } finally {
465
+ memoryDb.closeDatabase();
466
+ }
467
+ }
468
+
469
+ // ============================================================
470
+ // Exports (for use by session-end and other modules)
471
+ // ============================================================
472
+
473
+ module.exports = {
474
+ autoPromote,
475
+ listCandidates,
476
+ promoteFact,
477
+ showStatus,
478
+ loadConfig
479
+ };
480
+
481
+ // Run CLI if executed directly
482
+ if (require.main === module) {
483
+ main();
484
+ }