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.
- package/.claude/commands/wogi-start.md +124 -0
- package/.claude/docs/claude-code-compatibility.md +51 -0
- package/.claude/docs/explore-agents.md +11 -0
- package/.claude/settings.json +12 -1
- package/.workflow/models/registry.json +1 -1
- package/bin/flow +11 -1
- package/lib/workspace-contracts.js +599 -0
- package/lib/workspace-intelligence.js +600 -0
- package/lib/workspace-messages.js +441 -0
- package/lib/workspace-routing.js +485 -0
- package/lib/workspace-sync.js +339 -0
- package/lib/workspace.js +1073 -0
- package/package.json +4 -4
- package/scripts/MEMORY-ARCHITECTURE.md +1 -1
- package/scripts/base-workflow-step.js +136 -0
- package/scripts/flow-adaptive-learning.js +8 -9
- package/scripts/flow-aggregate.js +11 -6
- package/scripts/flow-api-index.js +4 -6
- package/scripts/flow-assumption-detector.js +0 -2
- package/scripts/flow-audit.js +15 -2
- package/scripts/flow-auto-context.js +8 -12
- package/scripts/flow-auto-learn.js +49 -49
- package/scripts/flow-background.js +5 -6
- package/scripts/flow-bridge-state.js +8 -10
- package/scripts/flow-bulk-loop.js +1 -3
- package/scripts/flow-bulk-orchestrator.js +1 -3
- package/scripts/flow-cascade-completion.js +0 -2
- package/scripts/flow-cascade.js +4 -4
- package/scripts/flow-checkpoint.js +10 -13
- package/scripts/flow-code-intelligence.js +10 -12
- package/scripts/flow-community-sync.js +4 -4
- package/scripts/flow-community.js +12 -20
- package/scripts/flow-config-defaults.js +28 -2
- package/scripts/flow-config-interactive.js +9 -5
- package/scripts/flow-config-loader.js +49 -92
- package/scripts/flow-config-substitution.js +0 -2
- package/scripts/flow-context-estimator.js +4 -4
- package/scripts/flow-context-init.js +10 -12
- package/scripts/flow-context-manager.js +0 -2
- package/scripts/flow-context-scoring.js +2 -2
- package/scripts/flow-contract-scan.js +6 -9
- package/scripts/flow-correct.js +29 -27
- package/scripts/flow-correction-detector.js +5 -1
- package/scripts/flow-damage-control.js +47 -54
- package/scripts/flow-decisions-merge.js +4 -14
- package/scripts/flow-diff.js +5 -8
- package/scripts/flow-done-gates.js +786 -0
- package/scripts/flow-done-report.js +123 -0
- package/scripts/flow-done.js +71 -717
- package/scripts/flow-entropy-monitor.js +1 -3
- package/scripts/flow-eval-calibration.js +257 -0
- package/scripts/flow-eval-judge.js +10 -1
- package/scripts/flow-eval.js +14 -5
- package/scripts/flow-extraction-review.js +1 -0
- package/scripts/flow-failure-categories.js +0 -2
- package/scripts/flow-figma-confirm.js +5 -9
- package/scripts/flow-figma-generate.js +8 -10
- package/scripts/flow-figma-index.js +8 -10
- package/scripts/flow-figma-match.js +3 -5
- package/scripts/flow-figma-mcp-server.js +2 -4
- package/scripts/flow-figma-orchestrator.js +2 -3
- package/scripts/flow-figma-registry.js +2 -3
- package/scripts/flow-framework-resolver.js +0 -2
- package/scripts/flow-function-index.js +4 -6
- package/scripts/flow-gate-confidence.js +2 -2
- package/scripts/flow-gitignore.js +0 -2
- package/scripts/flow-guided-edit.js +5 -6
- package/scripts/flow-health.js +5 -6
- package/scripts/flow-hook-errors.js +6 -0
- package/scripts/flow-hook-status.js +263 -0
- package/scripts/flow-hooks.js +17 -29
- package/scripts/flow-http-client.js +9 -8
- package/scripts/flow-hybrid-interactive.js +7 -12
- package/scripts/flow-hybrid-test.js +12 -13
- package/scripts/flow-instruction-richness.js +1 -1
- package/scripts/flow-io.js +21 -4
- package/scripts/flow-knowledge-router.js +9 -3
- package/scripts/flow-learning-orchestrator.js +318 -13
- package/scripts/flow-links.js +5 -7
- package/scripts/flow-long-input-association.js +275 -0
- package/scripts/flow-long-input-chunking.js +1 -0
- package/scripts/flow-long-input-cli.js +0 -2
- package/scripts/flow-long-input-complexity.js +0 -2
- package/scripts/flow-long-input-constants.js +0 -2
- package/scripts/flow-long-input-contradictions.js +351 -0
- package/scripts/flow-long-input-detection.js +0 -2
- package/scripts/flow-long-input-passes.js +885 -0
- package/scripts/flow-long-input-stories.js +1 -1
- package/scripts/flow-long-input-voice.js +0 -2
- package/scripts/flow-long-input.js +425 -3005
- package/scripts/flow-loop-retry-learning.js +2 -3
- package/scripts/flow-lsp.js +3 -3
- package/scripts/flow-mcp-docs.js +3 -4
- package/scripts/flow-memory-db.js +6 -8
- package/scripts/flow-memory-sync.js +18 -11
- package/scripts/flow-metrics.js +1 -2
- package/scripts/flow-model-adapter.js +2 -3
- package/scripts/flow-model-config.js +72 -104
- package/scripts/flow-model-router.js +2 -2
- package/scripts/flow-model-types.js +0 -2
- package/scripts/flow-multi-approach.js +5 -6
- package/scripts/flow-orchestrate-context.js +3 -7
- package/scripts/flow-orchestrate-rollback.js +3 -8
- package/scripts/flow-orchestrate-state.js +8 -14
- package/scripts/flow-orchestrate-templates.js +2 -6
- package/scripts/flow-orchestrate-validator.js +5 -9
- package/scripts/flow-orchestrate.js +126 -103
- package/scripts/flow-output.js +0 -2
- package/scripts/flow-parallel.js +1 -1
- package/scripts/flow-paths.js +23 -2
- package/scripts/flow-pattern-enforcer.js +30 -28
- package/scripts/flow-pattern-extractor.js +3 -4
- package/scripts/flow-pending.js +0 -2
- package/scripts/flow-permissions.js +2 -3
- package/scripts/flow-plugin-registry.js +10 -12
- package/scripts/flow-prd-manager.js +1 -1
- package/scripts/flow-progress.js +7 -9
- package/scripts/flow-prompt-composer.js +3 -3
- package/scripts/flow-prompt-template.js +2 -2
- package/scripts/flow-providers.js +7 -4
- package/scripts/flow-registry-manager.js +7 -12
- package/scripts/flow-regression.js +9 -11
- package/scripts/flow-roadmap.js +2 -2
- package/scripts/flow-run-trace.js +16 -15
- package/scripts/flow-safety.js +2 -5
- package/scripts/flow-scanner-base.js +5 -7
- package/scripts/flow-scenario-engine.js +1 -5
- package/scripts/flow-security.js +29 -0
- package/scripts/flow-session-end.js +32 -41
- package/scripts/flow-session-learning.js +53 -49
- package/scripts/flow-setup-hooks.js +2 -3
- package/scripts/flow-skill-create.js +7 -12
- package/scripts/flow-skill-generator.js +12 -16
- package/scripts/flow-skill-learn.js +17 -8
- package/scripts/flow-skill-matcher.js +1 -2
- package/scripts/flow-spec-generator.js +2 -4
- package/scripts/flow-stack-wizard.js +5 -7
- package/scripts/flow-standards-learner.js +35 -16
- package/scripts/flow-start.js +2 -0
- package/scripts/flow-stats-collector.js +2 -2
- package/scripts/flow-status.js +10 -10
- package/scripts/flow-statusline-setup.js +2 -2
- package/scripts/flow-step-changelog.js +2 -3
- package/scripts/flow-step-comments.js +66 -81
- package/scripts/flow-step-complexity.js +50 -70
- package/scripts/flow-step-coverage.js +3 -5
- package/scripts/flow-step-knowledge.js +2 -3
- package/scripts/flow-step-pr-tests.js +64 -74
- package/scripts/flow-step-regression.js +3 -5
- package/scripts/flow-step-review.js +86 -103
- package/scripts/flow-step-security.js +111 -121
- package/scripts/flow-step-silent-failures.js +56 -83
- package/scripts/flow-step-simplifier.js +52 -70
- package/scripts/flow-story.js +4 -7
- package/scripts/flow-strict-adherence.js +3 -4
- package/scripts/flow-task-checkpoint.js +36 -5
- package/scripts/flow-task-enforcer.js +2 -24
- package/scripts/flow-tech-debt.js +1 -1
- package/scripts/flow-template-extractor.js +1 -0
- package/scripts/flow-templates.js +11 -13
- package/scripts/flow-test-api.js +9 -13
- package/scripts/flow-test-discovery.js +1 -1
- package/scripts/flow-test-generate.js +5 -9
- package/scripts/flow-test-integrity.js +3 -7
- package/scripts/flow-test-ui.js +5 -9
- package/scripts/flow-testing-deps.js +1 -3
- package/scripts/flow-tiered-learning.js +4 -4
- package/scripts/flow-todowrite-sync.js +1 -1
- package/scripts/flow-tokens.js +0 -2
- package/scripts/flow-verification-profile.js +6 -10
- package/scripts/flow-verify.js +12 -16
- package/scripts/flow-version-check.js +4 -12
- package/scripts/flow-webmcp-generator.js +3 -5
- package/scripts/flow-workflow-steps.js +0 -2
- package/scripts/flow-workflow.js +9 -11
- package/scripts/hooks/adapters/claude-code.js +31 -0
- package/scripts/hooks/core/config-change.js +1 -0
- package/scripts/hooks/core/extension-registry.js +0 -2
- package/scripts/hooks/core/instructions-loaded.js +1 -1
- package/scripts/hooks/core/observation-capture.js +5 -5
- package/scripts/hooks/core/phase-gate.js +5 -0
- package/scripts/hooks/core/post-compact.js +1 -12
- package/scripts/hooks/core/research-gate.js +2 -12
- package/scripts/hooks/core/routing-gate.js +6 -0
- package/scripts/hooks/core/task-completed.js +12 -0
- package/scripts/hooks/core/task-created.js +83 -0
- package/scripts/hooks/core/worktree-lifecycle.js +1 -1
- package/scripts/hooks/entry/claude-code/config-change.js +6 -29
- package/scripts/hooks/entry/claude-code/instructions-loaded.js +5 -30
- package/scripts/hooks/entry/claude-code/post-compact.js +4 -31
- package/scripts/hooks/entry/claude-code/post-tool-use.js +121 -172
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +260 -361
- package/scripts/hooks/entry/claude-code/session-end.js +4 -28
- package/scripts/hooks/entry/claude-code/session-start.js +205 -243
- package/scripts/hooks/entry/claude-code/setup.js +8 -49
- package/scripts/hooks/entry/claude-code/stop.js +40 -72
- package/scripts/hooks/entry/claude-code/task-completed.js +4 -28
- package/scripts/hooks/entry/claude-code/task-created.js +15 -0
- package/scripts/hooks/entry/claude-code/user-prompt-submit.js +113 -195
- package/scripts/hooks/entry/claude-code/worktree-create.js +6 -25
- package/scripts/hooks/entry/claude-code/worktree-remove.js +6 -25
- package/scripts/hooks/entry/shared/hook-runner.js +99 -0
- package/scripts/hooks/entry/shared/read-stdin.js +0 -2
- package/scripts/postinstall.js +2 -0
- package/scripts/registries/api-registry.js +0 -2
- package/scripts/registries/component-registry.js +5 -9
- package/scripts/registries/contract-scanner.js +2 -9
- package/scripts/registries/function-registry.js +0 -2
- package/scripts/registries/schema-registry.js +14 -18
- package/scripts/registries/service-registry.js +23 -27
|
@@ -14,85 +14,53 @@
|
|
|
14
14
|
|
|
15
15
|
const { checkLoopExit } = require('../../core/loop-check');
|
|
16
16
|
const { isRoutingPending, incrementStopAttempts } = require('../../core/routing-gate');
|
|
17
|
-
const {
|
|
18
|
-
const { readHookInput } = require('../shared/read-stdin');
|
|
17
|
+
const { runHook } = require('../shared/hook-runner');
|
|
19
18
|
|
|
20
|
-
async
|
|
19
|
+
runHook('Stop', async ({ parsedInput }) => {
|
|
20
|
+
// v6.2: Routing enforcement check — catches text-only response bypass
|
|
21
|
+
// If routing-pending flag is still set when the AI tries to stop, it means
|
|
22
|
+
// the AI responded to the user's message without ever invoking a /wogi-* command.
|
|
23
|
+
// This is the exact bypass we need to prevent (especially after context compaction).
|
|
21
24
|
try {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
if (isRoutingPending()) {
|
|
26
|
+
// Use counter-based approach instead of clearing immediately.
|
|
27
|
+
// This gives the AI multiple chances to comply before giving up.
|
|
28
|
+
// Gap 4 fix: clearing immediately made this single-shot protection.
|
|
29
|
+
const { cleared, attempts } = incrementStopAttempts(10);
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
if (isRoutingPending()) {
|
|
32
|
-
// Use counter-based approach instead of clearing immediately.
|
|
33
|
-
// This gives the AI multiple chances to comply before giving up.
|
|
34
|
-
// Gap 4 fix: clearing immediately made this single-shot protection.
|
|
35
|
-
const { cleared, attempts } = incrementStopAttempts(10);
|
|
36
|
-
|
|
37
|
-
if (cleared) {
|
|
38
|
-
// Max attempts reached — allow stop to prevent infinite loop
|
|
39
|
-
if (process.env.DEBUG) {
|
|
40
|
-
console.error(`[Stop] Max routing enforcement attempts reached (${attempts}), allowing stop`);
|
|
41
|
-
}
|
|
42
|
-
// Fall through to normal stop logic
|
|
43
|
-
} else {
|
|
44
|
-
// Block the stop — force the AI to route through /wogi-start
|
|
45
|
-
const routingMessage = [
|
|
46
|
-
`ROUTING VIOLATION (attempt ${attempts}/10): You MUST call Skill(skill="wogi-start") before responding.`,
|
|
47
|
-
'',
|
|
48
|
-
'Call Skill(skill="wogi-start", args="<user\'s message>") NOW. No text. No explanation. Just the Skill tool call.'
|
|
49
|
-
].join('\n');
|
|
50
|
-
|
|
51
|
-
console.log(JSON.stringify({
|
|
52
|
-
continue: true, // Force continue — don't let the AI stop
|
|
53
|
-
stopReason: routingMessage
|
|
54
|
-
}));
|
|
55
|
-
process.exit(0);
|
|
56
|
-
return;
|
|
31
|
+
if (cleared) {
|
|
32
|
+
// Max attempts reached — allow stop to prevent infinite loop
|
|
33
|
+
if (process.env.DEBUG) {
|
|
34
|
+
console.error(`[Stop] Max routing enforcement attempts reached (${attempts}), allowing stop`);
|
|
57
35
|
}
|
|
36
|
+
// Fall through to normal stop logic
|
|
37
|
+
} else {
|
|
38
|
+
// Block the stop — force the AI to route through /wogi-start
|
|
39
|
+
const routingMessage = [
|
|
40
|
+
`ROUTING VIOLATION (attempt ${attempts}/10): You MUST call Skill(skill="wogi-start") before responding.`,
|
|
41
|
+
'',
|
|
42
|
+
'Call Skill(skill="wogi-start", args="<user\'s message>") NOW. No text. No explanation. Just the Skill tool call.'
|
|
43
|
+
].join('\n');
|
|
44
|
+
|
|
45
|
+
// Return raw output — skip adapter transform for routing enforcement
|
|
46
|
+
// (this needs { continue: true, stopReason } format directly)
|
|
47
|
+
return { __raw: true, continue: true, stopReason: routingMessage };
|
|
58
48
|
}
|
|
59
|
-
} catch (err) {
|
|
60
|
-
// Fail-CLOSED for routing check — force continuation on errors.
|
|
61
|
-
// Gap 5 fix: failing open here disabled the last line of defense.
|
|
62
|
-
// Worst case: AI retries and hits the 3-attempt limit, which clears naturally.
|
|
63
|
-
if (process.env.DEBUG) {
|
|
64
|
-
console.error(`[Stop] Routing check error (fail-closed, forcing continue): ${err.message}`);
|
|
65
|
-
}
|
|
66
|
-
console.log(JSON.stringify({
|
|
67
|
-
continue: true,
|
|
68
|
-
stopReason: 'Routing enforcement check encountered an error. Please invoke /wogi-start with your request.'
|
|
69
|
-
}));
|
|
70
|
-
process.exit(0);
|
|
71
|
-
return;
|
|
72
49
|
}
|
|
73
|
-
|
|
74
|
-
// Check if loop can exit
|
|
75
|
-
const coreResult = await checkLoopExit();
|
|
76
|
-
|
|
77
|
-
// Transform to Claude Code format
|
|
78
|
-
const output = claudeCodeAdapter.transformResult('Stop', coreResult);
|
|
79
|
-
|
|
80
|
-
// Output JSON
|
|
81
|
-
console.log(JSON.stringify(output));
|
|
82
|
-
process.exit(0);
|
|
83
50
|
} catch (err) {
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.error(`[WogiFlow] Stop hook error: ${err.message}`);
|
|
51
|
+
// Fail-CLOSED for routing check — force continuation on errors.
|
|
52
|
+
// Gap 5 fix: failing open here disabled the last line of defense.
|
|
53
|
+
// Worst case: AI retries and hits the 3-attempt limit, which clears naturally.
|
|
54
|
+
if (process.env.DEBUG) {
|
|
55
|
+
console.error(`[Stop] Routing check error (fail-closed, forcing continue): ${err.message}`);
|
|
90
56
|
}
|
|
91
|
-
|
|
92
|
-
|
|
57
|
+
return {
|
|
58
|
+
__raw: true,
|
|
59
|
+
continue: true,
|
|
60
|
+
stopReason: 'Routing enforcement check encountered an error. Please invoke /wogi-start with your request.'
|
|
61
|
+
};
|
|
93
62
|
}
|
|
94
|
-
}
|
|
95
63
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
64
|
+
// Check if loop can exit
|
|
65
|
+
return await checkLoopExit();
|
|
66
|
+
}, { failMode: 'warn', failOutput: { continue: false } });
|
|
@@ -8,32 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
const { handleTaskCompleted } = require('../../core/task-completed');
|
|
11
|
-
const {
|
|
12
|
-
const { readHookInput } = require('../shared/read-stdin');
|
|
11
|
+
const { runHook } = require('../shared/hook-runner');
|
|
13
12
|
|
|
14
|
-
async
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const input = parsedStdin || {};
|
|
18
|
-
const parsedInput = claudeCodeAdapter.parseInput(input);
|
|
19
|
-
|
|
20
|
-
// Handle task completion
|
|
21
|
-
const coreResult = await handleTaskCompleted(parsedInput);
|
|
22
|
-
|
|
23
|
-
// Transform to Claude Code format
|
|
24
|
-
const output = claudeCodeAdapter.transformResult('TaskCompleted', coreResult);
|
|
25
|
-
|
|
26
|
-
// Output JSON
|
|
27
|
-
console.log(JSON.stringify(output));
|
|
28
|
-
process.exit(0);
|
|
29
|
-
} catch (err) {
|
|
30
|
-
// Non-blocking error - don't prevent task completion
|
|
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('TaskCompleted', async ({ parsedInput }) => {
|
|
14
|
+
return await handleTaskCompleted(parsedInput);
|
|
15
|
+
}, { failMode: 'silent' });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Claude Code TaskCreated Hook
|
|
5
|
+
*
|
|
6
|
+
* Called when a native task is created via TaskCreate (Claude Code 2.1.84+).
|
|
7
|
+
* Links native tasks to the active WogiFlow task for tracking.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { handleTaskCreated } = require('../../core/task-created');
|
|
11
|
+
const { runHook } = require('../shared/hook-runner');
|
|
12
|
+
|
|
13
|
+
runHook('TaskCreated', async ({ parsedInput }) => {
|
|
14
|
+
return await handleTaskCreated(parsedInput);
|
|
15
|
+
}, { failMode: 'silent' });
|
|
@@ -12,241 +12,159 @@ const { checkImplementationGate } = require('../../core/implementation-gate');
|
|
|
12
12
|
const { checkResearchRequirement } = require('../../core/research-gate');
|
|
13
13
|
const { setRoutingPending, clearRoutingPending, ROUTING_CLEARED_PATH } = require('../../core/routing-gate');
|
|
14
14
|
const { getPhaseContextPrompt } = require('../../core/phase-gate');
|
|
15
|
-
const { claudeCodeAdapter } = require('../../adapters/claude-code');
|
|
16
15
|
const { markSkillPending, loadDurableSession } = require('../../../flow-durable-session');
|
|
17
16
|
const { captureCurrentPrompt } = require('../../../flow-prompt-capture');
|
|
18
17
|
const { spawnBackgroundDetection } = require('../../../flow-correction-detector');
|
|
19
18
|
const { getConfig } = require('../../../flow-utils');
|
|
20
|
-
const {
|
|
19
|
+
const { runHook } = require('../shared/hook-runner');
|
|
21
20
|
|
|
22
|
-
async
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!parsedStdin) {
|
|
28
|
-
console.log(JSON.stringify({ continue: true, hookSpecificOutput: { hookEventName: 'UserPromptSubmit' } }));
|
|
29
|
-
process.exit(0);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Parse JSON safely with prototype pollution protection
|
|
34
|
-
let input;
|
|
35
|
-
try {
|
|
36
|
-
input = parsedStdin;
|
|
37
|
-
if (!input) {
|
|
38
|
-
// Invalid JSON - allow through (graceful degradation)
|
|
39
|
-
console.log(JSON.stringify({ continue: true, hookSpecificOutput: { hookEventName: 'UserPromptSubmit' } }));
|
|
40
|
-
process.exit(0);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
} catch (err) {
|
|
44
|
-
// Parse error - allow through (graceful degradation)
|
|
45
|
-
console.log(JSON.stringify({ continue: true, hookSpecificOutput: { hookEventName: 'UserPromptSubmit' } }));
|
|
46
|
-
process.exit(0);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const parsedInput = claudeCodeAdapter.parseInput(input);
|
|
21
|
+
runHook('UserPromptSubmit', async ({ input, parsedInput }) => {
|
|
22
|
+
// Handle empty input gracefully
|
|
23
|
+
if (!input || Object.keys(input).length === 0) {
|
|
24
|
+
return { __raw: true, continue: true, hookSpecificOutput: { hookEventName: 'UserPromptSubmit' } };
|
|
25
|
+
}
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
27
|
+
const prompt = parsedInput.prompt;
|
|
28
|
+
const source = parsedInput.source;
|
|
54
29
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
console.error(`[Hook] Marked /${skillName} as pending execution`);
|
|
64
|
-
}
|
|
30
|
+
// v4.1: Detect skill commands that need execution tracking
|
|
31
|
+
if (typeof prompt === 'string') {
|
|
32
|
+
const skillMatch = prompt.match(/^\/(wogi-bulk|wogi-start)\b/i);
|
|
33
|
+
if (skillMatch) {
|
|
34
|
+
const skillName = skillMatch[1].toLowerCase();
|
|
35
|
+
markSkillPending(skillName, { prompt });
|
|
36
|
+
if (process.env.DEBUG) {
|
|
37
|
+
console.error(`[Hook] Marked /${skillName} as pending execution`);
|
|
65
38
|
}
|
|
66
39
|
}
|
|
40
|
+
}
|
|
67
41
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
42
|
+
// Load config once for feature flag checks
|
|
43
|
+
let hookConfig;
|
|
44
|
+
try {
|
|
45
|
+
hookConfig = getConfig();
|
|
46
|
+
} catch (err) {
|
|
47
|
+
hookConfig = {};
|
|
48
|
+
}
|
|
75
49
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
|
|
50
|
+
// v5.0: Capture prompt for learning system (non-blocking)
|
|
51
|
+
if (hookConfig.hooks?.rules?.intelligence?.promptCapture?.enabled !== false) {
|
|
52
|
+
if (typeof prompt === 'string' && prompt.trim().length > 0) {
|
|
53
|
+
setImmediate(() => {
|
|
80
54
|
try {
|
|
81
55
|
captureCurrentPrompt(prompt);
|
|
82
56
|
} catch (err) {
|
|
83
|
-
// Non-blocking - don't fail the hook if capture fails
|
|
84
57
|
if (process.env.DEBUG) {
|
|
85
58
|
console.error(`[Hook] Prompt capture failed: ${err.message}`);
|
|
86
59
|
}
|
|
87
60
|
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// v5.1→v7.0: Detect corrections for learning system (AI-only, non-blocking)
|
|
92
|
-
// Controlled by hooks.rules.intelligence.correctionDetection.enabled
|
|
93
|
-
if (hookConfig.hooks?.rules?.intelligence?.correctionDetection?.enabled !== false) {
|
|
94
|
-
if (typeof prompt === 'string' && prompt.trim().length > 0) {
|
|
95
|
-
try {
|
|
96
|
-
const session = loadDurableSession();
|
|
97
|
-
spawnBackgroundDetection(prompt, session?.taskId || '');
|
|
98
|
-
} catch (err) {
|
|
99
|
-
// Non-blocking - don't fail the hook if detection spawn fails
|
|
100
|
-
if (process.env.DEBUG) {
|
|
101
|
-
console.error(`[Hook] Correction detection spawn failed: ${err.message}`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
61
|
+
});
|
|
105
62
|
}
|
|
63
|
+
}
|
|
106
64
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// Exception: skipped when the prompt IS a /wogi-* command (see isWogiCommand below).
|
|
111
|
-
// v6.1: Also skip when the prompt IS a /wogi-* command — the user is already routing.
|
|
112
|
-
// When users type "/wogi-start ..." directly, Claude Code expands the skill inline
|
|
113
|
-
// (not through the Skill tool), so clearRoutingPending() in PreToolUse never fires.
|
|
114
|
-
// Setting the flag here would create an uncleable block.
|
|
115
|
-
// Tightened regex: only match /wogi-[lowercase-alphanumeric-hyphens] to prevent
|
|
116
|
-
// injection via crafted prompts like "/wogi-<script>" or "/wogi-../../path"
|
|
117
|
-
const isWogiCommand = typeof prompt === 'string' && /^\/wogi-[a-z0-9-]+\b/i.test(prompt.trim());
|
|
118
|
-
if (!isWogiCommand) {
|
|
119
|
-
// v8.1: Delete any stale cleared marker from previous turns.
|
|
120
|
-
// The cleared marker prevents flag re-setting during skill chains (same AI response).
|
|
121
|
-
// But across user turns, it must not persist — otherwise tools are unblocked without
|
|
122
|
-
// routing for the duration of the marker's TTL. A new user prompt (non-wogi-command)
|
|
123
|
-
// is unambiguously a new turn, so the old marker is invalidated.
|
|
124
|
-
try {
|
|
125
|
-
fs.unlinkSync(ROUTING_CLEARED_PATH);
|
|
126
|
-
} catch (err) {
|
|
127
|
-
// ENOENT is fine — no marker to delete
|
|
128
|
-
if (err.code !== 'ENOENT' && process.env.DEBUG) {
|
|
129
|
-
console.error(`[Hook] Failed to delete cleared marker: ${err.message}`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
setRoutingPending();
|
|
135
|
-
} catch (err) {
|
|
136
|
-
// Non-blocking - don't fail the hook if routing gate fails (fail-open)
|
|
137
|
-
if (process.env.DEBUG) {
|
|
138
|
-
console.error(`[Hook] Routing gate set failed: ${err.message}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
// v6.2: Actively CLEAR any existing routing flag when user explicitly types a /wogi-* command.
|
|
143
|
-
// Previously we only skipped setting it, but a flag from a prior prompt would persist and
|
|
144
|
-
// block tool calls inside the /wogi-* command when Claude Code expands it inline (not via Skill tool).
|
|
65
|
+
// v5.1->v7.0: Detect corrections for learning system (AI-only, non-blocking)
|
|
66
|
+
if (hookConfig.hooks?.rules?.intelligence?.correctionDetection?.enabled !== false) {
|
|
67
|
+
if (typeof prompt === 'string' && prompt.trim().length > 0) {
|
|
145
68
|
try {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
console.error(`[Hook] Cleared routing flag — prompt is a /wogi-* command`);
|
|
149
|
-
}
|
|
69
|
+
const session = loadDurableSession();
|
|
70
|
+
spawnBackgroundDetection(prompt, session?.taskId || '');
|
|
150
71
|
} catch (err) {
|
|
151
72
|
if (process.env.DEBUG) {
|
|
152
|
-
console.error(`[Hook]
|
|
73
|
+
console.error(`[Hook] Correction detection spawn failed: ${err.message}`);
|
|
153
74
|
}
|
|
154
75
|
}
|
|
155
76
|
}
|
|
77
|
+
}
|
|
156
78
|
|
|
157
|
-
|
|
158
|
-
|
|
79
|
+
// v6.0: Set routing-pending flag for routing gate enforcement
|
|
80
|
+
const isWogiCommand = typeof prompt === 'string' && /^\/wogi-[a-z0-9-]+\b/i.test(prompt.trim());
|
|
81
|
+
if (!isWogiCommand) {
|
|
82
|
+
// v8.1: Delete any stale cleared marker from previous turns.
|
|
159
83
|
try {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
84
|
+
fs.unlinkSync(ROUTING_CLEARED_PATH);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (err.code !== 'ENOENT' && process.env.DEBUG) {
|
|
87
|
+
console.error(`[Hook] Failed to delete cleared marker: ${err.message}`);
|
|
163
88
|
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
setRoutingPending();
|
|
164
93
|
} catch (err) {
|
|
165
|
-
// Non-blocking - phase context is best-effort
|
|
166
94
|
if (process.env.DEBUG) {
|
|
167
|
-
console.error(`[Hook]
|
|
95
|
+
console.error(`[Hook] Routing gate set failed: ${err.message}`);
|
|
168
96
|
}
|
|
169
97
|
}
|
|
170
|
-
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
source
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// If research protocol should be injected, add it to system reminder
|
|
185
|
-
if (researchResult.injectProtocol && researchResult.protocolSteps) {
|
|
186
|
-
coreResult = {
|
|
187
|
-
...coreResult,
|
|
188
|
-
systemReminder: researchResult.protocolSteps,
|
|
189
|
-
researchTriggered: true,
|
|
190
|
-
questionType: researchResult.questionType,
|
|
191
|
-
suggestedDepth: researchResult.suggestedDepth
|
|
192
|
-
};
|
|
193
|
-
} else if (researchResult.warning && coreResult.allowed) {
|
|
194
|
-
// Soft warning mode (not strict)
|
|
195
|
-
coreResult = {
|
|
196
|
-
...coreResult,
|
|
197
|
-
warning: true,
|
|
198
|
-
researchWarning: researchResult.message,
|
|
199
|
-
suggestedCommand: researchResult.suggestedCommand
|
|
200
|
-
};
|
|
98
|
+
} else {
|
|
99
|
+
// v6.2: Actively CLEAR any existing routing flag when user explicitly types a /wogi-* command.
|
|
100
|
+
try {
|
|
101
|
+
clearRoutingPending();
|
|
102
|
+
if (process.env.DEBUG) {
|
|
103
|
+
console.error(`[Hook] Cleared routing flag — prompt is a /wogi-* command`);
|
|
104
|
+
}
|
|
105
|
+
} catch (err) {
|
|
106
|
+
if (process.env.DEBUG) {
|
|
107
|
+
console.error(`[Hook] Routing gate clear failed: ${err.message}`);
|
|
108
|
+
}
|
|
201
109
|
}
|
|
110
|
+
}
|
|
202
111
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
112
|
+
// Phase context injection
|
|
113
|
+
let phasePrompt = null;
|
|
114
|
+
try {
|
|
115
|
+
const phaseContext = getPhaseContextPrompt();
|
|
116
|
+
if (phaseContext.inject && phaseContext.prompt) {
|
|
117
|
+
phasePrompt = phaseContext.prompt;
|
|
209
118
|
}
|
|
210
|
-
|
|
211
|
-
// Transform to Claude Code format
|
|
212
|
-
const output = claudeCodeAdapter.transformResult('UserPromptSubmit', coreResult);
|
|
213
|
-
|
|
214
|
-
// Output JSON
|
|
215
|
-
console.log(JSON.stringify(output));
|
|
216
|
-
process.exit(0);
|
|
217
119
|
} catch (err) {
|
|
218
|
-
// Fail-closed: block the prompt on hook errors to prevent untracked implementation
|
|
219
|
-
// Users installed WogiFlow to enforce task tracking - failing open would bypass that
|
|
220
120
|
if (process.env.DEBUG) {
|
|
221
|
-
console.error(`[
|
|
222
|
-
} else {
|
|
223
|
-
console.error('[Wogi Flow Hook] Validation error occurred');
|
|
121
|
+
console.error(`[Hook] Phase context injection failed: ${err.message}`);
|
|
224
122
|
}
|
|
225
|
-
console.log(JSON.stringify({
|
|
226
|
-
decision: 'block',
|
|
227
|
-
reason: 'WogiFlow validation error. Please check your WogiFlow setup or use /wogi-start to route your request.'
|
|
228
|
-
}));
|
|
229
|
-
process.exit(0);
|
|
230
123
|
}
|
|
231
|
-
}
|
|
232
124
|
|
|
233
|
-
//
|
|
234
|
-
|
|
125
|
+
// Check research gate first (before implementation gate)
|
|
126
|
+
const researchResult = checkResearchRequirement({
|
|
127
|
+
prompt,
|
|
128
|
+
source
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Check implementation gate
|
|
132
|
+
let coreResult = checkImplementationGate({
|
|
133
|
+
prompt,
|
|
134
|
+
source
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// If research protocol should be injected, add it to system reminder
|
|
138
|
+
if (researchResult.injectProtocol && researchResult.protocolSteps) {
|
|
139
|
+
coreResult = {
|
|
140
|
+
...coreResult,
|
|
141
|
+
systemReminder: researchResult.protocolSteps,
|
|
142
|
+
researchTriggered: true,
|
|
143
|
+
questionType: researchResult.questionType,
|
|
144
|
+
suggestedDepth: researchResult.suggestedDepth
|
|
145
|
+
};
|
|
146
|
+
} else if (researchResult.warning && coreResult.allowed) {
|
|
147
|
+
coreResult = {
|
|
148
|
+
...coreResult,
|
|
149
|
+
warning: true,
|
|
150
|
+
researchWarning: researchResult.message,
|
|
151
|
+
suggestedCommand: researchResult.suggestedCommand
|
|
152
|
+
};
|
|
153
|
+
}
|
|
235
154
|
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
process.exit(0);
|
|
155
|
+
// Inject phase-specific context prompt
|
|
156
|
+
if (phasePrompt) {
|
|
157
|
+
coreResult = {
|
|
158
|
+
...coreResult,
|
|
159
|
+
phasePrompt
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return coreResult;
|
|
164
|
+
}, {
|
|
165
|
+
failMode: 'block',
|
|
166
|
+
failOutput: {
|
|
167
|
+
decision: 'block',
|
|
168
|
+
reason: 'WogiFlow validation error. Please check your WogiFlow setup or use /wogi-start to route your request.'
|
|
251
169
|
}
|
|
252
|
-
})
|
|
170
|
+
});
|
|
@@ -11,29 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const { handleWorktreeCreate } = require('../../core/worktree-lifecycle');
|
|
14
|
-
const {
|
|
15
|
-
const { readHookInput } = require('../shared/read-stdin');
|
|
14
|
+
const { runHook } = require('../shared/hook-runner');
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const input = parsedStdin || {};
|
|
23
|
-
|
|
24
|
-
const worktreePath = input.worktree_path || input.worktreePath || '';
|
|
25
|
-
const projectRoot = input.cwd || process.cwd();
|
|
26
|
-
|
|
27
|
-
const result = handleWorktreeCreate({ worktreePath, projectRoot });
|
|
28
|
-
const output = claudeCodeAdapter.transformResult('WorktreeCreate', result);
|
|
29
|
-
|
|
30
|
-
process.stdout.write(JSON.stringify(output));
|
|
31
|
-
process.exit(0);
|
|
32
|
-
} catch (err) {
|
|
33
|
-
// Never block on worktree lifecycle errors
|
|
34
|
-
process.stdout.write(JSON.stringify({ continue: true }));
|
|
35
|
-
process.exit(0);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
main();
|
|
16
|
+
runHook('WorktreeCreate', async ({ input }) => {
|
|
17
|
+
const worktreePath = input.worktree_path || input.worktreePath || '';
|
|
18
|
+
const projectRoot = input.cwd || process.cwd();
|
|
19
|
+
return handleWorktreeCreate({ worktreePath, projectRoot });
|
|
20
|
+
}, { failMode: 'silent', useStdoutWrite: true });
|
|
@@ -11,29 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const { handleWorktreeRemove } = require('../../core/worktree-lifecycle');
|
|
14
|
-
const {
|
|
15
|
-
const { readHookInput } = require('../shared/read-stdin');
|
|
14
|
+
const { runHook } = require('../shared/hook-runner');
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const input = parsedStdin || {};
|
|
23
|
-
|
|
24
|
-
const worktreePath = input.worktree_path || input.worktreePath || '';
|
|
25
|
-
const projectRoot = input.cwd || process.cwd();
|
|
26
|
-
|
|
27
|
-
const result = handleWorktreeRemove({ worktreePath, projectRoot });
|
|
28
|
-
const output = claudeCodeAdapter.transformResult('WorktreeRemove', result);
|
|
29
|
-
|
|
30
|
-
process.stdout.write(JSON.stringify(output));
|
|
31
|
-
process.exit(0);
|
|
32
|
-
} catch (err) {
|
|
33
|
-
// Never block on worktree lifecycle errors
|
|
34
|
-
process.stdout.write(JSON.stringify({ continue: true }));
|
|
35
|
-
process.exit(0);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
main();
|
|
16
|
+
runHook('WorktreeRemove', async ({ input }) => {
|
|
17
|
+
const worktreePath = input.worktree_path || input.worktreePath || '';
|
|
18
|
+
const projectRoot = input.cwd || process.cwd();
|
|
19
|
+
return handleWorktreeRemove({ worktreePath, projectRoot });
|
|
20
|
+
}, { failMode: 'silent', useStdoutWrite: true });
|