@codihaus/claude-skills 1.6.4 → 1.6.6

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/README.md CHANGED
@@ -138,8 +138,8 @@ Creates BRD + Use Cases
138
138
 
139
139
  Skills are installed to `.claude/skills/`. You can customize:
140
140
 
141
- - **`.claude/settings.local.json`** - Claude Code permissions
142
- - **`.claude/hooks.json`** - Automation hooks
141
+ - **`.claude/settings.json`** - Automation hooks (checked into git for team)
142
+ - **`.claude/settings.local.json`** - Claude Code permissions (gitignored, personal)
143
143
  - **`CLAUDE.md`** - Project-specific instructions
144
144
 
145
145
  ## Updating
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codihaus/claude-skills",
3
- "version": "1.6.4",
3
+ "version": "1.6.6",
4
4
  "description": "Claude Code skills for software development workflow",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -49,7 +49,7 @@ const DEFAULT_SETTINGS = {
49
49
  hooks: [
50
50
  {
51
51
  type: "command",
52
- command: "jq -r '.tool_input.file_path // empty' | xargs -I {} bash .claude/scripts/safe-graph-update.sh '{}'"
52
+ command: "jq -r '.tool_input.file_path // empty' | { read file_path; if [ -n \"$file_path\" ] && echo \"$file_path\" | grep -q 'plans/.*\\.md$'; then bash .claude/scripts/safe-graph-update.sh \"$file_path\" 2>/dev/null || true; fi; }"
53
53
  }
54
54
  ]
55
55
  }
@@ -57,13 +57,14 @@ const DEFAULT_SETTINGS = {
57
57
  }
58
58
  };
59
59
 
60
- // Hooks are now configured in settings.json (see DEFAULT_SETTINGS)
60
+ // Hooks are configured in BOTH settings.json AND settings.local.json
61
+ // settings.json = team-shared (checked in), settings.local.json = personal (gitignored)
62
+ // Claude Code merges them, with settings.local.json taking precedence
61
63
 
62
64
  /**
63
65
  * Set up Claude Code settings
64
- * Creates TWO files:
65
- * - settings.json (with hooks, checked into git)
66
- * - settings.local.json (with permissions, gitignored)
66
+ * Creates BOTH settings.json (with hooks for team) AND settings.local.json (with hooks+permissions)
67
+ * This ensures hooks work regardless of which file Claude Code prioritizes
67
68
  */
