wogiflow 2.4.2 → 2.4.4

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 (210) hide show
  1. package/.claude/commands/wogi-start.md +124 -0
  2. package/.claude/docs/claude-code-compatibility.md +51 -0
  3. package/.claude/docs/explore-agents.md +11 -0
  4. package/.claude/settings.json +12 -1
  5. package/.workflow/models/registry.json +1 -1
  6. package/bin/flow +11 -1
  7. package/lib/workspace-contracts.js +599 -0
  8. package/lib/workspace-intelligence.js +600 -0
  9. package/lib/workspace-messages.js +441 -0
  10. package/lib/workspace-routing.js +485 -0
  11. package/lib/workspace-sync.js +339 -0
  12. package/lib/workspace.js +1073 -0
  13. package/package.json +4 -4
  14. package/scripts/MEMORY-ARCHITECTURE.md +1 -1
  15. package/scripts/base-workflow-step.js +136 -0
  16. package/scripts/flow-adaptive-learning.js +8 -9
  17. package/scripts/flow-aggregate.js +11 -6
  18. package/scripts/flow-api-index.js +4 -6
  19. package/scripts/flow-assumption-detector.js +0 -2
  20. package/scripts/flow-audit.js +15 -2
  21. package/scripts/flow-auto-context.js +8 -12
  22. package/scripts/flow-auto-learn.js +49 -49
  23. package/scripts/flow-background.js +5 -6
  24. package/scripts/flow-bridge-state.js +8 -10
  25. package/scripts/flow-bulk-loop.js +1 -3
  26. package/scripts/flow-bulk-orchestrator.js +1 -3
  27. package/scripts/flow-cascade-completion.js +0 -2
  28. package/scripts/flow-cascade.js +4 -4
  29. package/scripts/flow-checkpoint.js +10 -13
  30. package/scripts/flow-code-intelligence.js +10 -12
  31. package/scripts/flow-community-sync.js +4 -4
  32. package/scripts/flow-community.js +12 -20
  33. package/scripts/flow-config-defaults.js +28 -2
  34. package/scripts/flow-config-interactive.js +9 -5
  35. package/scripts/flow-config-loader.js +49 -92
  36. package/scripts/flow-config-substitution.js +0 -2
  37. package/scripts/flow-context-estimator.js +4 -4
  38. package/scripts/flow-context-init.js +10 -12
  39. package/scripts/flow-context-manager.js +0 -2
  40. package/scripts/flow-context-scoring.js +2 -2
  41. package/scripts/flow-contract-scan.js +6 -9
  42. package/scripts/flow-correct.js +29 -27
  43. package/scripts/flow-correction-detector.js +5 -1
  44. package/scripts/flow-damage-control.js +47 -54
  45. package/scripts/flow-decisions-merge.js +4 -14
  46. package/scripts/flow-diff.js +5 -8
  47. package/scripts/flow-done-gates.js +786 -0
  48. package/scripts/flow-done-report.js +123 -0
  49. package/scripts/flow-done.js +71 -717
  50. package/scripts/flow-entropy-monitor.js +1 -3
  51. package/scripts/flow-eval-calibration.js +257 -0
  52. package/scripts/flow-eval-judge.js +10 -1
  53. package/scripts/flow-eval.js +14 -5
  54. package/scripts/flow-extraction-review.js +1 -0
  55. package/scripts/flow-failure-categories.js +0 -2
  56. package/scripts/flow-figma-confirm.js +5 -9
  57. package/scripts/flow-figma-generate.js +8 -10
  58. package/scripts/flow-figma-index.js +8 -10
  59. package/scripts/flow-figma-match.js +3 -5
  60. package/scripts/flow-figma-mcp-server.js +2 -4
  61. package/scripts/flow-figma-orchestrator.js +2 -3
  62. package/scripts/flow-figma-registry.js +2 -3
  63. package/scripts/flow-framework-resolver.js +0 -2
  64. package/scripts/flow-function-index.js +4 -6
  65. package/scripts/flow-gate-confidence.js +2 -2
  66. package/scripts/flow-gitignore.js +0 -2
  67. package/scripts/flow-guided-edit.js +5 -6
  68. package/scripts/flow-health.js +5 -6
  69. package/scripts/flow-hook-errors.js +6 -0
  70. package/scripts/flow-hook-status.js +263 -0
  71. package/scripts/flow-hooks.js +17 -29
  72. package/scripts/flow-http-client.js +9 -8
  73. package/scripts/flow-hybrid-interactive.js +7 -12
  74. package/scripts/flow-hybrid-test.js +12 -13
  75. package/scripts/flow-instruction-richness.js +1 -1
  76. package/scripts/flow-io.js +21 -4
  77. package/scripts/flow-knowledge-router.js +9 -3
  78. package/scripts/flow-learning-orchestrator.js +318 -13
  79. package/scripts/flow-links.js +5 -7
  80. package/scripts/flow-long-input-association.js +275 -0
  81. package/scripts/flow-long-input-chunking.js +1 -0
  82. package/scripts/flow-long-input-cli.js +0 -2
  83. package/scripts/flow-long-input-complexity.js +0 -2
  84. package/scripts/flow-long-input-constants.js +0 -2
  85. package/scripts/flow-long-input-contradictions.js +351 -0
  86. package/scripts/flow-long-input-detection.js +0 -2
  87. package/scripts/flow-long-input-passes.js +885 -0
  88. package/scripts/flow-long-input-stories.js +1 -1
  89. package/scripts/flow-long-input-voice.js +0 -2
  90. package/scripts/flow-long-input.js +425 -3005
  91. package/scripts/flow-loop-retry-learning.js +2 -3
  92. package/scripts/flow-lsp.js +3 -3
  93. package/scripts/flow-mcp-docs.js +3 -4
  94. package/scripts/flow-memory-db.js +6 -8
  95. package/scripts/flow-memory-sync.js +18 -11
  96. package/scripts/flow-metrics.js +1 -2
  97. package/scripts/flow-model-adapter.js +2 -3
  98. package/scripts/flow-model-config.js +72 -104
  99. package/scripts/flow-model-router.js +2 -2
  100. package/scripts/flow-model-types.js +0 -2
  101. package/scripts/flow-multi-approach.js +5 -6
  102. package/scripts/flow-orchestrate-context.js +3 -7
  103. package/scripts/flow-orchestrate-rollback.js +3 -8
  104. package/scripts/flow-orchestrate-state.js +8 -14
  105. package/scripts/flow-orchestrate-templates.js +2 -6
  106. package/scripts/flow-orchestrate-validator.js +5 -9
  107. package/scripts/flow-orchestrate.js +126 -103
  108. package/scripts/flow-output.js +0 -2
  109. package/scripts/flow-parallel.js +1 -1
  110. package/scripts/flow-paths.js +23 -2
  111. package/scripts/flow-pattern-enforcer.js +30 -28
  112. package/scripts/flow-pattern-extractor.js +3 -4
  113. package/scripts/flow-pending.js +0 -2
  114. package/scripts/flow-permissions.js +2 -3
  115. package/scripts/flow-plugin-registry.js +10 -12
  116. package/scripts/flow-prd-manager.js +1 -1
  117. package/scripts/flow-progress.js +7 -9
  118. package/scripts/flow-prompt-composer.js +3 -3
  119. package/scripts/flow-prompt-template.js +2 -2
  120. package/scripts/flow-providers.js +7 -4
  121. package/scripts/flow-registry-manager.js +7 -12
  122. package/scripts/flow-regression.js +9 -11
  123. package/scripts/flow-roadmap.js +2 -2
  124. package/scripts/flow-run-trace.js +16 -15
  125. package/scripts/flow-safety.js +2 -5
  126. package/scripts/flow-scanner-base.js +5 -7
  127. package/scripts/flow-scenario-engine.js +1 -5
  128. package/scripts/flow-security.js +29 -0
  129. package/scripts/flow-session-end.js +32 -41
  130. package/scripts/flow-session-learning.js +53 -49
  131. package/scripts/flow-setup-hooks.js +2 -3
  132. package/scripts/flow-skill-create.js +7 -12
  133. package/scripts/flow-skill-generator.js +12 -16
  134. package/scripts/flow-skill-learn.js +17 -8
  135. package/scripts/flow-skill-matcher.js +1 -2
  136. package/scripts/flow-spec-generator.js +2 -4
  137. package/scripts/flow-stack-wizard.js +5 -7
  138. package/scripts/flow-standards-learner.js +35 -16
  139. package/scripts/flow-start.js +2 -0
  140. package/scripts/flow-stats-collector.js +2 -2
  141. package/scripts/flow-status.js +10 -10
  142. package/scripts/flow-statusline-setup.js +2 -2
  143. package/scripts/flow-step-changelog.js +2 -3
  144. package/scripts/flow-step-comments.js +66 -81
  145. package/scripts/flow-step-complexity.js +50 -70
  146. package/scripts/flow-step-coverage.js +3 -5
  147. package/scripts/flow-step-knowledge.js +2 -3
  148. package/scripts/flow-step-pr-tests.js +64 -74
  149. package/scripts/flow-step-regression.js +3 -5
  150. package/scripts/flow-step-review.js +86 -103
  151. package/scripts/flow-step-security.js +111 -121
  152. package/scripts/flow-step-silent-failures.js +56 -83
  153. package/scripts/flow-step-simplifier.js +52 -70
  154. package/scripts/flow-story.js +4 -7
  155. package/scripts/flow-strict-adherence.js +3 -4
  156. package/scripts/flow-task-checkpoint.js +36 -5
  157. package/scripts/flow-task-enforcer.js +2 -24
  158. package/scripts/flow-tech-debt.js +1 -1
  159. package/scripts/flow-template-extractor.js +1 -0
  160. package/scripts/flow-templates.js +11 -13
  161. package/scripts/flow-test-api.js +9 -13
  162. package/scripts/flow-test-discovery.js +1 -1
  163. package/scripts/flow-test-generate.js +5 -9
  164. package/scripts/flow-test-integrity.js +3 -7
  165. package/scripts/flow-test-ui.js +5 -9
  166. package/scripts/flow-testing-deps.js +1 -3
  167. package/scripts/flow-tiered-learning.js +4 -4
  168. package/scripts/flow-todowrite-sync.js +1 -1
  169. package/scripts/flow-tokens.js +0 -2
  170. package/scripts/flow-verification-profile.js +6 -10
  171. package/scripts/flow-verify.js +12 -16
  172. package/scripts/flow-version-check.js +4 -12
  173. package/scripts/flow-webmcp-generator.js +3 -5
  174. package/scripts/flow-workflow-steps.js +0 -2
  175. package/scripts/flow-workflow.js +9 -11
  176. package/scripts/hooks/adapters/claude-code.js +31 -0
  177. package/scripts/hooks/core/config-change.js +1 -0
  178. package/scripts/hooks/core/extension-registry.js +0 -2
  179. package/scripts/hooks/core/instructions-loaded.js +1 -1
  180. package/scripts/hooks/core/observation-capture.js +5 -5
  181. package/scripts/hooks/core/phase-gate.js +5 -0
  182. package/scripts/hooks/core/post-compact.js +1 -12
  183. package/scripts/hooks/core/research-gate.js +2 -12
  184. package/scripts/hooks/core/routing-gate.js +6 -0
  185. package/scripts/hooks/core/task-completed.js +12 -0
  186. package/scripts/hooks/core/task-created.js +83 -0
  187. package/scripts/hooks/core/worktree-lifecycle.js +1 -1
  188. package/scripts/hooks/entry/claude-code/config-change.js +6 -29
  189. package/scripts/hooks/entry/claude-code/instructions-loaded.js +5 -30
  190. package/scripts/hooks/entry/claude-code/post-compact.js +4 -31
  191. package/scripts/hooks/entry/claude-code/post-tool-use.js +121 -172
  192. package/scripts/hooks/entry/claude-code/pre-tool-use.js +260 -361
  193. package/scripts/hooks/entry/claude-code/session-end.js +4 -28
  194. package/scripts/hooks/entry/claude-code/session-start.js +205 -243
  195. package/scripts/hooks/entry/claude-code/setup.js +8 -49
  196. package/scripts/hooks/entry/claude-code/stop.js +40 -72
  197. package/scripts/hooks/entry/claude-code/task-completed.js +4 -28
  198. package/scripts/hooks/entry/claude-code/task-created.js +15 -0
  199. package/scripts/hooks/entry/claude-code/user-prompt-submit.js +113 -195
  200. package/scripts/hooks/entry/claude-code/worktree-create.js +6 -25
  201. package/scripts/hooks/entry/claude-code/worktree-remove.js +6 -25
  202. package/scripts/hooks/entry/shared/hook-runner.js +99 -0
  203. package/scripts/hooks/entry/shared/read-stdin.js +0 -2
  204. package/scripts/postinstall.js +2 -0
  205. package/scripts/registries/api-registry.js +0 -2
  206. package/scripts/registries/component-registry.js +5 -9
  207. package/scripts/registries/contract-scanner.js +2 -9
  208. package/scripts/registries/function-registry.js +0 -2
  209. package/scripts/registries/schema-registry.js +14 -18
  210. package/scripts/registries/service-registry.js +23 -27
