jettypod 4.4.77 → 4.4.79

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/jettypod.js CHANGED
@@ -705,6 +705,77 @@ async function generateClaude(options = {}) {
705
705
  console.log('📝 CLAUDE.md generated');
706
706
  }
707
707
 
708
+ // Ensure Claude Code hooks are up to date (called on every jettypod launch)
709
+ function ensureClaudeHooks() {
710
+ // Create .claude directory if needed
711
+ if (!fs.existsSync('.claude')) {
712
+ fs.mkdirSync('.claude', { recursive: true });
713
+ }
714
+
715
+ const claudeSettingsPath = path.join('.claude', 'settings.json');
716
+
717
+ // Required hooks configuration - always ensure these are present
718
+ const requiredHooks = {
719
+ Edit: [
720
+ '.jettypod/hooks/global-guardrails.js',
721
+ '.jettypod/hooks/protect-claude-md.js'
722
+ ],
723
+ Write: [
724
+ '.jettypod/hooks/global-guardrails.js',
725
+ '.jettypod/hooks/protect-claude-md.js'
726
+ ],
727
+ Bash: [
728
+ '.jettypod/hooks/global-guardrails.js',
729
+ '.jettypod/hooks/enforce-skill-activation.js'
730
+ ]
731
+ };
732
+
733
+ // Load existing settings or create empty structure
734
+ let claudeSettings = { hooks: { PreToolUse: [] } };
735
+ if (fs.existsSync(claudeSettingsPath)) {
736
+ try {
737
+ claudeSettings = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf-8'));
738
+ if (!claudeSettings.hooks) claudeSettings.hooks = {};
739
+ if (!claudeSettings.hooks.PreToolUse) claudeSettings.hooks.PreToolUse = [];
740
+ } catch {
741
+ // Invalid JSON, start fresh
742
+ claudeSettings = { hooks: { PreToolUse: [] } };
743
+ }
744
+ }
745
+
746
+ // Ensure required hooks are present for each matcher
747
+ let hooksUpdated = false;
748
+ for (const [matcher, requiredCommands] of Object.entries(requiredHooks)) {
749
+ // Find existing entry for this matcher
750
+ let matcherEntry = claudeSettings.hooks.PreToolUse.find(e => e.matcher === matcher);
751
+
752
+ if (!matcherEntry) {
753
+ // Create new entry for this matcher
754
+ matcherEntry = { matcher, hooks: [] };
755
+ claudeSettings.hooks.PreToolUse.push(matcherEntry);
756
+ hooksUpdated = true;
757
+ }
758
+
759
+ // Ensure each required command is present
760
+ for (const command of requiredCommands) {
761
+ const hasCommand = matcherEntry.hooks.some(h => h.command === command);
762
+ if (!hasCommand) {
763
+ // Add required hook at the beginning (guardrails should run first)
764
+ matcherEntry.hooks.unshift({ type: 'command', command });
765
+ hooksUpdated = true;
766
+ }
767
+ }
768
+ }
769
+
770
+ // Write updated settings
771
+ fs.writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2));
772
+ if (hooksUpdated) {
773
+ console.log('⚙️ Claude Code hooks updated');
774
+ }
775
+
776
+ return hooksUpdated;
777
+ }
778
+
708
779
  // Initialize project (used by both 'jettypod init' and 'jettypod' with no args)
