wogiflow 2.20.1 → 2.22.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 (255) hide show
  1. package/.claude/commands/wogi-finalize.md +83 -0
  2. package/.claude/rules/_internal/self-maintenance.md +1 -1
  3. package/.claude/settings.json +1 -1
  4. package/lib/commands/login.js +1 -1
  5. package/lib/installer.js +5 -5
  6. package/lib/release-channel.js +1 -1
  7. package/lib/skill-registry.js +3 -3
  8. package/lib/workspace-events.js +1 -1
  9. package/lib/workspace-gates.js +2 -2
  10. package/lib/workspace-intelligence.js +1 -1
  11. package/lib/workspace-routing.js +1 -1
  12. package/lib/workspace.js +16 -17
  13. package/package.json +2 -2
  14. package/scripts/base-workflow-step.js +2 -2
  15. package/scripts/flow-adaptive-learning.js +6 -6
  16. package/scripts/flow-api-index.js +2 -2
  17. package/scripts/flow-architect-pass.js +1 -1
  18. package/scripts/flow-ask.js +1 -1
  19. package/scripts/flow-assumption-detector.js +1 -1
  20. package/scripts/flow-audit-gates.js +38 -12
  21. package/scripts/flow-audit.js +4 -4
  22. package/scripts/flow-auto-context.js +3 -3
  23. package/scripts/flow-background.js +1 -1
  24. package/scripts/flow-best-of-n.js +7 -7
  25. package/scripts/flow-bridge.js +3 -3
  26. package/scripts/flow-bug.js +2 -2
  27. package/scripts/flow-bulk-loop.js +7 -7
  28. package/scripts/flow-cascade-completion.js +2 -2
  29. package/scripts/flow-cascade.js +1 -1
  30. package/scripts/flow-checkpoint.js +2 -2
  31. package/scripts/flow-clarifying-questions.js +2 -2
  32. package/scripts/flow-cli.js +2 -2
  33. package/scripts/flow-code-intelligence.js +4 -4
  34. package/scripts/flow-community-sync.js +6 -6
  35. package/scripts/flow-community.js +1 -1
  36. package/scripts/flow-completion-truth-gate.js +161 -5
  37. package/scripts/flow-complexity.js +1 -1
  38. package/scripts/flow-config-defaults.js +16 -4
  39. package/scripts/flow-config-interactive.js +2 -2
  40. package/scripts/flow-config-loader.js +1 -1
  41. package/scripts/flow-config-migrate.js +5 -6
  42. package/scripts/flow-consistency-check.js +5 -5
  43. package/scripts/flow-context-compact/expander.js +1 -1
  44. package/scripts/flow-context-compact/index.js +2 -2
  45. package/scripts/flow-context-compact/section-extractor.js +3 -3
  46. package/scripts/flow-context-compact/summary-tree.js +1 -1
  47. package/scripts/flow-context-estimator.js +1 -1
  48. package/scripts/flow-context-gatherer.js +6 -6
  49. package/scripts/flow-context-generator.js +6 -6
  50. package/scripts/flow-context-init.js +2 -2
  51. package/scripts/flow-context-manager.js +1 -1
  52. package/scripts/flow-context-manifest.js +1 -1
  53. package/scripts/flow-context-monitor.js +5 -5
  54. package/scripts/flow-context-orchestrator.js +2 -2
  55. package/scripts/flow-context-scoring.js +4 -4
  56. package/scripts/flow-contract-scan.js +1 -1
  57. package/scripts/flow-correct.js +3 -3
  58. package/scripts/flow-damage-control.js +2 -2
  59. package/scripts/flow-deploy-gate.js +2 -2
  60. package/scripts/flow-deploy-history.js +1 -1
  61. package/scripts/flow-diff.js +3 -3
  62. package/scripts/flow-done-gates.js +1 -1
  63. package/scripts/flow-done.js +7 -7
  64. package/scripts/flow-durable-session.js +1 -1
  65. package/scripts/flow-entropy-monitor.js +3 -3
  66. package/scripts/flow-epics.js +5 -5
  67. package/scripts/flow-error-recovery.js +4 -4
  68. package/scripts/flow-eval-judge.js +5 -5
  69. package/scripts/flow-eval.js +7 -7
  70. package/scripts/flow-export-scanner.js +5 -5
  71. package/scripts/flow-extraction-review.js +1 -1
  72. package/scripts/flow-failure-learning.js +9 -9
  73. package/scripts/flow-feature.js +5 -5
  74. package/scripts/flow-figma-confirm.js +1 -1
  75. package/scripts/flow-figma-extract.js +2 -2
  76. package/scripts/flow-figma-index.js +2 -2
  77. package/scripts/flow-figma-match.js +1 -1
  78. package/scripts/flow-figma-mcp-server.js +3 -3
  79. package/scripts/flow-figma-orchestrator.js +1 -1
  80. package/scripts/flow-figma-registry.js +2 -2
  81. package/scripts/flow-function-index.js +2 -2
  82. package/scripts/flow-gate-confidence.js +2 -2
  83. package/scripts/flow-gate-telemetry.js +1 -1
  84. package/scripts/flow-gitignore.js +1 -1
  85. package/scripts/flow-guided-edit.js +3 -3
  86. package/scripts/flow-health.js +95 -8
  87. package/scripts/flow-hooks.js +3 -3
  88. package/scripts/flow-hybrid-detect.js +2 -2
  89. package/scripts/flow-hybrid-interactive.js +1 -1
  90. package/scripts/flow-hybrid-test.js +1 -1
  91. package/scripts/flow-hypothesis-generator.js +4 -4
  92. package/scripts/flow-instruction-richness.js +11 -11
  93. package/scripts/flow-intent-bootstrap.js +1 -1
  94. package/scripts/flow-intent-framing.js +1 -1
  95. package/scripts/flow-item-link.js +2 -2
  96. package/scripts/flow-knowledge-router.js +7 -7
  97. package/scripts/flow-knowledge-sync.js +3 -3
  98. package/scripts/flow-learning-orchestrator.js +1 -1
  99. package/scripts/flow-links.js +2 -2
  100. package/scripts/flow-log-manager.js +2 -2
  101. package/scripts/flow-logic-adversary.js +5 -4
  102. package/scripts/flow-long-input-chunking.js +1 -1
  103. package/scripts/flow-long-input-cli.js +3 -3
  104. package/scripts/flow-long-input.js +18 -18
  105. package/scripts/flow-loop-retry-learning.js +2 -2
  106. package/scripts/flow-lsp.js +4 -4
  107. package/scripts/flow-mcp-docs.js +1 -1
  108. package/scripts/flow-memory-blocks.js +5 -5
  109. package/scripts/flow-memory-compactor.js +3 -3
  110. package/scripts/flow-memory-db.js +4 -4
  111. package/scripts/flow-memory-sync.js +3 -3
  112. package/scripts/flow-metrics.js +2 -2
  113. package/scripts/flow-migrate-igr.js +2 -2
  114. package/scripts/flow-migrate.js +2 -2
  115. package/scripts/flow-model-adapter.js +4 -4
  116. package/scripts/flow-model-caller.js +8 -8
  117. package/scripts/flow-model-config.js +5 -5
  118. package/scripts/flow-model-profile.js +7 -7
  119. package/scripts/flow-model-router.js +5 -5
  120. package/scripts/flow-model-types.js +3 -3
  121. package/scripts/flow-models.js +8 -8
  122. package/scripts/flow-morning.js +1 -1
  123. package/scripts/flow-multi-approach.js +1 -1
  124. package/scripts/flow-orchestrate-context.js +2 -2
  125. package/scripts/flow-orchestrate-llm.js +4 -4
  126. package/scripts/flow-orchestrate-rollback.js +1 -1
  127. package/scripts/flow-orchestrate-state.js +6 -6
  128. package/scripts/flow-orchestrate-templates.js +1 -1
  129. package/scripts/flow-orchestrate-validation.js +2 -2
  130. package/scripts/flow-orchestrate-validator.js +1 -1
  131. package/scripts/flow-orchestrate.js +25 -25
  132. package/scripts/flow-parallel.js +1 -1
  133. package/scripts/flow-pattern-enforcer.js +7 -7
  134. package/scripts/flow-pattern-extractor.js +3 -3
  135. package/scripts/flow-peer-review.js +8 -8
  136. package/scripts/flow-pending.js +1 -1
  137. package/scripts/flow-permissions.js +1 -1
  138. package/scripts/flow-phased-task.js +1 -1
  139. package/scripts/flow-plan.js +1 -1
  140. package/scripts/flow-prd-manager.js +2 -2
  141. package/scripts/flow-product-scanner.js +2 -2
  142. package/scripts/flow-progress-tracker.js +2 -2
  143. package/scripts/flow-progress.js +1 -1
  144. package/scripts/flow-project-analyzer.js +3 -3
  145. package/scripts/flow-prompt-capture.js +2 -2
  146. package/scripts/flow-prompt-composer.js +3 -3
  147. package/scripts/flow-prompt-template.js +4 -4
  148. package/scripts/flow-providers.js +31 -23
  149. package/scripts/flow-queue.js +1 -1
  150. package/scripts/flow-registry-manager.js +4 -4
  151. package/scripts/flow-regression.js +1 -1
  152. package/scripts/flow-response-parser.js +1 -1
  153. package/scripts/flow-resume.js +1 -1
  154. package/scripts/flow-review-passes/index.js +2 -2
  155. package/scripts/flow-review-passes/integration.js +3 -3
  156. package/scripts/flow-review-passes/logic.js +3 -3
  157. package/scripts/flow-review-passes/security.js +2 -2
  158. package/scripts/flow-review-passes/structure.js +1 -1
  159. package/scripts/flow-review.js +11 -11
  160. package/scripts/flow-revision-tracker.js +2 -2
  161. package/scripts/flow-roadmap.js +2 -2
  162. package/scripts/flow-run-trace.js +1 -1
  163. package/scripts/flow-safety.js +3 -3
  164. package/scripts/flow-scanner-base.js +1 -1
  165. package/scripts/flow-scenario-engine.js +7 -7
  166. package/scripts/flow-schema-drift.js +4 -3
  167. package/scripts/flow-section-index.js +2 -2
  168. package/scripts/flow-section-resolver.js +4 -4
  169. package/scripts/flow-semantic-match.js +3 -3
  170. package/scripts/flow-session-end.js +56 -0
  171. package/scripts/flow-session-learning.js +2 -2
  172. package/scripts/flow-setup-hooks.js +1 -1
  173. package/scripts/flow-skill-create.js +3 -3
  174. package/scripts/flow-skill-freshness.js +2 -2
  175. package/scripts/flow-skill-generator.js +6 -6
  176. package/scripts/flow-skill-learn.js +7 -7
  177. package/scripts/flow-skill-matcher.js +2 -2
  178. package/scripts/flow-solution-optimizer.js +1 -1
  179. package/scripts/flow-spec-generator.js +5 -5
  180. package/scripts/flow-spec-verifier.js +2 -2
  181. package/scripts/flow-stack-wizard.js +6 -6
  182. package/scripts/flow-standards-checker.js +8 -8
  183. package/scripts/flow-standards-gate.js +4 -4
  184. package/scripts/flow-standards-learner.js +2 -2
  185. package/scripts/flow-start.js +9 -9
  186. package/scripts/flow-stats-collector.js +2 -2
  187. package/scripts/flow-status.js +1 -1
  188. package/scripts/flow-step-changelog.js +3 -3
  189. package/scripts/flow-step-complexity.js +1 -1
  190. package/scripts/flow-step-coverage.js +3 -3
  191. package/scripts/flow-step-knowledge.js +2 -2
  192. package/scripts/flow-step-pr-tests.js +2 -2
  193. package/scripts/flow-step-regression.js +3 -3
  194. package/scripts/flow-step-review.js +5 -5
  195. package/scripts/flow-story.js +2 -2
  196. package/scripts/flow-strict-adherence.js +2 -2
  197. package/scripts/flow-structure-sensor.js +283 -0
  198. package/scripts/flow-sync-anonymizer.js +3 -3
  199. package/scripts/flow-task-checkpoint.js +2 -2
  200. package/scripts/flow-task-classifier.js +2 -2
  201. package/scripts/flow-task-completion-summary.js +1 -1
  202. package/scripts/flow-task-enforcer.js +5 -5
  203. package/scripts/flow-tech-debt.js +3 -3
  204. package/scripts/flow-template-extractor.js +3 -3
  205. package/scripts/flow-templates.js +1 -1
  206. package/scripts/flow-test-api.js +12 -12
  207. package/scripts/flow-test-discovery.js +9 -9
  208. package/scripts/flow-test-generate.js +5 -5
  209. package/scripts/flow-test-integrity.js +3 -3
  210. package/scripts/flow-test-ui.js +8 -8
  211. package/scripts/flow-testing-deps.js +4 -4
  212. package/scripts/flow-tiered-learning.js +3 -3
  213. package/scripts/flow-todowrite-sync.js +1 -1
  214. package/scripts/flow-trap-zone.js +1 -1
  215. package/scripts/flow-verification-profile.js +9 -9
  216. package/scripts/flow-verify.js +2 -2
  217. package/scripts/flow-version-check.js +2 -2
  218. package/scripts/flow-webmcp-generator.js +3 -3
  219. package/scripts/flow-wiring-verifier.js +13 -13
  220. package/scripts/flow-worker-question-classifier.js +256 -0
  221. package/scripts/flow-workflow-steps.js +3 -3
  222. package/scripts/flow-workflow.js +1 -1
  223. package/scripts/flow-worktree.js +1 -1
  224. package/scripts/hooks/adapters/base-adapter.js +2 -2
  225. package/scripts/hooks/core/commit-log-gate.js +2 -2
  226. package/scripts/hooks/core/component-check.js +3 -3
  227. package/scripts/hooks/core/config-change.js +1 -1
  228. package/scripts/hooks/core/deploy-gate.js +2 -1
  229. package/scripts/hooks/core/git-safety-gate.js +1 -1
  230. package/scripts/hooks/core/instructions-loaded.js +1 -1
  231. package/scripts/hooks/core/loop-check.js +1 -1
  232. package/scripts/hooks/core/manager-boundary-gate.js +3 -2
  233. package/scripts/hooks/core/observation-capture.js +6 -6
  234. package/scripts/hooks/core/phase-gate.js +4 -4
  235. package/scripts/hooks/core/pre-compact.js +1 -1
  236. package/scripts/hooks/core/pre-tool-orchestrator.js +1 -1
  237. package/scripts/hooks/core/routing-gate.js +2 -84
  238. package/scripts/hooks/core/session-context.js +1 -1
  239. package/scripts/hooks/core/session-end.js +3 -3
  240. package/scripts/hooks/core/session-history.js +1 -1
  241. package/scripts/hooks/core/setup-handler.js +1 -1
  242. package/scripts/hooks/core/task-boundary-reset.js +2 -4
  243. package/scripts/hooks/core/task-completed.js +13 -7
  244. package/scripts/hooks/core/task-created.js +1 -1
  245. package/scripts/hooks/core/worktree-lifecycle.js +1 -1
  246. package/scripts/hooks/entry/claude-code/permission-denied.js +4 -2
  247. package/scripts/hooks/entry/claude-code/stop.js +60 -0
  248. package/scripts/hooks/entry/claude-code/user-prompt-submit.js +1 -1
  249. package/scripts/hooks/git/post-commit.js +1 -1
  250. package/scripts/postinstall.js +7 -7
  251. package/scripts/preuninstall.js +5 -5
  252. package/scripts/registries/component-registry.js +2 -2
  253. package/scripts/registries/contract-scanner.js +11 -11
  254. package/scripts/registries/schema-registry.js +5 -5
  255. package/scripts/registries/service-registry.js +9 -9