@@ -8,32 +8,8 @@
8
8
  */
9
9
 
10
10
  const { handleSessionEnd } = require('../../core/session-end');
11
- const { claudeCodeAdapter } = require('../../adapters/claude-code');
12
- const { readHookInput } = require('../shared/read-stdin');
11
+ const { runHook } = require('../shared/hook-runner');
13
12
 
14
- async function main() {
15
- try {
16
- const { input: parsedStdin } = await readHookInput();
17
- const input = parsedStdin || {};
18
- const parsedInput = claudeCodeAdapter.parseInput(input);
19
-
20
- // Handle session end
21
- const coreResult = handleSessionEnd(parsedInput);
22
-
23
- // Transform to Claude Code format
24
- const output = claudeCodeAdapter.transformResult('SessionEnd', coreResult);
25
-
26
- // Output JSON
27
- console.log(JSON.stringify(output));
28
- process.exit(0);
29
- } catch (err) {
30
- // Non-blocking error
31
- console.error(`[Wogi Flow Hook Error] ${err.message}`);
32
- console.log(JSON.stringify({ continue: true }));
33
- process.exit(0);
34
- }
35
- }
36
-
37
- // Handle stdin properly
38
- process.stdin.setEncoding('utf8');
39
- main();
13
+ runHook('SessionEnd', async ({ parsedInput }) => {
14
+ return handleSessionEnd(parsedInput);
15
+ }, { failMode: 'silent' });
@@ -8,12 +8,11 @@
8
8
  */
