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,825 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * flow-gate-confidence.js
5
+ *
6
+ * Phase 4.3: Quality Gate Confidence System
7
+ *
8
+ * Analyzes AI responses to detect confidence levels.
9
+ * Don't auto-apply low-confidence changes.
10
+ *
11
+ * Usage:
12
+ * node flow-gate-confidence.js analyze "<response text>"
13
+ * node flow-gate-confidence.js check --file <file>
14
+ * node flow-gate-confidence.js stats
15
+ *
16
+ * @module flow-gate-confidence
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ // ============================================================
23
+ // Imports
24
+ // ============================================================
25
+
26
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
27
+
28
+ const {
29
+ getConfig,
30
+ parseFlags,
31
+ info,
32
+ success,
33
+ warn,
34
+ error,
35
+ color,
36
+ outputJson,
37
+ printHeader,
38
+ printSection,
39
+ safeJsonParse
40
+ } = require('./flow-utils');
41
+
42
+ // ============================================================
43
+ // Constants
44
+ // ============================================================
45
+
46
+ /**
47
+ * High confidence markers - indicate the model is sure.
48
+ */
49
+ const HIGH_CONFIDENCE_MARKERS = [
50
+ // Direct confidence statements
51
+ "I'm confident",
52
+ "I am confident",
53
+ "This will work",
54
+ "This is correct",
55
+ "This is the right",
56
+ "Straightforward",
57
+ "Simple fix",
58
+ "Standard approach",
59
+ "Best practice",
60
+ "Recommended way",
61
+
62
+ // Certainty indicators
63
+ "Definitely",
64
+ "Certainly",
65
+ "Absolutely",
66
+ "Without a doubt",
67
+ "Clearly",
68
+ "Obviously",
69
+
70
+ // Knowledge indicators
71
+ "I know that",
72
+ "This is because",
73
+ "The reason is",
74
+ "According to the docs",
75
+ "Per the documentation",
76
+
77
+ // Action confidence
78
+ "Here's the solution",
79
+ "The fix is",
80
+ "You should",
81
+ "You need to",
82
+ "Make sure to"
83
+ ];
84
+
85
+ /**
86
+ * Low confidence markers - indicate uncertainty.
87
+ */
88
+ const LOW_CONFIDENCE_MARKERS = [
89
+ // Uncertainty hedges
90
+ "I think",
91
+ "I believe",
92
+ "I assume",
93
+ "I suppose",
94
+ "I guess",
95
+ "I'm not sure",
96
+ "I'm not certain",
97
+ "I'm not entirely sure",
98
+ "I'm unsure",
99
+
100
+ // Possibility hedges
101
+ "Might work",
102
+ "May work",
103
+ "Could work",
104
+ "Should work",
105
+ "Possibly",
106
+ "Perhaps",
107
+ "Maybe",
108
+ "Probably",
109
+
110
+ // Uncertainty indicators
111
+ "Not entirely sure",
112
+ "Not completely certain",
113
+ "Hard to say",
114
+ "Difficult to tell",
115
+ "Unclear",
116
+ "Uncertain",
117
+
118
+ // Conditional language
119
+ "If I understand correctly",
120
+ "If I'm not mistaken",
121
+ "Unless I'm wrong",
122
+ "Assuming that",
123
+ "Depending on",
124
+
125
+ // Exploration language
126
+ "Let me try",
127
+ "We could try",
128
+ "One option might be",
129
+ "Worth trying",
130
+ "Experiment with",
131
+
132
+ // Risk indicators
133
+ "Risky",
134
+ "Potentially problematic",
135
+ "Might break",
136
+ "Could cause issues",
137
+ "Watch out for"
138
+ ];
139
+
140
+ /**
141
+ * Question markers - indicate the model needs more info.
142
+ */
143
+ const QUESTION_MARKERS = [
144
+ "Could you clarify",
145
+ "Can you confirm",
146
+ "Do you want",
147
+ "Would you like",
148
+ "Should I",
149
+ "Which approach",
150
+ "What do you prefer",
151
+ "Is this what you meant",
152
+ "Am I understanding correctly"
153
+ ];
154
+
155
+ /**
156
+ * Confidence levels.
157
+ */
158
+ const CONFIDENCE_LEVELS = {
159
+ HIGH: 'high',
160
+ MEDIUM: 'medium',
161
+ LOW: 'low',
162
+ NEEDS_CLARIFICATION: 'needs_clarification'
163
+ };
164
+
165
+ /**
166
+ * Default gate confidence configuration.
167
+ */
168
+ const DEFAULT_GATE_CONFIG = {
169
+ enabled: true,
170
+ autoApplyThreshold: 0.7,
171
+ requireApprovalThreshold: 0.5,
172
+ blockThreshold: 0.3,
173
+ trackHistory: true,
174
+ maxHistoryEntries: 100
175
+ };
176
+
177
+ // ============================================================
178
+ // State
179
+ // ============================================================
180
+
181
+ const STATE_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'gate-confidence.json');
182
+
183
+ /**
184
+ * Get default confidence state.
185
+ * @returns {Object} Default state
186
+ */
187
+ function getDefaultState() {
188
+ return {
189
+ history: [],
190
+ stats: {
191
+ totalAnalyzed: 0,
192
+ byLevel: {
193
+ high: 0,
194
+ medium: 0,
195
+ low: 0,
196
+ needs_clarification: 0
197
+ },
198
+ autoApplied: 0,
199
+ manualApproved: 0,
200
+ blocked: 0
201
+ }
202
+ };
203
+ }
204
+
205
+ let confidenceState = getDefaultState();
206
+
207
+ // ============================================================
208
+ // Configuration
209
+ // ============================================================
210
+
211
+ /**
212
+ * Get gate confidence configuration from config.json with defaults.
213
+ * @returns {Object} Gate confidence configuration
214
+ */
215
+ function getGateConfig() {
216
+ const config = getConfig();
217
+ return {
218
+ ...DEFAULT_GATE_CONFIG,
219
+ ...(config.gateConfidence || {})
220
+ };
221
+ }
222
+
223
+ // ============================================================
224
+ // State Management
225
+ // ============================================================
226
+
227
+ /**
228
+ * Load confidence state from file using safe JSON parsing.
229
+ */
230
+ function loadState() {
231
+ if (fs.existsSync(STATE_PATH)) {
232
+ const loaded = safeJsonParse(STATE_PATH, null);
233
+ if (loaded && typeof loaded === 'object') {
234
+ const defaults = getDefaultState();
235
+ // Validate structure before using
236
+ confidenceState = {
237
+ history: Array.isArray(loaded.history) ? loaded.history : [],
238
+ stats: {
239
+ ...defaults.stats,
240
+ ...(loaded.stats || {}),
241
+ byLevel: { ...defaults.stats.byLevel, ...(loaded.stats?.byLevel || {}) }
242
+ }
243
+ };
244
+ }
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Save confidence state to file.
250
+ */
251
+ function saveState() {
252
+ try {
253
+ const dir = path.dirname(STATE_PATH);
254
+ if (!fs.existsSync(dir)) {
255
+ fs.mkdirSync(dir, { recursive: true });
256
+ }
257
+ fs.writeFileSync(STATE_PATH, JSON.stringify(confidenceState, null, 2));
258
+ } catch (err) {
259
+ warn(`Could not save confidence state: ${err.message}`);
260
+ }
261
+ }
262
+
263
+ // ============================================================
264
+ // Confidence Analysis
265
+ // ============================================================
266
+
267
+ /**
268
+ * Analyze text for confidence level.
269
+ * @param {string} text - Text to analyze
270
+ * @param {Object} options - Analysis options
271
+ * @returns {Object} Confidence analysis result
272
+ */
273
+ function analyzeConfidence(text, options = {}) {
274
+ if (!text || typeof text !== 'string') {
275
+ return {
276
+ level: CONFIDENCE_LEVELS.LOW,
277
+ score: 0,
278
+ error: 'Invalid input'
279
+ };
280
+ }
281
+
282
+ const textLower = text.toLowerCase();
283
+ const analysis = {
284
+ highMarkers: [],
285
+ lowMarkers: [],
286
+ questionMarkers: [],
287
+ segments: []
288
+ };
289
+
290
+ // Find high confidence markers
291
+ for (const marker of HIGH_CONFIDENCE_MARKERS) {
292
+ if (textLower.includes(marker.toLowerCase())) {
293
+ analysis.highMarkers.push(marker);
294
+ }
295
+ }
296
+
297
+ // Find low confidence markers
298
+ for (const marker of LOW_CONFIDENCE_MARKERS) {
299
+ if (textLower.includes(marker.toLowerCase())) {
300
+ analysis.lowMarkers.push(marker);
301
+ }
302
+ }
303
+
304
+ // Find question markers
305
+ for (const marker of QUESTION_MARKERS) {
306
+ if (textLower.includes(marker.toLowerCase())) {
307
+ analysis.questionMarkers.push(marker);
308
+ }
309
+ }
310
+
311
+ // Calculate base score using normalized weights to prevent unbounded values
312
+ const totalMarkers = analysis.highMarkers.length + analysis.lowMarkers.length + analysis.questionMarkers.length;
313
+
314
+ let score;
315
+ if (totalMarkers === 0) {
316
+ // No markers found - neutral score
317
+ score = 0.5;
318
+ } else {
319
+ // Normalize weights based on total markers found (max influence capped)
320
+ const highInfluence = Math.min(analysis.highMarkers.length, 5) * 0.08; // Max +0.4
321
+ const lowInfluence = Math.min(analysis.lowMarkers.length, 5) * -0.1; // Max -0.5
322
+ const questionInfluence = Math.min(analysis.questionMarkers.length, 3) * -0.12; // Max -0.36
323
+
324
+ // Start from neutral (0.5) and adjust
325
+ score = 0.5 + highInfluence + lowInfluence + questionInfluence;
326
+
327
+ // Clamp to 0-1
328
+ score = Math.max(0, Math.min(1, score));
329
+ }
330
+
331
+ // Determine level
332
+ let level;
333
+ if (analysis.questionMarkers.length > 0) {
334
+ level = CONFIDENCE_LEVELS.NEEDS_CLARIFICATION;
335
+ } else if (score >= 0.7) {
336
+ level = CONFIDENCE_LEVELS.HIGH;
337
+ } else if (score >= 0.4) {
338
+ level = CONFIDENCE_LEVELS.MEDIUM;
339
+ } else {
340
+ level = CONFIDENCE_LEVELS.LOW;
341
+ }
342
+
343
+ // Analyze specific segments for more granular scoring
344
+ analysis.segments = analyzeSegments(text);
345
+
346
+ // Adjust score based on segment analysis
347
+ const segmentScores = analysis.segments.map(s => s.confidence);
348
+ if (segmentScores.length > 0) {
349
+ const avgSegmentScore = segmentScores.reduce((a, b) => a + b, 0) / segmentScores.length;
350
+ score = (score + avgSegmentScore) / 2; // Blend marker and segment scores
351
+ }
352
+
353
+ const result = {
354
+ level,
355
+ score: Math.round(score * 100) / 100,
356
+ markers: {
357
+ high: analysis.highMarkers,
358
+ low: analysis.lowMarkers,
359
+ questions: analysis.questionMarkers
360
+ },
361
+ segments: analysis.segments,
362
+ recommendation: getRecommendation(level, score),
363
+ timestamp: new Date().toISOString()
364
+ };
365
+
366
+ // Track in history if enabled
367
+ const config = getGateConfig();
368
+ if (config.trackHistory && options.track !== false) {
369
+ loadState();
370
+ confidenceState.stats.totalAnalyzed++;
371
+ confidenceState.stats.byLevel[level]++;
372
+ confidenceState.history.push({
373
+ score,
374
+ level,
375
+ timestamp: result.timestamp,
376
+ textPreview: text.slice(0, 100) + (text.length > 100 ? '...' : '')
377
+ });
378
+
379
+ // Keep only recent history
380
+ if (confidenceState.history.length > config.maxHistoryEntries) {
381
+ confidenceState.history = confidenceState.history.slice(-config.maxHistoryEntries);
382
+ }
383
+
384
+ saveState();
385
+ }
386
+
387
+ return result;
388
+ }
389
+
390
+ /**
391
+ * Analyze text segments for confidence.
392
+ * @param {string} text - Text to analyze
393
+ * @returns {Array} Segment analysis
394
+ */
395
+ function analyzeSegments(text) {
396
+ const segments = [];
397
+
398
+ // Split into paragraphs/sections
399
+ const paragraphs = text.split(/\n\n+/).filter(p => p.trim().length > 0);
400
+
401
+ for (let i = 0; i < paragraphs.length; i++) {
402
+ const paragraph = paragraphs[i].trim();
403
+
404
+ // Detect code blocks
405
+ if (paragraph.startsWith('```') || paragraph.startsWith(' ')) {
406
+ segments.push({
407
+ type: 'code',
408
+ confidence: 0.8, // Code blocks are generally confident
409
+ preview: paragraph.slice(0, 50)
410
+ });
411
+ continue;
412
+ }
413
+
414
+ // Analyze paragraph confidence
415
+ let confidence = 0.5;
416
+
417
+ // Check for hedging at start of paragraph
418
+ if (/^(I think|Maybe|Perhaps|Possibly|It might)/i.test(paragraph)) {
419
+ confidence -= 0.2;
420
+ }
421
+
422
+ // Check for confident starts
423
+ if (/^(This will|Here's|The solution|To fix)/i.test(paragraph)) {
424
+ confidence += 0.2;
425
+ }
426
+
427
+ // Check for explanations (usually confident)
428
+ if (/because|since|therefore|as a result/i.test(paragraph)) {
429
+ confidence += 0.1;
430
+ }
431
+
432
+ // Check for warnings/caveats
433
+ if (/warning|caution|note:|important:|be careful/i.test(paragraph)) {
434
+ confidence -= 0.1; // Not necessarily low confidence, but cautionary
435
+ }
436
+
437
+ segments.push({
438
+ type: 'text',
439
+ confidence: Math.max(0, Math.min(1, confidence)),
440
+ preview: paragraph.slice(0, 50)
441
+ });
442
+ }
443
+
444
+ return segments;
445
+ }
446
+
447
+ /**
448
+ * Get recommendation based on confidence.
449
+ * @param {string} level - Confidence level
450
+ * @param {number} score - Confidence score
451
+ * @returns {Object} Recommendation
452
+ */
453
+ function getRecommendation(level, score) {
454
+ const config = getGateConfig();
455
+
456
+ if (level === CONFIDENCE_LEVELS.NEEDS_CLARIFICATION) {
457
+ return {
458
+ action: 'ask',
459
+ message: 'The response contains questions - clarification needed before proceeding',
460
+ autoApply: false
461
+ };
462
+ }
463
+
464
+ if (score >= config.autoApplyThreshold) {
465
+ return {
466
+ action: 'auto-apply',
467
+ message: 'High confidence - safe to apply automatically',
468
+ autoApply: true
469
+ };
470
+ }
471
+
472
+ if (score >= config.requireApprovalThreshold) {
473
+ return {
474
+ action: 'approve',
475
+ message: 'Medium confidence - review before applying',
476
+ autoApply: false
477
+ };
478
+ }
479
+
480
+ if (score >= config.blockThreshold) {
481
+ return {
482
+ action: 'review',
483
+ message: 'Low confidence - careful review recommended',
484
+ autoApply: false
485
+ };
486
+ }
487
+
488
+ return {
489
+ action: 'block',
490
+ message: 'Very low confidence - do not apply without verification',
491
+ autoApply: false
492
+ };
493
+ }
494
+
495
+ // ============================================================
496
+ // Quality Gate Integration
497
+ // ============================================================
498
+
499
+ /**
500
+ * Check if a response should be auto-applied.
501
+ * @param {string} response - AI response text
502
+ * @returns {Object} Gate check result
503
+ */
504
+ function checkGate(response) {
505
+ const analysis = analyzeConfidence(response);
506
+ const config = getGateConfig();
507
+
508
+ return {
509
+ passed: analysis.score >= config.autoApplyThreshold,
510
+ confidence: analysis,
511
+ action: analysis.recommendation.action,
512
+ requiresApproval: !analysis.recommendation.autoApply
513
+ };
514
+ }
515
+
516
+ /**
517
+ * Valid decision types for recordDecision.
518
+ */
519
+ const VALID_DECISIONS = ['auto-apply', 'approved', 'blocked'];
520
+
521
+ /**
522
+ * Record a gate decision.
523
+ * @param {Object} params - Decision parameters
524
+ * @throws {Error} If decision is not a valid type
525
+ */
526
+ function recordDecision({ analysisId, decision, outcome }) {
527
+ // Validate decision type to prevent silent failures
528
+ if (!VALID_DECISIONS.includes(decision)) {
529
+ throw new Error(`Invalid decision type: ${decision}. Must be one of: ${VALID_DECISIONS.join(', ')}`);
530
+ }
531
+
532
+ loadState();
533
+
534
+ switch (decision) {
535
+ case 'auto-apply':
536
+ confidenceState.stats.autoApplied++;
537
+ break;
538
+ case 'approved':
539
+ confidenceState.stats.manualApproved++;
540
+ break;
541
+ case 'blocked':
542
+ confidenceState.stats.blocked++;
543
+ break;
544
+ }
545
+
546
+ saveState();
547
+ }
548
+
549
+ // ============================================================
550
+ // Statistics
551
+ // ============================================================
552
+
553
+ /**
554
+ * Get confidence statistics.
555
+ * @returns {Object} Statistics
556
+ */
557
+ function getStats() {
558
+ loadState();
559
+
560
+ const stats = { ...confidenceState.stats };
561
+
562
+ // Calculate additional metrics
563
+ const total = stats.totalAnalyzed || 1;
564
+ stats.percentages = {
565
+ high: ((stats.byLevel.high / total) * 100).toFixed(1),
566
+ medium: ((stats.byLevel.medium / total) * 100).toFixed(1),
567
+ low: ((stats.byLevel.low / total) * 100).toFixed(1),
568
+ needs_clarification: ((stats.byLevel.needs_clarification / total) * 100).toFixed(1)
569
+ };
570
+
571
+ // Calculate average score from history
572
+ if (confidenceState.history.length > 0) {
573
+ const scores = confidenceState.history.map(h => h.score);
574
+ stats.averageScore = (scores.reduce((a, b) => a + b, 0) / scores.length).toFixed(2);
575
+ stats.recentTrend = calculateTrend(confidenceState.history.slice(-20));
576
+ }
577
+
578
+ return stats;
579
+ }
580
+
581
+ /**
582
+ * Calculate confidence trend.
583
+ * @param {Array} history - Recent history entries
584
+ * @returns {string} Trend direction
585
+ */
586
+ function calculateTrend(history) {
587
+ if (history.length < 5) return 'insufficient_data';
588
+
589
+ const firstHalf = history.slice(0, Math.floor(history.length / 2));
590
+ const secondHalf = history.slice(Math.floor(history.length / 2));
591
+
592
+ const firstAvg = firstHalf.reduce((a, b) => a + b.score, 0) / firstHalf.length;
593
+ const secondAvg = secondHalf.reduce((a, b) => a + b.score, 0) / secondHalf.length;
594
+
595
+ const diff = secondAvg - firstAvg;
596
+
597
+ if (diff > 0.1) return 'improving';
598
+ if (diff < -0.1) return 'declining';
599
+ return 'stable';
600
+ }
601
+
602
+ // ============================================================
603
+ // CLI Output
604
+ // ============================================================
605
+
606
+ /**
607
+ * Print confidence analysis.
608
+ * @param {Object} analysis - Analysis result
609
+ */
610
+ function printAnalysis(analysis) {
611
+ printHeader('CONFIDENCE ANALYSIS');
612
+
613
+ // Score visualization
614
+ const scoreBar = '█'.repeat(Math.round(analysis.score * 20));
615
+ const emptyBar = '░'.repeat(20 - Math.round(analysis.score * 20));
616
+
617
+ const levelColor = analysis.level === 'high' ? success :
618
+ analysis.level === 'medium' ? warn :
619
+ analysis.level === 'low' ? error : info;
620
+
621
+ printSection('Score');
622
+ console.log(` ${scoreBar}${emptyBar} ${(analysis.score * 100).toFixed(0)}%`);
623
+ console.log(` Level: ${levelColor(analysis.level.toUpperCase())}`);
624
+
625
+ printSection('Markers Found');
626
+ if (analysis.markers.high.length > 0) {
627
+ console.log(` ${success('High confidence:')} ${analysis.markers.high.slice(0, 3).join(', ')}`);
628
+ }
629
+ if (analysis.markers.low.length > 0) {
630
+ console.log(` ${warn('Low confidence:')} ${analysis.markers.low.slice(0, 3).join(', ')}`);
631
+ }
632
+ if (analysis.markers.questions.length > 0) {
633
+ console.log(` ${info('Questions:')} ${analysis.markers.questions.slice(0, 3).join(', ')}`);
634
+ }
635
+
636
+ if (analysis.markers.high.length === 0 &&
637
+ analysis.markers.low.length === 0 &&
638
+ analysis.markers.questions.length === 0) {
639
+ console.log(color('dim', ' No specific markers found'));
640
+ }
641
+
642
+ printSection('Recommendation');
643
+ const actionIcon = analysis.recommendation.action === 'auto-apply' ? '✓' :
644
+ analysis.recommendation.action === 'approve' ? '?' :
645
+ analysis.recommendation.action === 'ask' ? '❓' : '✗';
646
+ console.log(` ${actionIcon} ${analysis.recommendation.message}`);
647
+ console.log(` ${color('dim', 'Auto-apply:')} ${analysis.recommendation.autoApply ? 'Yes' : 'No'}`);
648
+ }
649
+
650
+ /**
651
+ * Print statistics.
652
+ */
653
+ function printStats() {
654
+ const stats = getStats();
655
+
656
+ printHeader('CONFIDENCE STATISTICS');
657
+
658
+ printSection('Overview');
659
+ console.log(` ${color('dim', 'Total analyzed:')} ${stats.totalAnalyzed}`);
660
+ if (stats.averageScore) {
661
+ console.log(` ${color('dim', 'Average score:')} ${(stats.averageScore * 100).toFixed(0)}%`);
662
+ console.log(` ${color('dim', 'Recent trend:')} ${stats.recentTrend}`);
663
+ }
664
+
665
+ printSection('Distribution');
666
+ console.log(` ${success('High:')} ${stats.byLevel.high} (${stats.percentages.high}%)`);
667
+ console.log(` ${warn('Medium:')} ${stats.byLevel.medium} (${stats.percentages.medium}%)`);
668
+ console.log(` ${error('Low:')} ${stats.byLevel.low} (${stats.percentages.low}%)`);
669
+ console.log(` ${info('Needs clarification:')} ${stats.byLevel.needs_clarification} (${stats.percentages.needs_clarification}%)`);
670
+
671
+ printSection('Decisions');
672
+ console.log(` ${color('dim', 'Auto-applied:')} ${stats.autoApplied}`);
673
+ console.log(` ${color('dim', 'Manual approved:')} ${stats.manualApproved}`);
674
+ console.log(` ${color('dim', 'Blocked:')} ${stats.blocked}`);
675
+ }
676
+
677
+ // ============================================================
678
+ // Exports
679
+ // ============================================================
680
+
681
+ module.exports = {
682
+ // Core functions
683
+ analyzeConfidence,
684
+ checkGate,
685
+ recordDecision,
686
+ getStats,
687
+
688
+ // Configuration
689
+ getGateConfig,
690
+ CONFIDENCE_LEVELS,
691
+ HIGH_CONFIDENCE_MARKERS,
692
+ LOW_CONFIDENCE_MARKERS,
693
+ QUESTION_MARKERS,
694
+ DEFAULT_GATE_CONFIG
695
+ };
696
+
697
+ // ============================================================
698
+ // CLI Entry Point
699
+ // ============================================================
700
+
701
+ function main() {
702
+ const { positional, flags } = parseFlags(process.argv.slice(2));
703
+ const command = positional[0];
704
+
705
+ if (flags.help || !command) {
706
+ console.log(`
707
+ Usage: flow confidence <command> [options]
708
+
709
+ Commands:
710
+ analyze "<text>" Analyze text for confidence level
711
+ check --file <f> Check confidence of file contents
712
+ stats Show confidence statistics
713
+ reset Reset statistics
714
+
715
+ Options:
716
+ --json Output as JSON
717
+ --no-track Don't track in history
718
+ --help Show this help
719
+
720
+ Examples:
721
+ flow confidence analyze "I think this might work, but I'm not sure"
722
+ flow confidence analyze "This is the correct solution. Here's the fix:"
723
+ flow confidence check --file response.txt
724
+ flow confidence stats
725
+ `);
726
+ return;
727
+ }
728
+
729
+ switch (command) {
730
+ case 'analyze': {
731
+ const text = positional.slice(1).join(' ') || flags.text;
732
+
733
+ if (!text) {
734
+ error('Please provide text to analyze');
735
+ process.exit(1);
736
+ }
737
+
738
+ // Input length validation (prevent DoS)
739
+ if (text.length > 50000) {
740
+ error('Input text exceeds maximum length (50000 chars)');
741
+ process.exit(1);
742
+ }
743
+
744
+ const analysis = analyzeConfidence(text, { track: !flags['no-track'] });
745
+
746
+ if (flags.json) {
747
+ outputJson(analysis);
748
+ } else {
749
+ printAnalysis(analysis);
750
+ }
751
+ break;
752
+ }
753
+
754
+ case 'check': {
755
+ const file = flags.file || positional[1];
756
+
757
+ if (!file) {
758
+ error('Please provide a file with --file');
759
+ process.exit(1);
760
+ }
761
+
762
+ // Validate path is within project directory (prevent path traversal)
763
+ const filePath = path.resolve(file);
764
+ if (!filePath.startsWith(PROJECT_ROOT)) {
765
+ error('File must be within project directory');
766
+ process.exit(1);
767
+ }
768
+
769
+ if (!fs.existsSync(filePath)) {
770
+ error('File not found');
771
+ process.exit(1);
772
+ }
773
+
774
+ let content;
775
+ try {
776
+ content = fs.readFileSync(filePath, 'utf8');
777
+ } catch (err) {
778
+ error('Failed to read file');
779
+ process.exit(1);
780
+ }
781
+
782
+ const gateResult = checkGate(content);
783
+
784
+ if (flags.json) {
785
+ outputJson(gateResult);
786
+ } else {
787
+ printAnalysis(gateResult.confidence);
788
+ console.log('');
789
+ console.log(`Gate: ${gateResult.passed ? success('PASSED') : warn('REQUIRES APPROVAL')}`);
790
+ }
791
+ break;
792
+ }
793
+
794
+ case 'stats':
795
+ if (flags.json) {
796
+ outputJson(getStats());
797
+ } else {
798
+ printStats();
799
+ }
800
+ break;
801
+
802
+ case 'reset':
803
+ confidenceState = {
804
+ history: [],
805
+ stats: {
806
+ totalAnalyzed: 0,
807
+ byLevel: { high: 0, medium: 0, low: 0, needs_clarification: 0 },
808
+ autoApplied: 0,
809
+ manualApproved: 0,
810
+ blocked: 0
811
+ }
812
+ };
813
+ saveState();
814
+ success('Statistics reset');
815
+ break;
816
+
817
+ default:
818
+ error(`Unknown command: ${command}`);
819
+ process.exit(1);
820
+ }
821
+ }
822
+
823
+ if (require.main === module) {
824
+ main();
825
+ }