709
780
  async function initializeProject() {
710
781
  const { showLogo } = require('./lib/terminal-logo');
@@ -805,74 +876,11 @@ async function initializeProject() {
805
876
  fs.chmodSync(guardrailsHookDest, 0o755);
806
877
  }
807
878
 
808
- // Create Claude Code settings
809
- if (!fs.existsSync('.claude')) {
810
- fs.mkdirSync('.claude', { recursive: true });
811
- }
812
-
813
879
  // Ensure .claude/session.md is gitignored and untracked
814
880
  ensureJettypodGitignores();
815
881
 
816
- const claudeSettingsPath = path.join('.claude', 'settings.json');
817
-
818
- // Required hooks configuration - always ensure these are present
819
- const requiredHooks = {
820
- Edit: [
821
- '.jettypod/hooks/global-guardrails.js',
822
- '.jettypod/hooks/protect-claude-md.js'
823
- ],
824
- Write: [
825
- '.jettypod/hooks/global-guardrails.js',
826
- '.jettypod/hooks/protect-claude-md.js'
827
- ],
828
- Bash: [
829
- '.jettypod/hooks/global-guardrails.js',
830
- '.jettypod/hooks/enforce-skill-activation.js'
831
- ]
832
- };
833
-
834
- // Load existing settings or create empty structure
835
- let claudeSettings = { hooks: { PreToolUse: [] } };
836
- if (fs.existsSync(claudeSettingsPath)) {
837
- try {
838
- claudeSettings = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf-8'));
839
- if (!claudeSettings.hooks) claudeSettings.hooks = {};
840
- if (!claudeSettings.hooks.PreToolUse) claudeSettings.hooks.PreToolUse = [];
841
- } catch {
842
- // Invalid JSON, start fresh
843
- claudeSettings = { hooks: { PreToolUse: [] } };
844
- }
845
- }
846
-
847
- // Ensure required hooks are present for each matcher
848
- let hooksUpdated = false;
849
- for (const [matcher, requiredCommands] of Object.entries(requiredHooks)) {
850
- // Find existing entry for this matcher
851
- let matcherEntry = claudeSettings.hooks.PreToolUse.find(e => e.matcher === matcher);
852
-
853
- if (!matcherEntry) {
854
- // Create new entry for this matcher
855
- matcherEntry = { matcher, hooks: [] };
856
- claudeSettings.hooks.PreToolUse.push(matcherEntry);
857
- hooksUpdated = true;
858
- }
859
-
860
- // Ensure each required command is present
861
- for (const command of requiredCommands) {
862
- const hasCommand = matcherEntry.hooks.some(h => h.command === command);
863
- if (!hasCommand) {
864
- // Add required hook at the beginning (guardrails should run first)
865
- matcherEntry.hooks.unshift({ type: 'command', command });
866
- hooksUpdated = true;
867
- }
868
- }
869
- }
870
-
871
- // Write updated settings
872
- fs.writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2));
873
- if (hooksUpdated) {
874
- console.log('⚙️ Claude Code hooks updated');
875
- }
882
+ // Ensure Claude Code hooks are up to date
883
+ ensureClaudeHooks();
876
884
 
877
885
  // Copy skills directory
878
886
  // Allow tests to override skills source directory
@@ -1163,8 +1171,11 @@ switch (command) {
1163
1171
  const updateCommand = require('./lib/update-command');
1164
1172
  const success = await updateCommand.runUpdate();
1165
1173
 
1166
- // Always refresh skills in current project after update attempt
1174
+ // Always refresh skills and hooks in current project after update attempt
1167
1175
  if (fs.existsSync('.jettypod')) {
1176
+ // Update Claude Code hooks first
1177
+ ensureClaudeHooks();
1178
+
1168
1179
  console.log('');
1169
1180
  console.log('🔄 Refreshing skills in current project...');
1170
1181
 
@@ -2099,6 +2110,9 @@ switch (command) {
2099
2110
  const currentConfig = config.read();
2100
2111
  await generateClaude();
2101
2112
 
2113
+ // Ensure Claude Code hooks are up to date on every launch
2114
+ ensureClaudeHooks();
2115
+
2102
2116
  // Launch dashboard
2103
2117
  const dashboardPath = path.join(__dirname, 'apps', 'dashboard');
2104
2118
  const BASE_PORT = 3456;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jettypod",
3
- "version": "4.4.77",
3
+ "version": "4.4.79",
4
4
  "description": "AI-powered development workflow manager with TDD, BDD, and automatic test generation",
5
5
  "main": "jettypod.js",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: chore-planning
3
- description: Guide standalone chore planning with automatic type classification, taxonomy guidance loading, and routing to chore-mode for execution. Use when user starts a standalone chore (chore with no parent feature), mentions planning a chore, or says "help me with this chore".
3
+ description: Guide standalone chore planning with automatic type classification and routing to chore-mode. Use when the implementation approach is obvious - refactoring, bug fixes, infrastructure, or simple enhancements where there's no UX decision to make. Key question - "Does this need UX exploration?" No → chore-planning. Yes → feature-planning instead.
4
4
  ---
5
5
 
6
6
  # Chore Planning Skill
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: feature-planning
3
- description: Guide feature planning with UX approach exploration and BDD scenario generation. Use when user asks to plan a feature, mentions designing/implementing a feature, says "help me plan feature", or wants to explore UX approaches for a specific feature.
3
+ description: Guide feature planning with UX approach exploration and BDD scenario generation. Use when implementing NEW user-facing behavior that requires UX decisions (multiple valid approaches to discuss). NOT for simple/obvious changes like copy tweaks, styling fixes, or adding straightforward functionality. Key question - "Does this need UX exploration?" Yes feature-planning.
4
4
  ---
5
5
 
6
6
  # Feature Planning Skill