9
9
 
10
10
  const { gatherSessionContext } = require('../../core/session-context');
11
- const { claudeCodeAdapter } = require('../../adapters/claude-code');
12
11
  const { setCliSessionId, clearStaleCurrentTaskAsync } = require('../../../flow-session-state');
13
12
  const { checkAndResetStalePhase } = require('../../core/phase-gate');
14
13
  const { setRoutingPending } = require('../../core/routing-gate');
15
14
  const { getConfig } = require('../../../flow-utils');
16
- const { readHookInput } = require('../shared/read-stdin');
15
+ const { runHook } = require('../shared/hook-runner');
17
16
 
18
17
  // Lazy-load bridge state to avoid circular dependencies
19
18
  let autoSyncBridge = null;
@@ -28,294 +27,257 @@ function getAutoSyncBridge() {
28
27
  return autoSyncBridge;
29
28
  }
30
29
 
31
- async function main() {
32
- try {
33
- // Start bridge auto-sync in parallel with stdin reading (both are independent I/O)
34
- const bridgeSyncPromise = (async () => {
35
- try {
36
- const syncFn = getAutoSyncBridge();
37
- await syncFn('claude-code', { silent: true });
38
- } catch (err) {
39
- if (process.env.DEBUG) {
40
- console.error(`[session-start] Bridge auto-sync failed: ${err.message}`);
41
- }
42
- }
43
- })();
44
-
45
- // Read input from stdin (runs concurrently with bridge sync)
46
- const { input: parsedStdin } = await readHookInput();
47
- const input = parsedStdin || {};
48
- const parsedInput = claudeCodeAdapter.parseInput(input);
49
-
50
- // Wait for bridge sync to complete before proceeding
51
- await bridgeSyncPromise;
52
-
53
- // CLAUDE.md drift detection — check if manually edited since last sync
54
- let driftDetected = false;
55
- let driftMarkerMissing = false;
56
- try {
57
- const { checkClaudeMdDrift } = require('../../../flow-bridge-state');
58
- const drift = checkClaudeMdDrift();
59
- if (drift.drifted && drift.reason === 'content-changed') {
60
- if (process.env.DEBUG) {
61
- console.error('[session-start] CLAUDE.md drift detected — content changed since last sync');
62
- }
63
- driftDetected = true;
64
- } else if (drift.drifted && drift.reason === 'marker-missing') {
65
- if (process.env.DEBUG) {
66
- console.error('[session-start] CLAUDE.md appears manually maintained (no generation marker)');
67
- }
68
- driftDetected = true;
69
- driftMarkerMissing = true;
70
- }
71
- } catch (err) {
72
- if (process.env.DEBUG) {
73
- console.error(`[session-start] Drift detection failed: ${err.message}`);
74
- }
75
- }
76
-
77
- // --- Version compatibility checks (parallelized) ---
78
- // 1. Claude Code: warns if below hard minimum (2.1.23) where hooks don't work
79
- // 2. WogiFlow npm: warns if a newer version is available (checks once per 24h)
80
- let versionWarning = null;
81
- let updateWarning = null;
30
+ runHook('SessionStart', async ({ parsedInput }) => {
31
+ // Start bridge auto-sync in parallel with other init work
32
+ const bridgeSyncPromise = (async () => {
82
33
  try {
83
- const { checkClaudeCodeVersionOnce, checkWogiFlowUpdateOnce } = require('../../../flow-version-check');
84
- const [vw, uw] = await Promise.all([
85
- (async () => { try { return await checkClaudeCodeVersionOnce(); } catch (_err) { return null; } })(),
86
- (async () => { try { return await checkWogiFlowUpdateOnce(); } catch (_err) { return null; } })()
87
- ]);
88
- versionWarning = vw;
89
- updateWarning = uw;
34
+ const syncFn = getAutoSyncBridge();
35
+ await syncFn('claude-code', { silent: true });
90
36
  } catch (err) {
91
37
  if (process.env.DEBUG) {
92
- console.error(`[session-start] Version check failed: ${err.message}`);
38
+ console.error(`[session-start] Bridge auto-sync failed: ${err.message}`);
93
39
  }
94
40
  }
41
+ })();
95
42
 
96
- // --- Batch 1: Independent pre-context operations (async + sync) ---
97
- // These all operate on separate state files and have no data dependencies.
43
+ // Wait for bridge sync to complete
44
+ await bridgeSyncPromise;
98
45
 
99
- // Sync operations (run immediately, no await needed)
100
- let scriptWarnings = [];
101
- try {
102
- const wasReset = checkAndResetStalePhase();
103
- if (wasReset && process.env.DEBUG) {
104
- console.error('[session-start] Reset stale workflow phase to idle');
46
+ // CLAUDE.md drift detection check if manually edited since last sync
47
+ let driftDetected = false;
48
+ let driftMarkerMissing = false;
49
+ try {
50
+ const { checkClaudeMdDrift } = require('../../../flow-bridge-state');
51
+ const drift = checkClaudeMdDrift();
52
+ if (drift.drifted && drift.reason === 'content-changed') {
53
+ if (process.env.DEBUG) {
54
+ console.error('[session-start] CLAUDE.md drift detected — content changed since last sync');
105
55
  }
106
- } catch (err) {
56
+ driftDetected = true;
57
+ } else if (drift.drifted && drift.reason === 'marker-missing') {
107
58
  if (process.env.DEBUG) {
108
- console.error(`[session-start] Failed to check stale phase: ${err.message}`);
59
+ console.error('[session-start] CLAUDE.md appears manually maintained (no generation marker)');
109
60
  }
61
+ driftDetected = true;
62
+ driftMarkerMissing = true;
63
+ }
64
+ } catch (err) {
65
+ if (process.env.DEBUG) {
66
+ console.error(`[session-start] Drift detection failed: ${err.message}`);
110
67
  }
68
+ }
111
69
 
112
- try {
113
- const routingResult = setRoutingPending();
114
- if (process.env.DEBUG) {
115
- console.error(`[session-start] Set routing-pending: ${routingResult.reason}`);
116
- }
117
- } catch (err) {
118
- if (process.env.DEBUG) {
119
- console.error(`[session-start] Failed to set routing-pending: ${err.message}`);
120
- }
70
+ // --- Version compatibility checks (parallelized) ---
71
+ let versionWarning = null;
72
+ let updateWarning = null;
73
+ try {
74
+ const { checkClaudeCodeVersionOnce, checkWogiFlowUpdateOnce } = require('../../../flow-version-check');
75
+ const [vw, uw] = await Promise.all([
76
+ (async () => { try { return await checkClaudeCodeVersionOnce(); } catch (_err) { return null; } })(),
77
+ (async () => { try { return await checkWogiFlowUpdateOnce(); } catch (_err) { return null; } })()
78
+ ]);
79
+ versionWarning = vw;
80
+ updateWarning = uw;
81
+ } catch (err) {
82
+ if (process.env.DEBUG) {
83
+ console.error(`[session-start] Version check failed: ${err.message}`);
121
84
  }
85
+ }
122
86
 
123
- try {
124
- const { validateScripts } = require('../../../flow-script-resolver');
125
- scriptWarnings = validateScripts();
126
- } catch (err) {
127
- if (process.env.DEBUG) {
128
- console.error(`[session-start] Script validation failed: ${err.message}`);
129
- }
87
+ // --- Batch 1: Independent pre-context operations (async + sync) ---
88
+ let scriptWarnings = [];
89
+ try {
90
+ const wasReset = checkAndResetStalePhase();
91
+ if (wasReset && process.env.DEBUG) {
92
+ console.error('[session-start] Reset stale workflow phase to idle');
93
+ }
94
+ } catch (err) {
95
+ if (process.env.DEBUG) {
96
+ console.error(`[session-start] Failed to check stale phase: ${err.message}`);
130
97
  }
98
+ }
131
99
 
132
- // BUG-005 fix: Create durable-session.json for active tasks on session start.
133
- // Without this, the first prompt of every task is lost because user-prompt-submit
134
- // fires BEFORE post-tool-use (which creates the session file). This also fixes
135
- // session resume after context compaction — durable-session.json may have been
136
- // archived but the task is still inProgress in ready.json.
137
- try {
138
- const { getReadyData } = require('../../../flow-utils');
139
- const readyData = getReadyData();
140
- if (Array.isArray(readyData.inProgress) && readyData.inProgress.length > 0) {
141
- const task = readyData.inProgress[0];
142
- const taskId = task && task.id;
143
- if (taskId) {
144
- const { loadDurableSession, createDurableSession } = require('../../../flow-durable-session');
145
- const existing = loadDurableSession();
146
- if (!existing || existing.taskId !== taskId) {
147
- const criteria = task.acceptanceCriteria || task.scenarios || [];
148
- const steps = Array.isArray(criteria) ? criteria : [];
149
- const sessionSteps = steps.length > 0 ? steps : [task.title || taskId];
150
- createDurableSession(taskId, 'task', sessionSteps);
151
- if (process.env.DEBUG) {
152
- console.error(`[session-start] Created durable session for active task ${taskId}`);
153
- }
154
- }
155
- }
156
- }
157
- } catch (err) {
158
- // Non-blocking — prompt capture is best-effort
159
- if (process.env.DEBUG) {
160
- console.error(`[session-start] Durable session init failed: ${err.message}`);
161
- }
100
+ try {
101
+ const routingResult = setRoutingPending();
102
+ if (process.env.DEBUG) {
103
+ console.error(`[session-start] Set routing-pending: ${routingResult.reason}`);
162
104
  }
105
+ } catch (err) {
106
+ if (process.env.DEBUG) {
107
+ console.error(`[session-start] Failed to set routing-pending: ${err.message}`);
108
+ }
109
+ }
163
110
 
164
- // Async operations — batch with Promise.all (both use file locking, independent targets)
165
- const asyncPreOps = [];
111
+ try {
112
+ const { validateScripts } = require('../../../flow-script-resolver');
113
+ scriptWarnings = validateScripts();
114
+ } catch (err) {
115
+ if (process.env.DEBUG) {
116
+ console.error(`[session-start] Script validation failed: ${err.message}`);
117
+ }
118
+ }
166
119
 
167
- if (parsedInput.sessionId) {
168
- asyncPreOps.push(
169
- setCliSessionId(parsedInput.sessionId).catch(err => {
120
+ // BUG-005 fix: Create durable-session.json for active tasks on session start.
121
+ try {
122
+ const { getReadyData } = require('../../../flow-utils');
123
+ const readyData = getReadyData();
124
+ if (Array.isArray(readyData.inProgress) && readyData.inProgress.length > 0) {
125
+ const task = readyData.inProgress[0];
126
+ const taskId = task && task.id;
127
+ if (taskId) {
128
+ const { loadDurableSession, createDurableSession } = require('../../../flow-durable-session');
129
+ const existing = loadDurableSession();
130
+ if (!existing || existing.taskId !== taskId) {
131
+ const criteria = task.acceptanceCriteria || task.scenarios || [];
132
+ const steps = Array.isArray(criteria) ? criteria : [];
133
+ const sessionSteps = steps.length > 0 ? steps : [task.title || taskId];
134
+ createDurableSession(taskId, 'task', sessionSteps);
170
135
  if (process.env.DEBUG) {
171
- console.error(`[session-start] Failed to store session ID: ${err.message}`);
136
+ console.error(`[session-start] Created durable session for active task ${taskId}`);
172
137
  }
173
- })
174
- );
138
+ }
139
+ }
175
140
  }
141
+ } catch (err) {
142
+ if (process.env.DEBUG) {
143
+ console.error(`[session-start] Durable session init failed: ${err.message}`);
144
+ }
145
+ }
146
+
147
+ // Async operations — batch with Promise.all
148
+ const asyncPreOps = [];
176
149
 
150
+ if (parsedInput.sessionId) {
177
151
  asyncPreOps.push(
178
- clearStaleCurrentTaskAsync().catch(err => {
152
+ setCliSessionId(parsedInput.sessionId).catch(err => {
179
153
  if (process.env.DEBUG) {
180
- console.error(`[session-start] Failed to clear stale task: ${err.message}`);
154
+ console.error(`[session-start] Failed to store session ID: ${err.message}`);
181
155
  }
182
156
  })
183
157
  );
158
+ }
184
159
 
185
- // Gather session context concurrently with the async pre-ops
186
- const [, coreResult] = await Promise.all([
187
- Promise.all(asyncPreOps),
188
- gatherSessionContext({
189
- includeSuspended: true,
190
- includeDecisions: true,
191
- includeActivity: true
192
- })
193
- ]);
194
-
195
- // --- Batch 2: Post-context operations (plugin scan + community pull) ---
196
- // Both modify coreResult.context but touch different keys, so they can run concurrently.
197
-
198
- const postContextOps = [];
199
-
200
- // Plugin auto-scan (non-blocking)
201
- postContextOps.push((async () => {
202
- try {
203
- const config = getConfig();
204
- if (config.plugins?.enabled && config.plugins?.autoScanOnSessionStart) {
205
- const { scanUnregisteredMcpServers, registerPlugin, deactivateStaleMcpPlugins, listPlugins } = require('../../../flow-plugin-registry');
206
-
207
- const unregistered = scanUnregisteredMcpServers();
208
- for (const server of unregistered) {
209
- registerPlugin({
210
- name: server.serverName,
211
- description: `Auto-discovered MCP server: ${server.serverName}`,
212
- source: 'auto-scan',
213
- triggers: [`use ${server.serverName}`, `send to ${server.serverName}`, server.serverName],
214
- capabilities: [],
215
- metadata: { mcpServer: server.serverName }
216
- });
217
- if (process.env.DEBUG) {
218
- console.error(`[session-start] Auto-registered plugin: ${server.serverName}`);
219
- }
160
+ asyncPreOps.push(
161
+ clearStaleCurrentTaskAsync().catch(err => {
162
+ if (process.env.DEBUG) {
163
+ console.error(`[session-start] Failed to clear stale task: ${err.message}`);
164
+ }
165
+ })
166
+ );
167
+
168
+ // Gather session context concurrently with the async pre-ops
169
+ const [, coreResult] = await Promise.all([
170
+ Promise.all(asyncPreOps),
171
+ gatherSessionContext({
172
+ includeSuspended: true,
173
+ includeDecisions: true,
174
+ includeActivity: true
175
+ })
176
+ ]);
177
+
178
+ // --- Batch 2: Post-context operations (plugin scan + community pull) ---
179
+ const postContextOps = [];
180
+
181
+ // Plugin auto-scan (non-blocking)
182
+ postContextOps.push((async () => {
183
+ try {
184
+ const config = getConfig();
185
+ if (config.plugins?.enabled && config.plugins?.autoScanOnSessionStart) {
186
+ const { scanUnregisteredMcpServers, registerPlugin, deactivateStaleMcpPlugins, listPlugins } = require('../../../flow-plugin-registry');
187
+
188
+ const unregistered = scanUnregisteredMcpServers();
189
+ for (const server of unregistered) {
190
+ registerPlugin({
191
+ name: server.serverName,
192
+ description: `Auto-discovered MCP server: ${server.serverName}`,
193
+ source: 'auto-scan',
194
+ triggers: [`use ${server.serverName}`, `send to ${server.serverName}`, server.serverName],
195
+ capabilities: [],
196
+ metadata: { mcpServer: server.serverName }
197
+ });
198
+ if (process.env.DEBUG) {
199
+ console.error(`[session-start] Auto-registered plugin: ${server.serverName}`);
220
200
  }
201
+ }
221
202
 
222
- const deactivated = deactivateStaleMcpPlugins();
223
- if (deactivated.length > 0 && process.env.DEBUG) {
224
- console.error(`[session-start] Deactivated ${deactivated.length} stale plugin(s): ${deactivated.join(', ')}`);
225
- }
203
+ const deactivated = deactivateStaleMcpPlugins();
204
+ if (deactivated.length > 0 && process.env.DEBUG) {
205
+ console.error(`[session-start] Deactivated ${deactivated.length} stale plugin(s): ${deactivated.join(', ')}`);
206
+ }
226
207
 
227
- if (coreResult && coreResult.context) {
228
- const activePlugins = listPlugins({ activeOnly: true });
229
- if (unregistered.length > 0 || activePlugins.length > 0) {
230
- coreResult.context.pluginScan = {
231
- newlyRegistered: unregistered.map(s => s.serverName),
232
- activePlugins: activePlugins.map(p => ({ name: p.name, capabilities: (p.capabilities || []).length }))
233
- };
234
- }
208
+ if (coreResult && coreResult.context) {
209
+ const activePlugins = listPlugins({ activeOnly: true });
210
+ if (unregistered.length > 0 || activePlugins.length > 0) {
211
+ coreResult.context.pluginScan = {
212
+ newlyRegistered: unregistered.map(s => s.serverName),
213
+ activePlugins: activePlugins.map(p => ({ name: p.name, capabilities: (p.capabilities || []).length }))
214
+ };
235
215
  }
236
216
  }
237
- } catch (err) {
238
- if (process.env.DEBUG) {
239
- console.error(`[session-start] Plugin auto-scan failed: ${err.message}`);
240
- }
241
217
  }
242
- })());
243
-
244
- // Community knowledge pull + suggestion retry (non-blocking)
245
- postContextOps.push((async () => {
246
- try {
247
- const communityConfig = getConfig();
248
- if (communityConfig.community?.enabled) {
249
- const community = require('../../../flow-community');
250
-
251
- community.retryPendingSuggestions(communityConfig).catch(() => {});
252
-
253
- if (communityConfig.community?.pullOnSessionStart !== false) {
254
- const knowledge = await community.pullFromServer(communityConfig);
255
- if (knowledge && coreResult && coreResult.context) {
256
- coreResult.context.communityKnowledge = knowledge;
218
+ } catch (err) {
219
+ if (process.env.DEBUG) {
220
+ console.error(`[session-start] Plugin auto-scan failed: ${err.message}`);
221
+ }
222
+ }
223
+ })());
257
224
 
258
- try {
259
- community.mergeCommunityKnowledge(knowledge, communityConfig);
260
- } catch (err) {
261
- if (process.env.DEBUG) {
262
- console.error(`[session-start] Community merge failed: ${err.message}`);
263
- }
225
+ // Community knowledge pull + suggestion retry (non-blocking)
226
+ postContextOps.push((async () => {
227
+ try {
228
+ const communityConfig = getConfig();
229
+ if (communityConfig.community?.enabled) {
230
+ const community = require('../../../flow-community');
231
+
232
+ community.retryPendingSuggestions(communityConfig).catch(() => {});
233
+
234
+ if (communityConfig.community?.pullOnSessionStart !== false) {
235
+ const knowledge = await community.pullFromServer(communityConfig);
236
+ if (knowledge && coreResult && coreResult.context) {
237
+ coreResult.context.communityKnowledge = knowledge;
238
+
239
+ try {
240
+ community.mergeCommunityKnowledge(knowledge, communityConfig);
241
+ } catch (err) {
242
+ if (process.env.DEBUG) {
243
+ console.error(`[session-start] Community merge failed: ${err.message}`);
264
244
  }
265
245
  }
266
246
  }
267
247
  }
268
- } catch (err) {
269
- if (process.env.DEBUG) {
270
- console.error(`[session-start] Community pull failed: ${err.message}`);
271
- }
272
248
  }
273
- })());
274
-
275
- await Promise.all(postContextOps);
276
-
277
- // Inject script warnings into context (if any)
278
- if (scriptWarnings.length > 0 && coreResult && coreResult.context) {
279
- coreResult.context.scriptWarnings = scriptWarnings.map(w => w.message);
249
+ } catch (err) {
250
+ if (process.env.DEBUG) {
251
+ console.error(`[session-start] Community pull failed: ${err.message}`);
252
+ }
280
253
  }
254
+ })());
281
255
 
282
- // Inject version compatibility warning (if any)
283
- if (versionWarning && coreResult && coreResult.context) {
284
- coreResult.context.versionWarning = versionWarning;
285
- }
256
+ await Promise.all(postContextOps);
286
257
 
287
- // Inject WogiFlow update warning (if any)
288
- if (updateWarning && coreResult && coreResult.context) {
289
- coreResult.context.updateWarning = updateWarning;
290
- }
258
+ // Inject script warnings into context (if any)
259
+ if (scriptWarnings.length > 0 && coreResult && coreResult.context) {
260
+ coreResult.context.scriptWarnings = scriptWarnings.map(w => w.message);
261
+ }
291
262
 
292
- // Inject drift detection results (if any)
293
- if (driftDetected && coreResult && coreResult.context) {
294
- if (driftMarkerMissing) {
295
- coreResult.context.driftWarning = 'CLAUDE.md appears to have been manually edited (generation marker missing). Was this intentional? If yes, WogiFlow will respect your custom CLAUDE.md. If not, run `flow bridge sync` to regenerate from template.';
296
- } else {
297
- coreResult.context.driftWarning = 'CLAUDE.md content has changed since the last bridge sync. Was this intentional? If yes, WogiFlow will preserve your changes. If not, run `flow bridge sync` to regenerate from template.';
298
- }
299
- }
263
+ // Inject version compatibility warning (if any)
264
+ if (versionWarning && coreResult && coreResult.context) {
265
+ coreResult.context.versionWarning = versionWarning;
266
+ }
300
267
 
301
- // Transform to Claude Code format
302
- const output = claudeCodeAdapter.transformResult('SessionStart', coreResult);
268
+ // Inject WogiFlow update warning (if any)
269
+ if (updateWarning && coreResult && coreResult.context) {
270
+ coreResult.context.updateWarning = updateWarning;
271
+ }
303
272
 
304
- // Output JSON
305
- console.log(JSON.stringify(output));
306
- process.exit(0);
307
- } catch (err) {
308
- // Non-blocking error - log with unified handler, exit 1
309
- try {
310
- const { logHookError } = require('../../../flow-hook-errors');
311
- logHookError('SessionStart', err, { failMode: 'open', operation: 'session-initialization' });
312
- } catch (logErr) {
313
- console.error(`[WogiFlow] SessionStart hook error: ${err.message}`);
273
+ // Inject drift detection results (if any)
274
+ if (driftDetected && coreResult && coreResult.context) {
275
+ if (driftMarkerMissing) {
276
+ coreResult.context.driftWarning = 'CLAUDE.md appears to have been manually edited (generation marker missing). Was this intentional? If yes, WogiFlow will respect your custom CLAUDE.md. If not, run `flow bridge sync` to regenerate from template.';
277
+ } else {
278
+ coreResult.context.driftWarning = 'CLAUDE.md content has changed since the last bridge sync. Was this intentional? If yes, WogiFlow will preserve your changes. If not, run `flow bridge sync` to regenerate from template.';
314
279
  }
315
- process.exit(1);
316
280
  }
317
- }
318
281
 
319
- // Handle stdin properly
320
- process.stdin.setEncoding('utf8');
321
- main();
282
+ return coreResult;
283
+ }, { failMode: 'warn' });
@@ -10,55 +10,14 @@
10
10
  */
11
11
 
12
12
  const { handleSetup, handleMaintenance } = require('../../core/setup-handler');
13
- const { claudeCodeAdapter } = require('../../adapters/claude-code');
14
- const { readHookInput } = require('../shared/read-stdin');
13
+ const { runHook } = require('../shared/hook-runner');
15
14
 
16
- async function main() {
17
- try {
18
- const { input: parsedStdin } = await readHookInput();
19
- const input = parsedStdin || {};
20
- const parsedInput = claudeCodeAdapter.parseInput(input);
15
+ runHook('Setup', async ({ parsedInput }) => {
16
+ const trigger = parsedInput.source || 'init';
17
+ const isMaintenance = trigger === 'maintenance' || trigger === '--maintenance';
21
18
 
22
- // Determine what type of setup event this is
23
- // Claude Code passes the trigger via source or a specific field
24
- const trigger = parsedInput.source || 'init';
25
- const isMaintenance = trigger === 'maintenance' || trigger === '--maintenance';
26
-
27
- let coreResult;
28
-
29
- if (isMaintenance) {
30
- // Run maintenance tasks
31
- coreResult = handleMaintenance({
32
- cwd: parsedInput.cwd
33
- });
34
- } else {
35
- // Run setup check
36
- coreResult = handleSetup({
37
- trigger,
38
- cwd: parsedInput.cwd
39
- });
40
- }
41
-
42
- // Transform to Claude Code format
43
- const output = claudeCodeAdapter.transformResult('Setup', coreResult);
44
-
45
- // Output JSON
46
- console.log(JSON.stringify(output));
47
- process.exit(0);
48
- } catch (err) {
49
- // Non-blocking error - log to stderr, exit with allow
50
- console.error(`[Wogi Flow Hook Error] ${err.message}`);
51
- // Exit 0 with allow to not block on hook errors (graceful degradation)
52
- console.log(JSON.stringify({
53
- continue: true,
54
- hookSpecificOutput: {
55
- hookEventName: 'Setup'
56
- }
57
- }));
58
- process.exit(0);
19
+ if (isMaintenance) {
20
+ return handleMaintenance({ cwd: parsedInput.cwd });
59
21
  }
60
- }
61
-
62
- // Handle stdin properly
63
- process.stdin.setEncoding('utf8');
64
- main();
22
+ return handleSetup({ trigger, cwd: parsedInput.cwd });
23
+ }, { failMode: 'silent' });