wogiflow 1.5.2 → 1.5.3

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/lib/installer.js CHANGED
@@ -583,6 +583,24 @@ function createCLIConfig(projectRoot, cliKey, config) {
583
583
 
584
584
  You are an AI development assistant using the WogiFlow methodology v1.0.
585
585
 
586
+ ---
587
+
588
+ ## Task Gating (MANDATORY — NO EXCEPTIONS)
589
+
590
+ **STOP. Before doing ANYTHING with a user message, you MUST route it through a \`/wogi-*\` command.**
591
+
592
+ **EVERY user message** MUST be routed through either:
593
+ 1. **A matching \`/wogi-*\` command** (e.g., "code review" → \`/wogi-review\`, "show tasks" → \`/wogi-ready\`)
594
+ 2. **\`/wogi-start\`** for everything else (the universal fallback router)
595
+
596
+ This applies to ALL message types — implementation requests, questions, exploration, research, operational requests. No exceptions.
597
+
598
+ **You do NOT handle requests directly.** Always invoke a \`/wogi-*\` command first. If you find yourself thinking "this is just a question, I can handle it directly" — that thought is the exact bypass this rule exists to prevent.
599
+
600
+ **Do NOT use EnterPlanMode directly.** Route through \`/wogi-start\` which will use plan mode internally when appropriate.
601
+
602
+ ---
603
+
586
604
  ## Quick Start
587
605
 
588
606
  \`\`\`bash
@@ -593,9 +611,12 @@ cat .workflow/state/ready.json # Check tasks
593
611
  ## Core Commands
594
612
 
595
613
  - \`/wogi-ready\` - Show available tasks
596
- - \`/wogi-start TASK-X\` - Start a task
614
+ - \`/wogi-start TASK-X\` - Start a task (or \`/wogi-start "description"\` to route any request)
615
+ - \`/wogi-story "title"\` - Create story with acceptance criteria
597
616
  - \`/wogi-status\` - Project overview
598
617
  - \`/wogi-health\` - Check workflow health
618
+ - \`/wogi-review\` - Code review
619
+ - \`/wogi-bug "description"\` - Report a bug
599
620
 
600
621
  Run \`flow bridge sync\` to regenerate this file with full template.
601
622
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wogiflow",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "AI-powered development workflow management system with multi-model support",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -441,6 +441,117 @@ function main() {
441
441
  console.log(` ${color('yellow', '○')} .claude/settings.local.json not found (run 'flow bridge sync')`);
442
442
  }
443
443
 
444
+ // Check hook integrity
445
+ console.log('');
446
+ printSection('Checking hook integrity...');
447
+
448
+ const settingsLocalPath = path.join(PROJECT_ROOT, '.claude', 'settings.local.json');
449
+ if (fileExists(settingsLocalPath)) {
450
+ try {
451
+ const settings = safeJsonParse(settingsLocalPath, {});
452
+ const hooks = settings.hooks || {};
453
+
454
+ // Check PreToolUse matcher includes EnterPlanMode
455
+ const preToolHooks = hooks.PreToolUse || [];
456
+ let hasEnterPlanMode = false;
457
+ let hasCorrectMatcher = false;
458
+ let hookScriptsMissing = [];
459
+
460
+ for (const hookEntry of preToolHooks) {
461
+ const matcher = hookEntry.matcher || '';
462
+ if (matcher.includes('EnterPlanMode')) {
463
+ hasEnterPlanMode = true;
464
+ }
465
+ if (matcher.includes('Edit') && matcher.includes('Write') && matcher.includes('Bash') && matcher.includes('Skill')) {
466
+ hasCorrectMatcher = true;
467
+ }
468
+
469
+ // Check hook script files exist
470
+ for (const h of (hookEntry.hooks || [])) {
471
+ if (h.command) {
472
+ // Extract script path from command like: node "/path/to/script.js"
473
+ const scriptMatch = h.command.match(/node\s+"([^"]+)"/);
474
+ if (scriptMatch) {
475
+ const scriptPath = scriptMatch[1];
476
+ if (!fileExists(scriptPath)) {
477
+ hookScriptsMissing.push(scriptPath);
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
483
+
484
+ // Also check other hook types for missing scripts
485
+ for (const hookType of ['PostToolUse', 'UserPromptSubmit', 'SessionStart']) {
486
+ for (const hookEntry of (hooks[hookType] || [])) {
487
+ for (const h of (hookEntry.hooks || [])) {
488
+ if (h.command) {
489
+ const scriptMatch = h.command.match(/node\s+"([^"]+)"/);
490
+ if (scriptMatch && !fileExists(scriptMatch[1])) {
491
+ hookScriptsMissing.push(scriptMatch[1]);
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ if (hasEnterPlanMode) {
499
+ console.log(` ${color('green', '✓')} PreToolUse matcher includes EnterPlanMode`);
500
+ } else {
501
+ console.log(` ${color('red', '✗')} PreToolUse matcher MISSING EnterPlanMode — Claude can bypass /wogi-start`);
502
+ console.log(` ${color('dim', "→ Run 'flow bridge sync' to regenerate hooks")}`);
503
+ issues++;
504
+ }
505
+
506
+ if (hasCorrectMatcher) {
507
+ console.log(` ${color('green', '✓')} PreToolUse matcher has core tools (Edit|Write|Bash|Skill)`);
508
+ } else if (preToolHooks.length > 0) {
509
+ console.log(` ${color('yellow', '⚠')} PreToolUse matcher may be outdated — missing core tools`);
510
+ console.log(` ${color('dim', "→ Run 'flow bridge sync' to regenerate hooks")}`);
511
+ warnings++;
512
+ }
513
+
514
+ if (hookScriptsMissing.length > 0) {
515
+ console.log(` ${color('red', '✗')} ${hookScriptsMissing.length} hook script(s) MISSING:`);
516
+ for (const missing of hookScriptsMissing.slice(0, 5)) {
517
+ console.log(` - ${missing}`);
518
+ }
519
+ console.log(` ${color('dim', "→ Run 'npm install wogiflow' or 'flow init' to restore scripts")}`);
520
+ issues++;
521
+ } else if (preToolHooks.length > 0) {
522
+ console.log(` ${color('green', '✓')} All hook scripts exist`);
523
+ }
524
+ } catch (err) {
525
+ console.log(` ${color('yellow', '⚠')} Could not parse settings.local.json for hooks: ${err.message}`);
526
+ warnings++;
527
+ }
528
+ } else {
529
+ console.log(` ${color('yellow', '⚠')} .claude/settings.local.json not found — hooks not configured`);
530
+ console.log(` ${color('dim', "→ Run 'flow bridge sync' to generate hooks")}`);
531
+ warnings++;
532
+ }
533
+
534
+ // Check CLAUDE.md has routing instructions (not just product description)
535
+ if (fileExists(claudeMdPath)) {
536
+ try {
537
+ const claudeContent = fs.readFileSync(claudeMdPath, 'utf-8');
538
+ const hasRouting = claudeContent.includes('wogi-start') && (
539
+ claudeContent.includes('Task Gating') ||
540
+ claudeContent.includes('MUST route') ||
541
+ claudeContent.includes('MANDATORY')
542
+ );
543
+ if (hasRouting) {
544
+ console.log(` ${color('green', '✓')} CLAUDE.md contains routing instructions`);
545
+ } else {
546
+ console.log(` ${color('red', '✗')} CLAUDE.md has NO routing instructions — Claude will bypass /wogi-start`);
547
+ console.log(` ${color('dim', "→ Run 'flow bridge sync' to regenerate CLAUDE.md from template")}`);
548
+ issues++;
549
+ }
550
+ } catch (err) {
551
+ // Already warned about CLAUDE.md read failure above
552
+ }
553
+ }
554
+
444
555
  // Check git status
445
556
  console.log('');
446
557
  printSection('Checking git status...');
@@ -513,7 +513,7 @@ Run: /wogi-start ${coreResult.nextTaskId}`;
513
513
  // Task gating for Edit/Write + TodoWrite gating + Skill tracking + Bash strict adherence
514
514
  if (rules.taskGating?.enabled !== false || rules.todoWriteGate?.enabled !== false) {
515
515
  preToolUseMatchers.push({
516
- matcher: 'Edit|Write|TodoWrite|Skill|Bash',
516
+ matcher: 'Edit|Write|TodoWrite|Skill|Bash|EnterPlanMode',
517
517
  hooks: [{
518
518
  type: 'command',
519
519
  command: `node "${path.join(scriptsDir, 'pre-tool-use.js')}"`,
@@ -163,9 +163,11 @@ function isRoutingPending() {
163
163
  * @returns {{ allowed: boolean, blocked: boolean, reason: string, message: string|null }}
164
164
  */
165
165
  function checkRoutingGate(toolName) {
166
- // Only gate Bash calls
167
- if (toolName !== 'Bash') {
168
- return { allowed: true, blocked: false, reason: 'not_bash', message: null };
166
+ // Gate Bash and EnterPlanMode calls
167
+ // EnterPlanMode bypasses /wogi-start routing — must be blocked before routing
168
+ const GATED_TOOLS = new Set(['Bash', 'EnterPlanMode']);
169
+ if (!GATED_TOOLS.has(toolName)) {
170
+ return { allowed: true, blocked: false, reason: 'not_gated_tool', message: null };
169
171
  }
170
172
 
171
173
  // Check if routing gate is enabled
@@ -151,9 +151,9 @@ async function main() {
151
151
  }
152
152
  }
153
153
 
154
- // v6.0: Routing gate check (for Bash)
155
- // Blocks Bash calls when no /wogi-* command has been invoked first
156
- if (toolName === 'Bash') {
154
+ // v6.0: Routing gate check (for Bash and EnterPlanMode)
155
+ // Blocks Bash/EnterPlanMode calls when no /wogi-* command has been invoked first
156
+ if (toolName === 'Bash' || toolName === 'EnterPlanMode') {
157
157
  try {
158
158
  const routingResult = checkRoutingGate(toolName);
159
159
  if (routingResult.blocked) {