@@ -18,7 +18,7 @@ const { spawn } = require('node:child_process');
18
18
  const fs = require('node:fs');
19
19
  const path = require('node:path');
20
20
  const {
21
- getProjectRoot,
21
+ getProjectRoot: _getProjectRoot,
22
22
  safeJsonParse,
23
23
  fileExists,
24
24
  color,
@@ -14,14 +14,14 @@
14
14
  * flow best-of-n config Show Best-of-N configuration
15
15
  */
16
16
 
17
- const path = require('node:path');
17
+ const _path = require('node:path');
18
18
  const {
19
19
  getConfig,
20
- PATHS,
21
- readJson,
20
+ PATHS: _PATHS,
21
+ readJson: _readJson,
22
22
  validateTaskId
23
23
  } = require('./flow-utils');
24
- const { analyzeTask, analyzeComplexity } = require('./flow-task-analyzer');
24
+ const { analyzeComplexity } = require('./flow-task-analyzer');
25
25
 
26
26
  // ============================================================
27
27
  // Constants
@@ -108,7 +108,7 @@ function assessRisk(params) {
108
108
  factors.push(`Medium complexity + many files`);
109
109
  if (riskLevel !== 'high') riskLevel = 'medium';
110
110
  }
111
- } catch (err) {
111
+ } catch (_err) {
112
112
  // Non-critical — analyzer may not fully parse
113
113
  }