68
69
  export async function setupSettings(projectPath, options = {}) {
69
70
  const claudePath = path.join(projectPath, '.claude');
@@ -72,23 +73,20 @@ export async function setupSettings(projectPath, options = {}) {
72
73
 
73
74
  await fs.ensureDir(claudePath);
74
75
 
75
- // Create settings.json with hooks (for team, checked in)
76
- const settingsJsonContent = {
76
+ // Create settings.json with hooks (for team, checked into git)
77
+ const settingsJson = {
77
78
  hooks: DEFAULT_SETTINGS.hooks
78
79
  };
80
+ await fs.writeJson(settingsPath, settingsJson, { spaces: 2 });
79
81
 
80
- await fs.writeJson(settingsPath, settingsJsonContent, { spaces: 2 });
81
-
82
- // Create/update settings.local.json with permissions (personal, gitignored)
83
- let localSettings = {
84
- permissions: DEFAULT_SETTINGS.permissions
85
- };
82
+ // Create/merge settings.local.json with hooks + permissions (personal, gitignored)
83
+ let settingsLocal = DEFAULT_SETTINGS;
86
84
 
87
85
  // Merge with existing if present
88
86
  if (await fs.pathExists(settingsLocalPath)) {
89
87
  try {
90
88
  const existing = await fs.readJson(settingsLocalPath);
91
- localSettings = {
89
+ settingsLocal = {
92
90
  permissions: {
93
91
  allow: [...new Set([
94
92
  ...(existing.permissions?.allow || []),
@@ -98,24 +96,25 @@ export async function setupSettings(projectPath, options = {}) {
98
96
  ...(existing.permissions?.deny || []),
99
97
  ...(DEFAULT_SETTINGS.permissions?.deny || [])
100
98
  ])]
101
- }
99
+ },
100
+ hooks: DEFAULT_SETTINGS.hooks
102
101
  };
103
102
  } catch (e) {
104
103
  // Invalid JSON, use defaults
105
104
  }
106
105
  }
107
106
 
108
- await fs.writeJson(settingsLocalPath, localSettings, { spaces: 2 });
107
+ await fs.writeJson(settingsLocalPath, settingsLocal, { spaces: 2 });
109
108
 
110
109
  return {
111
110
  settingsPath,
112
111
  settingsLocalPath,
113
- settings: { ...settingsJsonContent, ...localSettings }
112
+ settings: settingsLocal
114
113
  };
115
114
  }
116
115
 
117
116
  /**
118
- * Set up hook scripts (hooks config is in settings.json)
117
+ * Set up hook scripts (hooks config is in both settings.json and settings.local.json)
119
118
  */
120
119
  export async function setupHooks(projectPath, options = {}) {
121
120
  if (options.noHooks) return null;
@@ -124,11 +124,11 @@ After running `npx @codihaus/claude-skills init`, verify:
124
124
 
125
125
  ```bash
126
126
  # Check hook configuration
127
- cat .claude/hooks.json | jq '.postToolUse[0].matcher.path'
128
- # Should output: "plans/**/*.md"
127
+ cat .claude/settings.json | jq '.hooks.PostToolUse[0].matcher'
128
+ # Should output: "Write|Edit"
129
129
 
130
- cat .claude/hooks.json | jq '.postToolUse[0].command'
131
- # Should output: "bash .claude/scripts/safe-graph-update.sh $PATH"
130
+ cat .claude/settings.json | jq '.hooks.PostToolUse[0].hooks[0].command'
131
+ # Should contain: "bash .claude/scripts/safe-graph-update.sh"
132
132
 
133
133
  # Test the safe wrapper script
134
134
  bash .claude/scripts/safe-graph-update.sh plans/brd/README.md
@@ -17,34 +17,34 @@ Hooks allow you to run commands automatically in response to Claude Code events.
17
17
 
18
18
  ## Best Practices
19
19
 
20
- ### 1. Always Add Retry Limits
20
+ ### 1. Correct Hook Structure
21
+
22
+ Hooks go in `.claude/settings.json`:
21
23
 
22
24
  ```json
23
25
  {
24
- "postToolUse": [{
25
- "matcher": {
26
- "toolName": "Write|Edit",
27
- "path": "plans/**/*.md"
28
- },
29
- "command": "bash .claude/scripts/safe-graph-update.sh $PATH",
30
- "retries": {
31
- "maxAttempts": 3,
32
- "backoff": "exponential",
33
- "failureAction": "warn"
34
- },
35
- "timeout": 5000
36
- }]
26
+ "hooks": {
27
+ "PostToolUse": [
28
+ {
29
+ "matcher": "Write|Edit",
30
+ "hooks": [
31
+ {
32
+ "type": "command",
33
+ "command": "jq -r '.tool_input.file_path // empty' | { read file_path; if [ -n \"$file_path\" ] && echo \"$file_path\" | grep -q 'plans/.*\\.md$'; then bash .claude/scripts/safe-graph-update.sh \"$file_path\" 2>/dev/null || true; fi; }"
34
+ }
35
+ ]
36
+ }
37
+ ]
38
+ }
37
39
  }
38
40
  ```
39
41
 
40
- **Key Fields:**
41
- - `maxAttempts`: Stop after N failures (recommended: 2-3)
42
- - `backoff`: Wait strategy ("none", "linear", "exponential")
43
- - `failureAction`: What to do after max attempts
44
- - `"warn"` - Show warning, continue (recommended)
45
- - `"error"` - Stop and ask user for help
46
- - `"ignore"` - Silent failure (not recommended)
47
- - `timeout`: Kill hook after N milliseconds (recommended: 5000-10000)
42
+ **Key Points:**
43
+ - Hooks are in `settings.json` (checked into git for team)
44
+ - Command uses bash subshell with `read` to capture file path
45
+ - Includes `|| true` for graceful failure (non-blocking)
46
+ - Filters to only run on `plans/**/*.md` files
47
+ - Redirects stderr with `2>/dev/null` to avoid noise
48
48
 
49
49
  ### 2. Make Commands Fail Gracefully
50
50
 
@@ -161,7 +161,7 @@ fi
161
161
  timeout 10s python3 .claude/scripts/graph.py --check-path "$1" || true
162
162
  ```
163
163
 
164
- Then in hooks.json:
164
+ Then in settings.json:
165
165
  ```json
166
166
  {
167
167
  "command": "bash .claude/scripts/safe-graph-update.sh $PATH"
@@ -251,7 +251,7 @@ To temporarily disable a problematic hook:
251
251
  }
252
252
  ```
253
253
 
254
- Or delete `.claude/hooks.json` entirely (hooks are optional).
254
+ Or delete `.claude/settings.json` entirely (hooks are optional).
255
255
 
256
256
  ## Example: Robust Hook Configuration
257
257