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,522 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Knowledge Router
5
+ *
6
+ * Auto-detects where learnings/corrections should be stored:
7
+ * - model-specific: Applies only to a specific LLM
8
+ * - skill: Related to a specific skill (nestjs, react, etc.)
9
+ * - project: Project-specific decisions
10
+ * - team: General patterns worthy of team sharing
11
+ *
12
+ * Implements "auto-detect + confirm" pattern:
13
+ * 1. Analyzes correction text and context
14
+ * 2. Suggests best route with confidence score
15
+ * 3. Asks user to confirm or choose alternative
16
+ *
17
+ * Part of v1.8.0 Team Collaboration
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+ const {
23
+ getConfig,
24
+ PATHS,
25
+ STATE_DIR,
26
+ colors,
27
+ color,
28
+ success,
29
+ warn,
30
+ error,
31
+ readFile,
32
+ writeFile,
33
+ fileExists,
34
+ printHeader
35
+ } = require('./flow-utils');
36
+
37
+ // Import from skill-learn and model-adapter to avoid duplication
38
+ const { appendLearning: appendSkillLearning, discoverSkills } = require('./flow-skill-learn');
39
+ const { storeSingleLearning: storeModelLearning, getCurrentModel } = require('./flow-model-adapter');
40
+
41
+ // Use shared memory database for proposals
42
+ const memoryDb = require('./flow-memory-db');
43
+
44
+ // Rules sync for Claude Code integration
45
+ const { syncDecisionsToRules } = require('./flow-rules-sync');
46
+
47
+ // ============================================================
48
+ // Route Detection
49
+ // ============================================================
50
+
51
+ /**
52
+ * Detect possible routes for a learning/correction
53
+ * @param {string} correction - The correction or learning text
54
+ * @param {object} context - Context about where this came from
55
+ * @returns {Array} Sorted array of route suggestions with confidence
56
+ */
57
+ function detectKnowledgeRoute(correction, context = {}) {
58
+ const routes = [];
59
+ const correctionLower = correction.toLowerCase();
60
+
61
+ // 1. Check if model-specific
62
+ const modelPatterns = [
63
+ { pattern: /claude|anthropic/i, model: 'claude' },
64
+ { pattern: /gemini|google/i, model: 'gemini' },
65
+ { pattern: /gpt|openai|chatgpt/i, model: 'openai' },
66
+ { pattern: /ollama|local|llama|qwen|deepseek|mistral|nemotron/i, model: 'local' }
67
+ ];
68
+
69
+ const modelMatch = modelPatterns.find(p =>
70
+ p.pattern.test(correction) || (context.currentModel && p.pattern.test(context.currentModel))
71
+ );
72
+
73
+ // Check for model-specific error patterns
74
+ const modelErrorIndicators = [
75
+ 'this model',
76
+ 'claude tends to',
77
+ 'gemini often',
78
+ 'when using',
79
+ 'with this llm',
80
+ 'model-specific'
81
+ ];
82
+
83
+ const hasModelIndicator = modelErrorIndicators.some(ind =>
84
+ correctionLower.includes(ind)
85
+ ) || context.errorWasModelSpecific;
86
+
87
+ if (modelMatch || hasModelIndicator) {
88
+ routes.push({
89
+ type: 'model-specific',
90
+ model: modelMatch?.model || context.currentModel || 'unknown',
91
+ confidence: hasModelIndicator ? 0.85 : 0.7,
92
+ description: `Store as ${modelMatch?.model || 'model'}-specific learning`
93
+ });
94
+ }
95
+
96
+ // 2. Check if skill-specific
97
+ const skillMatch = matchSkillFromContext(correction, context);
98
+ if (skillMatch) {
99
+ routes.push({
100
+ type: 'skill',
101
+ skill: skillMatch.name,
102
+ file: `.claude/skills/${skillMatch.name}/knowledge/learnings.md`,
103
+ confidence: skillMatch.confidence,
104
+ description: `Add to ${skillMatch.name} skill knowledge`
105
+ });
106
+ }
107
+
108
+ // 3. Check if project-specific
109
+ const projectPatterns = [
110
+ /this project|our codebase|in this repo/i,
111
+ /\bour api\b|\bour database\b|\bour schema\b/i,
112
+ /project.?specific|local rule/i
113
+ ];
114
+
115
+ // Also check for project name reference
116
+ const projectName = context.projectName || getConfig().projectName;
117
+ if (projectName) {
118
+ projectPatterns.push(new RegExp(projectName.replace(/[-_]/g, '[-_]?'), 'i'));
119
+ }
120
+
121
+ if (projectPatterns.some(p => p.test(correction))) {
122
+ routes.push({
123
+ type: 'project',
124
+ file: 'decisions.md',
125
+ confidence: 0.75,
126
+ description: 'Add to project decisions.md'
127
+ });
128
+ }
129
+
130
+ // 4. Check if general/team-worthy
131
+ const generalPatterns = [
132
+ /always|never|best practice/i,
133
+ /convention|standard|pattern/i,
134
+ /\bdo not\b|\bdon't\b.*\buse\b/i,
135
+ /prefer|avoid|instead of/i,
136
+ /rule of thumb|general rule/i
137
+ ];
138
+
139
+ if (generalPatterns.some(p => p.test(correction))) {
140
+ routes.push({
141
+ type: 'team',
142
+ scope: 'proposal',
143
+ confidence: 0.65,
144
+ description: 'Propose as team rule (requires approval)'
145
+ });
146
+ }
147
+
148
+ // 5. Default: local project decision
149
+ if (routes.length === 0) {
150
+ routes.push({
151
+ type: 'project',
152
+ file: 'decisions.md',
153
+ confidence: 0.5,
154
+ description: 'Add to project decisions.md (default)'
155
+ });
156
+ }
157
+
158
+ // Sort by confidence
159
+ return routes.sort((a, b) => b.confidence - a.confidence);
160
+ }
161
+
162
+ /**
163
+ * Match correction to installed skills based on file types and keywords
164
+ */
165
+ function matchSkillFromContext(correction, context) {
166
+ const config = getConfig();
167
+ const installedSkills = config.skills?.installed || [];
168
+
169
+ if (installedSkills.length === 0) return null;
170
+
171
+ // Skill detection patterns
172
+ const skillPatterns = {
173
+ nestjs: {
174
+ keywords: ['nestjs', 'nest.js', '@nestjs', 'module', 'controller', 'service', 'dto', 'typeorm', 'prisma'],
175
+ fileExtensions: ['.module.ts', '.controller.ts', '.service.ts', '.dto.ts', '.entity.ts']
176
+ },
177
+ react: {
178
+ keywords: ['react', 'component', 'hook', 'usestate', 'useeffect', 'jsx', 'tsx', 'props'],
179
+ fileExtensions: ['.tsx', '.jsx']
180
+ },
181
+ python: {
182
+ keywords: ['python', 'fastapi', 'django', 'flask', 'pydantic', 'pytest'],
183
+ fileExtensions: ['.py']
184
+ },
185
+ typescript: {
186
+ keywords: ['typescript', 'type', 'interface', 'generic', 'tsconfig'],
187
+ fileExtensions: ['.ts', '.tsx']
188
+ }
189
+ };
190
+
191
+ const correctionLower = correction.toLowerCase();
192
+ const filesModified = context.filesModified || [];
193
+
194
+ for (const skillName of installedSkills) {
195
+ const patterns = skillPatterns[skillName];
196
+ if (!patterns) continue;
197
+
198
+ // Check keywords
199
+ const keywordMatch = patterns.keywords.some(kw =>
200
+ correctionLower.includes(kw.toLowerCase())
201
+ );
202
+
203
+ // Check file extensions
204
+ const fileMatch = patterns.fileExtensions.some(ext =>
205
+ filesModified.some(f => f.endsWith(ext))
206
+ );
207
+
208
+ if (keywordMatch || fileMatch) {
209
+ return {
210
+ name: skillName,
211
+ confidence: keywordMatch && fileMatch ? 0.9 : keywordMatch ? 0.75 : 0.65
212
+ };
213
+ }
214
+ }
215
+
216
+ return null;
217
+ }
218
+
219
+ // ============================================================
220
+ // Route Handlers
221
+ // ============================================================
222
+
223
+ /**
224
+ * Store learning based on selected route
225
+ */
226
+ async function storeByRoute(correction, route, context = {}) {
227
+ switch (route.type) {
228
+ case 'model-specific':
229
+ return await storeModelSpecific(correction, route, context);
230
+
231
+ case 'skill':
232
+ return await storeSkillLearning(correction, route, context);
233
+
234
+ case 'project':
235
+ return await storeProjectDecision(correction, route, context);
236
+
237
+ case 'team':
238
+ return await createTeamProposal(correction, route, context);
239
+
240
+ default:
241
+ return { success: false, error: `Unknown route type: ${route.type}` };
242
+ }
243
+ }
244
+
245
+ async function storeModelSpecific(correction, route, context) {
246
+ // Use the centralized model-adapter module
247
+ const modelName = route.model || getCurrentModel();
248
+ return storeModelLearning(modelName, correction, context);
249
+ }
250
+
251
+ async function storeSkillLearning(correction, route, context) {
252
+ // Use the centralized skill-learn module
253
+ const skillPath = path.join(PATHS.skills, route.skill);
254
+
255
+ // Adapt context format for skill-learn's appendLearning
256
+ const skillContext = {
257
+ trigger: context.trigger || 'knowledge-router',
258
+ timestamp: new Date().toISOString(),
259
+ files: context.filesModified || [],
260
+ summary: correction.slice(0, 100) + (correction.length > 100 ? '...' : ''),
261
+ type: 'correction'
262
+ };
263
+
264
+ const success = appendSkillLearning(skillPath, skillContext);
265
+
266
+ if (success) {
267
+ return {
268
+ success: true,
269
+ file: path.join(PATHS.skills, route.skill, 'knowledge', 'learnings.md'),
270
+ message: `Added to ${route.skill} skill learnings`
271
+ };
272
+ }
273
+
274
+ return {
275
+ success: false,
276
+ error: `Failed to append learning to ${route.skill} skill`
277
+ };
278
+ }
279
+
280
+ async function storeProjectDecision(correction, route, context) {
281
+ const decisionsPath = PATHS.decisions;
282
+
283
+ let content = '';
284
+ if (fs.existsSync(decisionsPath)) {
285
+ content = fs.readFileSync(decisionsPath, 'utf-8');
286
+ } else {
287
+ content = `# Project Decisions
288
+
289
+ Coding conventions and project-specific rules.
290
+
291
+ ---
292
+
293
+ `;
294
+ }
295
+
296
+ const date = new Date().toISOString().split('T')[0];
297
+ const entry = `\n### ${date}
298
+
299
+ ${correction}
300
+
301
+ `;
302
+
303
+ content += entry;
304
+ fs.writeFileSync(decisionsPath, content);
305
+
306
+ // Sync to .claude/rules/ for Claude Code integration
307
+ syncDecisionsToRules();
308
+
309
+ return {
310
+ success: true,
311
+ file: decisionsPath,
312
+ message: 'Added to project decisions.md'
313
+ };
314
+ }
315
+
316
+ async function createTeamProposal(correction, route, context) {
317
+ const config = getConfig();
318
+
319
+ // Check if team features are enabled
320
+ if (!config.team?.enabled) {
321
+ return {
322
+ success: false,
323
+ error: 'Team features not enabled. Use `./scripts/flow team login` to enable.',
324
+ fallback: 'project'
325
+ };
326
+ }
327
+
328
+ // Store in shared database (will sync when team sync runs)
329
+ const result = await memoryDb.createProposal({
330
+ rule: correction,
331
+ category: route.category || 'pattern',
332
+ rationale: context.originalError || 'Learned from correction',
333
+ sourceContext: context.taskId || null
334
+ });
335
+
336
+ return {
337
+ success: true,
338
+ proposalId: result.id,
339
+ message: 'Team proposal created. Will sync on next `./scripts/flow team sync`.'
340
+ };
341
+ }
342
+
343
+ // ============================================================
344
+ // Interactive Confirmation
345
+ // ============================================================
346
+
347
+ /**
348
+ * Format route for display
349
+ */
350
+ function formatRouteChoice(route, index) {
351
+ const confidence = Math.round(route.confidence * 100);
352
+ const prefix = index === 0 ? '(Recommended) ' : '';
353
+ const confStr = color('dim', `[${confidence}%]`);
354
+
355
+ switch (route.type) {
356
+ case 'model-specific':
357
+ return `${prefix}Model-specific (${route.model}) ${confStr}`;
358
+ case 'skill':
359
+ return `${prefix}Skill: ${route.skill} ${confStr}`;
360
+ case 'project':
361
+ return `${prefix}Project decisions.md ${confStr}`;
362
+ case 'team':
363
+ return `${prefix}Team proposal (requires approval) ${confStr}`;
364
+ default:
365
+ return `${prefix}${route.type} ${confStr}`;
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Print routes for user selection (non-interactive output)
371
+ */
372
+ function printRouteOptions(correction, routes) {
373
+ printHeader('Knowledge Router');
374
+
375
+ console.log(color('dim', 'Learning:'));
376
+ console.log(` "${correction.slice(0, 100)}${correction.length > 100 ? '...' : ''}"`);
377
+ console.log('');
378
+
379
+ console.log('Suggested destinations:');
380
+ routes.forEach((route, i) => {
381
+ console.log(` ${i + 1}. ${formatRouteChoice(route, i)}`);
382
+ console.log(color('dim', ` ${route.description}`));
383
+ });
384
+ console.log(` ${routes.length + 1}. Skip - don't save`);
385
+ console.log('');
386
+ }
387
+
388
+ // ============================================================
389
+ // CLI Interface
390
+ // ============================================================
391
+
392
+ function printUsage() {
393
+ console.log(`
394
+ Usage: flow-knowledge-router.js [command] [args]
395
+
396
+ Commands:
397
+ detect <text> Detect route for a learning (returns JSON)
398
+ store <text> <route> Store learning with specified route type
399
+ routes List all possible route types
400
+ --help Show this help
401
+
402
+ Route types:
403
+ model-specific Store as model-specific learning
404
+ skill:<name> Store in skill knowledge
405
+ project Store in project decisions.md
406
+ team Create team proposal
407
+
408
+ Examples:
409
+ node scripts/flow-knowledge-router.js detect "Always use explicit types"
410
+ node scripts/flow-knowledge-router.js store "Use kebab-case" project
411
+ node scripts/flow-knowledge-router.js store "Claude needs explicit types" model-specific
412
+ `);
413
+ }
414
+
415
+ // Main CLI handler
416
+ if (require.main === module) {
417
+ const args = process.argv.slice(2);
418
+ const command = args[0];
419
+
420
+ switch (command) {
421
+ case 'detect': {
422
+ const text = args.slice(1).join(' ');
423
+ if (!text) {
424
+ error('Please provide text to analyze');
425
+ process.exit(1);
426
+ }
427
+
428
+ const routes = detectKnowledgeRoute(text, {});
429
+ console.log(JSON.stringify(routes, null, 2));
430
+ break;
431
+ }
432
+
433
+ case 'store': {
434
+ const routeType = args[args.length - 1];
435
+ const text = args.slice(1, -1).join(' ');
436
+
437
+ if (!text || !routeType) {
438
+ error('Usage: store <text> <route-type>');
439
+ process.exit(1);
440
+ }
441
+
442
+ let route;
443
+ if (routeType.startsWith('skill:')) {
444
+ route = { type: 'skill', skill: routeType.split(':')[1] };
445
+ } else if (routeType === 'model-specific') {
446
+ route = { type: 'model-specific', model: 'unknown' };
447
+ } else {
448
+ route = { type: routeType };
449
+ }
450
+
451
+ storeByRoute(text, route, {}).then(result => {
452
+ if (result.success) {
453
+ success(result.message);
454
+ } else {
455
+ error(result.error);
456
+ process.exit(1);
457
+ }
458
+ });
459
+ break;
460
+ }
461
+
462
+ case 'routes': {
463
+ console.log(`
464
+ Available route types:
465
+
466
+ model-specific Learnings specific to a particular LLM
467
+ Stored in: .workflow/model-adapters/<model>.md
468
+
469
+ skill:<name> Learnings related to a specific skill
470
+ Stored in: .claude/skills/<name>/knowledge/learnings.md
471
+
472
+ project Project-specific decisions and conventions
473
+ Stored in: .workflow/state/decisions.md
474
+
475
+ team General patterns worthy of team sharing
476
+ Stored as: proposal for team approval (requires subscription)
477
+ `);
478
+ break;
479
+ }
480
+
481
+ case 'show': {
482
+ // Show routes for text without storing
483
+ const text = args.slice(1).join(' ');
484
+ if (!text) {
485
+ error('Please provide text to analyze');
486
+ process.exit(1);
487
+ }
488
+
489
+ const routes = detectKnowledgeRoute(text, {});
490
+ printRouteOptions(text, routes);
491
+ break;
492
+ }
493
+
494
+ case '--help':
495
+ case '-h':
496
+ printUsage();
497
+ break;
498
+
499
+ default:
500
+ if (command) {
501
+ error(`Unknown command: ${command}`);
502
+ }
503
+ printUsage();
504
+ process.exit(command ? 1 : 0);
505
+ }
506
+ }
507
+
508
+ // ============================================================
509
+ // Exports
510
+ // ============================================================
511
+
512
+ module.exports = {
513
+ detectKnowledgeRoute,
514
+ matchSkillFromContext,
515
+ storeByRoute,
516
+ storeModelSpecific,
517
+ storeSkillLearning,
518
+ storeProjectDecision,
519
+ createTeamProposal,
520
+ formatRouteChoice,
521
+ printRouteOptions
522
+ };