114
114
 
@@ -242,7 +242,7 @@ function parseSelectionResponse(response) {
242
242
  try {
243
243
  const parsed = JSON.parse(response.trim());
244
244
  if (parsed.winner && parsed.scores) return parsed;
245
- } catch (err) {
245
+ } catch (_err) {
246
246
  // Not direct JSON
247
247
  }
248
248
 
@@ -252,7 +252,7 @@ function parseSelectionResponse(response) {
252
252
  try {
253
253
  const parsed = JSON.parse(jsonMatch[0]);
254
254
  if (parsed.winner && parsed.scores) return parsed;
255
- } catch (err) {
255
+ } catch (_err) {
256
256
  // Failed to parse
257
257
  }
258
258
  }
@@ -11,8 +11,8 @@
11
11
 
12
12
  const fs = require('node:fs');
13
13
  const path = require('node:path');
14
- const { colors, getConfig, PROJECT_ROOT, PATHS } = require('./flow-utils');
15
- const { success, warn, error, info, printHeader } = require('./flow-output');
14
+ const { colors, getConfig, PROJECT_ROOT } = require('./flow-utils');
15
+ const { success, warn, error } = require('./flow-output');
16
16
 
17
17
  const { PACKAGE_PATHS } = require('./flow-paths');
18
18
  const BRIDGES_DIR = PACKAGE_PATHS.bridges;
@@ -129,7 +129,7 @@ async function syncBridge(options = {}) {
129
129
  let bridges;
130
130
  try {
131
131
  bridges = require(path.join(BRIDGES_DIR, 'index.js'));
132
- } catch (err) {
132
+ } catch (_err) {
133
133
  error('Bridges module not found.');
134
134
  console.error('Make sure .workflow/bridges/index.js exists.');
135
135
  process.exit(1);
@@ -19,7 +19,7 @@ const fs = require('node:fs');
19
19
  const path = require('node:path');
20
20
  const {
21
21
  PATHS,
22
- fileExists,
22
+ fileExists: _fileExists,
23
23
  dirExists,
24
24
  writeFile,
25
25
  writeJson,
@@ -269,7 +269,7 @@ Examples:
269
269
  const discoveredDuring = currentTask ? 'implementation' : null;
270
270
 
271
271
  // Determine priority
272
- const config = getConfig();
272
+ const _config = getConfig();
273
273
  const defaultPriority = getConfigValue('priorities.defaultPriority', 'P2');
274
274
 
275
275
  let priority = flags.priority;
@@ -14,19 +14,19 @@
14
14
  * - Graceful shutdown on Ctrl+C
15
15
  */
16
16
 
17
- const path = require('node:path');
17
+ const _path = require('node:path');
18
18
  const {
19
19
  PATHS,
20
20
  PROJECT_ROOT,
21
- getConfig,
21
+ getConfig: _getConfig,
22
22
  safeJsonParse,
23
23
  writeJson,
24
- fileExists,
24
+ fileExists: _fileExists,
25
25
  readFile
26
26
  } = require('./flow-utils')
27
27
  const { color, success, warn, error } = require('./flow-output');;
28
28
 
29
- const { loadDurableSession, saveDurableSession } = require('./flow-durable-session');
29
+ const { } = require('./flow-durable-session');
30
30
 
31
31
  // ============================================================================
32
32
  // Constants
@@ -140,7 +140,7 @@ function getInProgressTask() {
140
140
  const readyData = safeJsonParse(PATHS.ready, {});
141
141
  const inProgress = getArraySafe(readyData, 'inProgress');
142
142
  return inProgress.length > 0 ? inProgress[0] : null;
143
- } catch (err) {
143
+ } catch (_err) {
144
144
  return null;
145
145
  }
146
146
  }
@@ -163,7 +163,7 @@ function getNextReadyTask() {
163
163
  });
164
164
 
165
165
  return sorted[0];
166
- } catch (err) {
166
+ } catch (_err) {
167
167
  return null;
168
168
  }
169
169
  }
@@ -184,7 +184,7 @@ function getNextCapture() {
184
184
  );
185
185
 
186
186
  return captures.length > 0 ? captures[0] : null;
187
- } catch (err) {
187
+ } catch (_err) {
188
188
  return null;
189
189
  }
190
190
  }
@@ -21,7 +21,7 @@ let flowPlan;
21
21
  try {
22
22
  flowFeature = require('./flow-feature');
23
23
  flowPlan = require('./flow-plan');
24
- } catch (err) {
24
+ } catch (_err) {
25
25
  // Modules optional - graceful degradation
26
26
  flowFeature = null;
27
27
  flowPlan = null;
@@ -149,7 +149,7 @@ function allFeaturesComplete(epic) {
149
149
  if (!isComplete) return false;
150
150
  }
151
151
  return true;
152
- } catch (err) {
152
+ } catch (_err) {
153
153
  return false;
154
154
  }
155
155
  }
@@ -18,7 +18,7 @@
18
18
  const fs = require('node:fs');
19
19
  const path = require('node:path');
20
20
  const {
21
- PROJECT_ROOT,
21
+ PROJECT_ROOT: _PROJECT_ROOT,
22
22
  parseFlags,
23
23
  outputJson,
24
24
  color,
@@ -22,8 +22,8 @@
22
22
 
23
23
  const fs = require('node:fs');
24
24
  const path = require('node:path');
25
- const { execSync, spawnSync } = require('node:child_process');
26
- const { getProjectRoot, getConfig, colors: c, PATHS } = require('./flow-utils');
25
+ const { spawnSync } = require('node:child_process');
26
+ const { getConfig, colors: c, PATHS } = require('./flow-utils');
27
27
  const { success: printSuccess, warn: printWarn } = require('./flow-output');
28
28
 
29
29
  const CHECKPOINTS_DIR = PATHS.checkpoints;
@@ -14,7 +14,7 @@
14
14
  const path = require('node:path');
15
15
  const {
16
16
  PATHS,
17
- readJson,
17
+ readJson: _readJson,
18
18
  readFile,
19
19
  fileExists,
20
20
  parseFlags,
@@ -171,7 +171,7 @@ function assessComplexity(context) {
171
171
  * @returns {Object[]} Array of questions with category and text
172
172
  */
173
173
  function generateQuestions(context, options = {}) {
174
- const config = getConfig();
174
+ const _config = getConfig();
175
175
  const maxQuestions = options.maxQuestions ||
176
176
  getConfigValue('clarifyingQuestions.maxQuestions', 5);
177
177
  const skipForSmall = options.skipForSmall ??
@@ -22,8 +22,8 @@
22
22
  * cli.fail('Something went wrong', 1);
23
23
  */
24
24
 
25
- const fs = require('node:fs');
26
- const path = require('node:path');
25
+ const _fs = require('node:fs');
26
+ const _path = require('node:path');
27
27
  const { colors: c, parseFlags: utilsParseFlags } = require('./flow-utils');
28
28
  const { success: outputSuccess, warn: outputWarn, error: outputError, info: outputInfo } = require('./flow-output');
29
29
 
@@ -18,7 +18,7 @@
18
18
 
19
19
  const fs = require('node:fs');
20
20
  const path = require('node:path');
21
- const { getProjectRoot, getConfig, PATHS, colors, readJson } = require('./flow-utils');
21
+ const { getConfig, PATHS, colors, readJson } = require('./flow-utils');
22
22
  const { success, error: errorMsg } = require('./flow-output');
23
23
  const { safeGrep, safeFind, escapeRegex } = require('./flow-security');
24
24
 
@@ -105,7 +105,7 @@ function analyzeRelationships(filePath) {
105
105
  /**
106
106
  * Extract imports from file content
107
107
  */
108
- function extractImports(content, fileDir) {
108
+ function extractImports(content, _fileDir) {
109
109
  const imports = [];
110
110
 
111
111
  // ES6 imports
@@ -456,7 +456,7 @@ async function searchCodebase(keyword, maxResults = 10) {
456
456
  * Generate enhanced component index with relationships
457
457
  */
458
458
  async function generateEnhancedIndex() {
459
- const config = getConfig();
459
+ const _config = getConfig();
460
460
  const indexPath = path.join(PATHS.state, 'component-index.json');
461
461
 
462
462
  // Read existing index
@@ -514,7 +514,7 @@ async function generateEnhancedIndex() {
514
514
  * @param {object} options - Options
515
515
  */
516
516
  async function getSmartContext(taskDescription, options = {}) {
517
- const config = getConfig();
517
+ const _config = getConfig();
518
518
  const indexPath = path.join(PATHS.state, 'component-index.json');
519
519
 
520
520
  if (!fs.existsSync(indexPath)) {
@@ -22,10 +22,10 @@ const {
22
22
  PATHS,
23
23
  readJson,
24
24
  writeJson,
25
- fileExists,
25
+ fileExists: _fileExists,
26
26
  getTodayDate
27
27
  } = require('./flow-utils');
28
- const { anonymizeBatch, createUploadPayload } = require('./flow-sync-anonymizer');
28
+ const { createUploadPayload } = require('./flow-sync-anonymizer');
29
29
  const { loadStats } = require('./flow-stats-collector');
30
30
 
31
31
  // ============================================================
@@ -84,7 +84,7 @@ function isSyncEnabled() {
84
84
  if (!fs.existsSync(authPath)) return false;
85
85
  const auth = readJson(authPath, {});
86
86
  return !!(auth.token || auth.apiKey);
87
- } catch (err) {
87
+ } catch (_err) {
88
88
  return false;
89
89
  }
90
90
  }
@@ -293,7 +293,7 @@ function getQueueStatus() {
293
293
  ? queue.payloads[0].queuedAt
294
294
  : null
295
295
  };
296
- } catch (err) {
296
+ } catch (_err) {
297
297
  return { queuedSessions: 0, lastUpdated: null };
298
298
  }
299
299
  }
@@ -324,7 +324,7 @@ function loadCommunityScores() {
324
324
  try {
325
325
  if (!fs.existsSync(COMMUNITY_SCORES_PATH)) return {};
326
326
  return readJson(COMMUNITY_SCORES_PATH, {});
327
- } catch (err) {
327
+ } catch (_err) {
328
328
  return {};
329
329
  }
330
330
  }
@@ -338,7 +338,7 @@ function loadCommunityRouting() {
338
338
  try {
339
339
  if (!fs.existsSync(COMMUNITY_ROUTING_PATH)) return {};
340
340
  return readJson(COMMUNITY_ROUTING_PATH, {});
341
- } catch (err) {
341
+ } catch (_err) {
342
342
  return {};
343
343
  }
344
344
  }
@@ -888,7 +888,7 @@ const COMMUNITY_MARKER = '<!-- community-knowledge-v1 -->';
888
888
  * @param {Object} config - WogiFlow config
889
889
  * @returns {{ modelIntelligence: number, errorStrategies: number, patterns: number }} Merge counts
890
890
  */
891
- function mergeCommunityKnowledge(knowledge, config) {
891
+ function mergeCommunityKnowledge(knowledge, _config) {
892
892
  const counts = { modelIntelligence: 0, errorStrategies: 0, patterns: 0 };
893
893
  if (!knowledge || typeof knowledge !== 'object') return counts;
894
894
 
@@ -40,13 +40,13 @@
40
40
  * const safeText = downgradeClaim('Task is done.', audit);
41
41
  */
42
42
 
43
- const fs = require('node:fs');
44
- const path = require('node:path');
43
+ const _fs = require('node:fs');
44
+ const _path = require('node:path');
45
45
 
46
- const { PATHS } = require('./flow-paths');
47
- const { fileExists } = require('./flow-io');
46
+ const { } = require('./flow-paths');
47
+ const { } = require('./flow-io');
48
48
  const { getConfig } = require('./flow-config-loader');
49
- const { color, info, warn, error } = require('./flow-output');
49
+ const { } = require('./flow-output');
50
50
 
51
51
  const gateTelemetry = require('./flow-gate-telemetry');
52
52
 
@@ -460,6 +460,160 @@ function recordTelemetry(verdict, runCtx = {}) {
460
460
  });
461
461
  }
462
462
 
463
+ // ============================================================
464
+ // Claim-vs-state contradiction scanner (2026-04-16 honesty-infra review)
465
+ // ============================================================
466
+
467
+ /**
468
+ * Done-words must be preceded by a negation to qualify as a "no outage" claim.
469
+ * We keep the list narrow to avoid false positives on routine phrasing.
470
+ */
471
+ const NEGATION_PREFIXES = /\b(?:no|zero|0|without(?: any)?|not a single)\s+/i;
472
+
473
+ /**
474
+ * State-disagreement words a user would recognize as "the work did NOT go cleanly":
475
+ * hotfix/hotfixes (committed after-the-fact repair), regression, outage, incident,
476
+ * P0/P1, rollback, revert. Regex is intentionally anchored so "incidentally" does
477
+ * not match.
478
+ */
479
+ const DISAGREEMENT_WORDS = ['outage', 'outages', 'incident', 'incidents', 'regression', 'regressions', 'rollback', 'rollbacks', 'revert', 'reverts', 'hotfix', 'hotfixes'];
480
+ const DISAGREEMENT_RE = new RegExp(`\\b(?:${DISAGREEMENT_WORDS.join('|')})\\b`, 'i');
481
+
482
+ const PARTIAL_STATUSES = new Set(['completed-partial', 'completed_partial', 'partial', 'in-progress', 'in_progress', 'blocked', 'failed']);
483
+
484
+ /**
485
+ * Scan a task-shaped object (from ready.json, completed-archive.json, or a durable
486
+ * session snapshot) for contradictions between its free-text claim fields and its
487
+ * structured state fields.
488
+ *
489
+ * Free-text fields scanned: `notes`, `result`, `summary`, `description`.
490
+ * Structured fields inspected: `status`, `childTasks[].hotfixes`, `hotfixes`,
491
+ * `incidents`, `regressions`.
492
+ *
493
+ * Two contradiction classes:
494
+ * A) **done-word vs partial-status** — notes say "shipped end-to-end" while
495
+ * status is "completed-partial". If the notes claim completion but the
496
+ * status is not `completed`, emit a contradiction.
497
+ * B) **negated-disagreement vs evidence-of-disagreement** — result says
498
+ * "0 outages" while `childTasks[].hotfixes` is non-empty, or notes say
499
+ * "no regressions" while a `regressions` array has entries.
500
+ *
501
+ * Return shape:
502
+ * {
503
+ * contradictions: [
504
+ * { class: 'A'|'B', field, snippet, structuralEvidence, suggestion }, ...
505
+ * ],
506
+ * scanned: true,
507
+ * reason: '...' // when scanned=false (e.g., input not a task)
508
+ * }
509
+ *
510
+ * @param {Object} task - task-shaped object
511
+ * @returns {Object}
512
+ */
513
+ function scanForClaimContradictions(task) {
514
+ if (!task || typeof task !== 'object' || Array.isArray(task)) {
515
+ return { contradictions: [], scanned: false, reason: 'not-a-task-object' };
516
+ }
517
+
518
+ const contradictions = [];
519
+ const freeTextFields = ['notes', 'result', 'summary', 'description'];
520
+
521
+ const status = String(task.status || '').toLowerCase().trim();
522
+ const isPartial = PARTIAL_STATUSES.has(status);
523
+
524
+ // Evidence that the work hit real disagreement (would invalidate "0 outages" claims).
525
+ const hotfixes = collectArrayEntries(task, ['hotfixes', 'incidents', 'regressions']);
526
+ const childHotfixes = Array.isArray(task.childTasks)
527
+ ? task.childTasks.flatMap((c) => collectArrayEntries(c, ['hotfixes', 'incidents', 'regressions']))
528
+ : [];
529
+ const hasDisagreementEvidence = hotfixes.length > 0 || childHotfixes.length > 0;
530
+
531
+ for (const field of freeTextFields) {
532
+ const text = extractText(task[field]);
533
+ if (!text) continue;
534
+
535
+ // Class A: done-word + partial status
536
+ if (isPartial) {
537
+ const hit = findDoneWordHit(text);
538
+ if (hit) {
539
+ contradictions.push({
540
+ class: 'A',
541
+ field,
542
+ snippet: snippetAround(text, hit.index, hit.word.length),
543
+ structuralEvidence: `task.status = "${task.status}"`,
544
+ suggestion: `Reconcile: either update status to "completed" (if actually done) or soften the ${field} wording (e.g., "implemented" / "partially shipped")`,
545
+ });
546
+ }
547
+ }
548
+
549
+ // Class B: negated-disagreement + evidence of disagreement
550
+ if (hasDisagreementEvidence) {
551
+ const bHit = findNegatedDisagreement(text);
552
+ if (bHit) {
553
+ const evidenceSummary = [
554
+ hotfixes.length > 0 ? `task.hotfixes/incidents/regressions has ${hotfixes.length} entry(ies)` : null,
555
+ childHotfixes.length > 0 ? `childTasks[].hotfixes has ${childHotfixes.length} entry(ies)` : null,
556
+ ].filter(Boolean).join(' + ');
557
+ contradictions.push({
558
+ class: 'B',
559
+ field,
560
+ snippet: snippetAround(text, bHit.index, bHit.length),
561
+ structuralEvidence: evidenceSummary,
562
+ suggestion: `Either remove the negation (e.g., "one hotfix resolved in X min" instead of "0 outages") or move the disagreement entries off this task`,
563
+ });
564
+ }
565
+ }
566
+ }
567
+
568
+ return { contradictions, scanned: true };
569
+ }
570
+
571
+ function extractText(value) {
572
+ if (typeof value === 'string') return value;
573
+ if (Array.isArray(value)) return value.map(extractText).filter(Boolean).join(' ');
574
+ return '';
575
+ }
576
+
577
+ function findDoneWordHit(text) {
578
+ const re = new RegExp(`\\b(?:${DONE_WORDS.join('|')})\\b(?:\\s+end-to-end)?`, 'i');
579
+ const m = re.exec(text);
580
+ if (!m) return null;
581
+ return { word: m[0], index: m.index };
582
+ }
583
+
584
+ function findNegatedDisagreement(text) {
585
+ // Walk every occurrence of a disagreement word and check if it's preceded
586
+ // (within the same sentence, up to ~40 chars) by a negation prefix.
587
+ const re = new RegExp(`\\b(${DISAGREEMENT_WORDS.join('|')})\\b`, 'gi');
588
+ let m;
589
+ while ((m = re.exec(text)) !== null) {
590
+ const windowStart = Math.max(0, m.index - 40);
591
+ const window = text.slice(windowStart, m.index);
592
+ if (NEGATION_PREFIXES.test(window)) {
593
+ return { index: m.index, length: m[0].length };
594
+ }
595
+ }
596
+ return null;
597
+ }
598
+
599
+ function snippetAround(text, index, length) {
600
+ const start = Math.max(0, index - 30);
601
+ const end = Math.min(text.length, index + length + 30);
602
+ const prefix = start > 0 ? '…' : '';
603
+ const suffix = end < text.length ? '…' : '';
604
+ return `${prefix}${text.slice(start, end).replace(/\s+/g, ' ').trim()}${suffix}`;
605
+ }
606
+
607
+ function collectArrayEntries(obj, keys) {
608
+ if (!obj || typeof obj !== 'object') return [];
609
+ const out = [];
610
+ for (const k of keys) {
611
+ const v = obj[k];
612
+ if (Array.isArray(v)) out.push(...v.filter((x) => x !== null && x !== undefined && x !== ''));
613
+ }
614
+ return out;
615
+ }
616
+
463
617
  // ============================================================
464
618
  // Exports
465
619
  // ============================================================
@@ -472,6 +626,8 @@ module.exports = {
472
626
  getStepEvidence,
473
627
  isTruthGateDisabled,
474
628
  getMinTierForDone,
629
+ scanForClaimContradictions,
475
630
  TIER_NAMES,
476
631
  DONE_WORDS,
632
+ DISAGREEMENT_WORDS,
477
633
  };
@@ -369,7 +369,7 @@ function assessTaskComplexity(task) {
369
369
  /**
370
370
  * Generates human-readable reasoning
371
371
  */
372
- function generateReasoning(level, factors, breakdown) {
372
+ function generateReasoning(level, factors, _breakdown) {
373
373
  const parts = [];
374
374
 
375
375
  // File summary
@@ -399,10 +399,14 @@ const CONFIG_DEFAULTS = {
399
399
  managerCanSkipGates: false,
400
400
  _comment_autoPickupChannelDispatches: 'v2.20.0+: After task completion, if channel-dispatched tasks are queued in ready.json, the task-completed hook injects additionalContext instructing the AI to auto-invoke /wogi-start on the next queued task in the same turn. Prevents "Sauteed worker" silent stalls between queued dispatches. The Stop hook also blocks end-of-turn when queued dispatches exist but no task is in progress — making "awaiting signal" language mechanically impossible as a terminal state.',
401
401
  autoPickupChannelDispatches: true,
402
- _comment_diagnosticCurlBypass: 'v2.20.0+: When true, PreToolUse routing gate allows narrow curl-to-manager-port when replying to channel messages tagged INTROSPECTION or DIAGNOSTIC, with body starting "## ". Unblocks diagnostic round-trips without forcing fake task creation. Scope: localhost:8800 only.',
403
- diagnosticCurlBypass: true,
404
402
  _comment_blockAskUserQuestionInWorker: 'v2.20.1+: When true, PreToolUse blocks AskUserQuestion in workspace worker mode. The user only sees the manager terminal, so direct prompts from workers stall silently. Block message instructs channel-dispatch "## QUESTION:" to the manager. Closes the v2.20.0 gap where workers could still prompt the user directly when their queue was empty.',
405
- blockAskUserQuestionInWorker: true
403
+ blockAskUserQuestionInWorker: true,
404
+ _comment_aiWorkerQuestionClassifier: 'v2.21.0+: When true, Stop hook runs a Haiku classifier on the final assistant message in worker mode. If the message ends by asking the user a question (detected semantically, not via regex), the stop is blocked with channel-dispatch instructions. Degrades to no-op when ANTHROPIC_API_KEY is absent. Uses existing flow-model-caller infrastructure.',
405
+ aiWorkerQuestionClassifier: {
406
+ enabled: true,
407
+ minConfidence: 70,
408
+ model: 'anthropic:claude-3-5-haiku-latest'
409
+ }
406
410
  },
407
411
  checkpoint: { enabled: false },
408
412
  regressionTesting: { enabled: false },
@@ -733,7 +737,15 @@ const CONFIG_DEFAULTS = {
733
737
  autoMergeForTypes: ['bugfix', 'quick-fix'],
734
738
  requirePRForTypes: [],
735
739
  squashOnMerge: true,
736
- prTemplate: { includeTaskSpec: true, includeCommitList: true, includeFileSummary: true }
740
+ prTemplate: { includeTaskSpec: true, includeCommitList: true, includeFileSummary: true },
741
+ // Merge-plan gate: require .workflow/scratch/merge-plan.md for large or cross-repo merges.
742
+ // See .claude/commands/wogi-finalize.md §Step 2.5. Added 2026-04-16.
743
+ mergePlan: {
744
+ enabled: true,
745
+ threshold: 5,
746
+ restructureThreshold: 0.20,
747
+ alwaysForCrossRepo: true
748
+ }
737
749
  },
738
750
 
739
751
  // --- Models ---
@@ -22,7 +22,7 @@ const {
22
22
  getConfig,
23
23
  color,
24
24
  success,
25
- warn,
25
+ warn: _warn,
26
26
  error,
27
27
  parseFlags,
28
28
  outputJson,
@@ -286,7 +286,7 @@ function main() {
286
286
  execFileSync(process.execPath, [path.join(__dirname, 'flow-config-set.js'), key, value], {
287
287
  stdio: 'inherit'
288
288
  });
289
- } catch (err) {
289
+ } catch (_err) {
290
290
  process.exit(1);
291
291
  }
292
292
  break;
@@ -11,7 +11,7 @@
11
11
  const fs = require('node:fs');
12
12
  const path = require('node:path');
13
13
  const { PATHS, PROJECT_ROOT, isPathWithinProject } = require('./flow-paths');
14
- const { checkForDangerousKeys, readJson, writeJson, acquireLock, safeJsonParse, safeJsonParseString } = require('./flow-io');
14
+ const { writeJson, acquireLock, safeJsonParse, safeJsonParseString } = require('./flow-io');
15
15
  const { warn } = require('./flow-output');
16
16
 
17
17
  // Late-loaded to avoid circular dependency
@@ -19,7 +19,8 @@
19
19
  */
20
20
 
21
21
  const fs = require('node:fs');
22
- const path = require('node:path');
22
+ const _path = require('node:path');
23
+ const { safeJsonParse } = require('./flow-io');
23
24
 
24
25
  /** Current config version — increment when adding new migrations */
25
26
  const CURRENT_CONFIG_VERSION = 2;
@@ -232,12 +233,10 @@ function migrateConfigFile(configPath) {
232
233
  return { migrated: false, fromVersion: 0, toVersion: 0, applied: [] };
233
234
  }
234
235
 
235
- let config;
236
- try {
237
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
238
- } catch (err) {
236
+ const config = safeJsonParse(configPath, null);
237
+ if (!config) {
239
238
  if (process.env.DEBUG) {
240
- console.error(`[config-migrate] Failed to read config: ${err.message}`);
239
+ console.error(`[config-migrate] Failed to read config at ${configPath}`);
241
240
  }
242
241
  return { migrated: false, fromVersion: 0, toVersion: 0, applied: [] };
243
242
  }
@@ -34,8 +34,8 @@ const {
34
34
  getConfig,
35
35
  success,
36
36
  warn,
37
- error,
38
- safeJsonParse,
37
+ error: _error,
38
+ safeJsonParse: _safeJsonParse,
39
39
  isPathWithinProject
40
40
  } = require('./flow-utils');
41
41
 
@@ -338,7 +338,7 @@ function getSourceFiles() {
338
338
  let entries;
339
339
  try {
340
340
  entries = fs.readdirSync(dir, { withFileTypes: true });
341
- } catch (err) {
341
+ } catch (_err) {
342
342
  return;
343
343
  }
344
344
 
@@ -402,7 +402,7 @@ function checkFileExists(entry) {
402
402
  * @param {Object} [options] - Options
403
403
  * @returns {Object} Check results
404
404
  */
405
- function runConsistencyCheck(options = {}) {
405
+ function runConsistencyCheck(_options = {}) {
406
406
  const config = getConfig();
407
407
  const consistencyConfig = config.consistency || {};
408
408
 
@@ -426,7 +426,7 @@ function runConsistencyCheck(options = {}) {
426
426
  const appMapEntries = checks.appMapVsCodebase !== false || checks.orphanDetection !== false ? parseAppMap() : [];
427
427
  const functionMapEntries = checks.functionMapVsCodebase !== false || checks.orphanDetection !== false ? parseFunctionMap() : [];
428
428
  const apiMapEntries = checks.apiMapVsCodebase !== false || checks.orphanDetection !== false ? parseApiMap() : [];
429
- const additionalEntries = checks.orphanDetection !== false ? parseAdditionalRegistryMaps() : [];
429
+ const _additionalEntries = checks.orphanDetection !== false ? parseAdditionalRegistryMaps() : [];
430
430
 
431
431
  // 1. App-map vs codebase
432
432
  if (checks.appMapVsCodebase !== false) {
@@ -15,7 +15,7 @@
15
15
 
16
16
  const path = require('node:path');
17
17
  const { getConfig, readJson, writeJson, ensureDir, PATHS } = require('../flow-utils');
18
- const { loadTree, saveTree, estimateTokens, calculateTreeTokens } = require('./summary-tree');
18
+ const { loadTree, estimateTokens, calculateTreeTokens } = require('./summary-tree');
19
19
  const { scoreNodeRelevance, extractKeywords } = require('./section-extractor');
20
20
 
21
21
  // ============================================================
@@ -141,14 +141,14 @@ function cleanupPlanFiles() {
141
141
  try {
142
142
  const stats = fs.lstatSync(filePath);
143
143
  if (stats.isSymbolicLink()) continue;
144
- } catch (err) {
144
+ } catch (_err) {
145
145
  continue;
146
146
  }
147
147
 
148
148
  let content;
149
149
  try {
150
150
  content = fs.readFileSync(filePath, 'utf-8');
151
- } catch (err) {
151
+ } catch (_err) {
152
152
  continue; // Skip files we can't read
153
153
  }
154
154