@amsterdamdatalabs/enact-extensions 0.1.0 → 0.1.1

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 (152) hide show
  1. package/README.md +94 -20
  2. package/dist/index.d.ts +3 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/install.d.ts +89 -0
  7. package/dist/install.d.ts.map +1 -1
  8. package/dist/install.js +219 -18
  9. package/dist/install.js.map +1 -1
  10. package/dist/validate/index.d.ts +21 -0
  11. package/dist/validate/index.d.ts.map +1 -1
  12. package/dist/validate/index.js +77 -0
  13. package/dist/validate/index.js.map +1 -1
  14. package/extensions/cmux/.agents/plugin.json +37 -0
  15. package/extensions/cmux/skills/cmux/SKILL.md +82 -0
  16. package/extensions/cmux/skills/cmux/agents/openai.yaml +4 -0
  17. package/extensions/cmux/skills/cmux/references/handles-and-identify.md +35 -0
  18. package/extensions/cmux/skills/cmux/references/panes-surfaces.md +37 -0
  19. package/extensions/cmux/skills/cmux/references/trigger-flash-and-health.md +23 -0
  20. package/extensions/cmux/skills/cmux/references/windows-workspaces.md +31 -0
  21. package/extensions/cmux/skills/cmux-vm-monitor/SKILL.md +122 -0
  22. package/extensions/cmux/skills/cmux-vm-monitor/agents/openai.yaml +4 -0
  23. package/extensions/cmux/skills/cmux-vm-monitor/references/cmux-commands.md +66 -0
  24. package/extensions/cmux/skills/cmux-vm-monitor/scripts/codex_vm_monitor.sh +45 -0
  25. package/extensions/cmux/skills/cmux-workspace/SKILL.md +93 -0
  26. package/extensions/dev-state/.agents/plugin.json +35 -0
  27. package/extensions/dev-state/skills/dev-state-plan-graduation/SKILL.md +194 -0
  28. package/extensions/dev-state/skills/dev-state-plan-graduation/agents/openai.yaml +4 -0
  29. package/extensions/dev-state/skills/dev-state-plan-graduation/references/reference.md +130 -0
  30. package/extensions/devops/.agents/plugin.json +36 -0
  31. package/extensions/devops/skills/azure-devops-cli/SKILL.md +431 -0
  32. package/extensions/devops/skills/azure-devops-cli/agents/openai.yaml +4 -0
  33. package/extensions/devops/skills/ci-pipeline-strategy/SKILL.md +217 -0
  34. package/extensions/devops/skills/ci-pipeline-strategy/agents/openai.yaml +4 -0
  35. package/{plugins/net-revenue-management/.codex-plugin → extensions/net-revenue-management/.agents}/plugin.json +10 -6
  36. package/extensions/plugin-dev/.agents/plugin.json +42 -0
  37. package/extensions/plugin-dev/.mcp.json +3 -0
  38. package/extensions/plugin-dev/agents/agent-creator.md +199 -0
  39. package/extensions/plugin-dev/agents/plugin-validator.md +91 -0
  40. package/extensions/plugin-dev/agents/skill-reviewer.md +212 -0
  41. package/extensions/plugin-dev/commands/_archive/create-marketplace.md +427 -0
  42. package/extensions/plugin-dev/commands/_archive/plugin-dev-guide.md +12 -0
  43. package/extensions/plugin-dev/commands/create-plugin.md +498 -0
  44. package/extensions/plugin-dev/commands/start.md +81 -0
  45. package/extensions/plugin-dev/hooks/hooks.json +3 -0
  46. package/extensions/plugin-dev/skills/agent-development/SKILL.md +641 -0
  47. package/extensions/plugin-dev/skills/agent-development/examples/agent-creation-prompt.md +250 -0
  48. package/extensions/plugin-dev/skills/agent-development/examples/complete-agent-examples.md +461 -0
  49. package/extensions/plugin-dev/skills/agent-development/references/advanced-agent-fields.md +246 -0
  50. package/extensions/plugin-dev/skills/agent-development/references/agent-creation-system-prompt.md +216 -0
  51. package/extensions/plugin-dev/skills/agent-development/references/permission-modes-rules.md +226 -0
  52. package/extensions/plugin-dev/skills/agent-development/references/system-prompt-design.md +464 -0
  53. package/extensions/plugin-dev/skills/agent-development/references/triggering-examples.md +474 -0
  54. package/extensions/plugin-dev/skills/agent-development/scripts/create-agent-skeleton.sh +176 -0
  55. package/extensions/plugin-dev/skills/agent-development/scripts/test-agent-trigger.sh +227 -0
  56. package/extensions/plugin-dev/skills/agent-development/scripts/validate-agent.sh +227 -0
  57. package/extensions/plugin-dev/skills/command-development/SKILL.md +763 -0
  58. package/extensions/plugin-dev/skills/command-development/examples/plugin-commands.md +612 -0
  59. package/extensions/plugin-dev/skills/command-development/examples/simple-commands.md +527 -0
  60. package/extensions/plugin-dev/skills/command-development/references/advanced-workflows.md +762 -0
  61. package/extensions/plugin-dev/skills/command-development/references/documentation-patterns.md +769 -0
  62. package/extensions/plugin-dev/skills/command-development/references/frontmatter-reference.md +508 -0
  63. package/extensions/plugin-dev/skills/command-development/references/interactive-commands.md +966 -0
  64. package/extensions/plugin-dev/skills/command-development/references/marketplace-considerations.md +943 -0
  65. package/extensions/plugin-dev/skills/command-development/references/plugin-features-reference.md +637 -0
  66. package/extensions/plugin-dev/skills/command-development/references/plugin-integration.md +191 -0
  67. package/extensions/plugin-dev/skills/command-development/references/skill-tool.md +447 -0
  68. package/extensions/plugin-dev/skills/command-development/references/testing-strategies.md +723 -0
  69. package/extensions/plugin-dev/skills/command-development/scripts/check-frontmatter.sh +234 -0
  70. package/extensions/plugin-dev/skills/command-development/scripts/validate-command.sh +160 -0
  71. package/extensions/plugin-dev/skills/hook-development/SKILL.md +861 -0
  72. package/extensions/plugin-dev/skills/hook-development/examples/load-context.sh +55 -0
  73. package/extensions/plugin-dev/skills/hook-development/examples/validate-bash.sh +57 -0
  74. package/extensions/plugin-dev/skills/hook-development/examples/validate-write.sh +48 -0
  75. package/extensions/plugin-dev/skills/hook-development/references/advanced.md +871 -0
  76. package/extensions/plugin-dev/skills/hook-development/references/hook-input-schemas.md +145 -0
  77. package/extensions/plugin-dev/skills/hook-development/references/migration.md +392 -0
  78. package/extensions/plugin-dev/skills/hook-development/references/patterns.md +430 -0
  79. package/extensions/plugin-dev/skills/hook-development/scripts/README.md +181 -0
  80. package/extensions/plugin-dev/skills/hook-development/scripts/hook-linter.sh +153 -0
  81. package/extensions/plugin-dev/skills/hook-development/scripts/test-hook.sh +276 -0
  82. package/extensions/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh +159 -0
  83. package/extensions/plugin-dev/skills/mcp-integration/SKILL.md +775 -0
  84. package/extensions/plugin-dev/skills/mcp-integration/examples/http-server.json +20 -0
  85. package/extensions/plugin-dev/skills/mcp-integration/examples/sse-server.json +19 -0
  86. package/extensions/plugin-dev/skills/mcp-integration/examples/stdio-server.json +38 -0
  87. package/extensions/plugin-dev/skills/mcp-integration/examples/ws-server.json +26 -0
  88. package/extensions/plugin-dev/skills/mcp-integration/references/authentication.md +601 -0
  89. package/extensions/plugin-dev/skills/mcp-integration/references/server-discovery.md +190 -0
  90. package/extensions/plugin-dev/skills/mcp-integration/references/server-types.md +572 -0
  91. package/extensions/plugin-dev/skills/mcp-integration/references/tool-usage.md +623 -0
  92. package/extensions/plugin-dev/skills/plugin-dev-guide/SKILL.md +222 -0
  93. package/extensions/plugin-dev/skills/plugin-structure/SKILL.md +705 -0
  94. package/extensions/plugin-dev/skills/plugin-structure/examples/advanced-plugin.md +774 -0
  95. package/extensions/plugin-dev/skills/plugin-structure/examples/minimal-plugin.md +83 -0
  96. package/extensions/plugin-dev/skills/plugin-structure/examples/standard-plugin.md +611 -0
  97. package/extensions/plugin-dev/skills/plugin-structure/references/advanced-topics.md +289 -0
  98. package/extensions/plugin-dev/skills/plugin-structure/references/component-patterns.md +592 -0
  99. package/extensions/plugin-dev/skills/plugin-structure/references/github-actions.md +233 -0
  100. package/extensions/plugin-dev/skills/plugin-structure/references/headless-ci-mode.md +193 -0
  101. package/extensions/plugin-dev/skills/plugin-structure/references/manifest-reference.md +625 -0
  102. package/extensions/plugin-dev/skills/plugin-structure/references/output-styles.md +116 -0
  103. package/extensions/plugin-dev/skills/skill-development/SKILL.md +564 -0
  104. package/extensions/plugin-dev/skills/skill-development/examples/complete-skill.md +465 -0
  105. package/extensions/plugin-dev/skills/skill-development/examples/frontmatter-templates.md +167 -0
  106. package/extensions/plugin-dev/skills/skill-development/examples/minimal-skill.md +111 -0
  107. package/extensions/plugin-dev/skills/skill-development/references/advanced-frontmatter.md +225 -0
  108. package/extensions/plugin-dev/skills/skill-development/references/commands-vs-skills.md +39 -0
  109. package/extensions/plugin-dev/skills/skill-development/references/skill-creation-workflow.md +379 -0
  110. package/extensions/plugin-dev/skills/skill-development/references/skill-creator-original.md +210 -0
  111. package/package.json +8 -11
  112. package/scripts/enact-extensions.mjs +751 -16
  113. package/scripts/hooks/session-start-drift-check.mjs +58 -0
  114. package/scripts/lib/build-index.mjs +50 -0
  115. package/scripts/lib/bundle-hash.mjs +137 -0
  116. package/scripts/lib/hooks.mjs +389 -0
  117. package/scripts/lib/ledger.mjs +162 -0
  118. package/scripts/lib/list-bundles.mjs +70 -0
  119. package/scripts/lib/outdated.mjs +144 -0
  120. package/scripts/lib/provision-mcp.mjs +369 -0
  121. package/scripts/lib/resolve-bundle.mjs +121 -0
  122. package/scripts/lib/run-install.mjs +321 -39
  123. package/scripts/lib/run-uninstall.mjs +220 -0
  124. package/scripts/lib/run-update.mjs +152 -0
  125. package/scripts/lib/run-validate.mjs +12 -18
  126. package/scripts/lib/serve.mjs +454 -0
  127. package/scripts/postinstall.mjs +63 -0
  128. package/scripts/setup-enact-context.sh +2 -2
  129. package/spec/index.json +59 -0
  130. package/web/assets/README.md +111 -0
  131. package/web/assets/logo-full.png +0 -0
  132. package/web/assets/logo-slim.png +0 -0
  133. package/web/assets/tokens/base.css +45 -0
  134. package/web/assets/tokens/colors.css +248 -0
  135. package/web/assets/tokens/effects.css +24 -0
  136. package/web/assets/tokens/fonts.css +8 -0
  137. package/web/assets/tokens/index.css +18 -0
  138. package/web/assets/tokens/spacing.css +50 -0
  139. package/web/index.html +1188 -0
  140. package/.agents/plugins/marketplace.json +0 -20
  141. package/catalog/enact-context.json +0 -9
  142. package/catalog/enact-factory.json +0 -7
  143. package/catalog/enact-operator.json +0 -7
  144. package/catalog/enact-wiki.json +0 -7
  145. package/catalog/net-revenue-management.json +0 -8
  146. package/scripts/rename-supervisor-to-operator.pl +0 -66
  147. package/scripts/sync-manifests.mjs +0 -23
  148. package/scripts/validate-catalog.mjs +0 -37
  149. package/scripts/validate-plugin.mjs +0 -10
  150. /package/{plugins → extensions}/net-revenue-management/.mcp.json +0 -0
  151. /package/{plugins → extensions}/net-revenue-management/skills/net-revenue-risks/SKILL.md +0 -0
  152. /package/{plugins → extensions}/net-revenue-management/skills/net-revenue-scenario/SKILL.md +0 -0
@@ -0,0 +1,145 @@
1
+ # Hook Input Schemas
2
+
3
+ Comprehensive reference for all hook input schemas. Every hook receives JSON via stdin containing common fields plus event-specific fields.
4
+
5
+ ## Common Fields (All Hooks)
6
+
7
+ Every hook receives these fields:
8
+
9
+ | Field | Type | Description |
10
+ | ----------------- | ------ | ------------------------------ |
11
+ | `session_id` | string | Unique session identifier |
12
+ | `transcript_path` | string | Path to conversation JSON |
13
+ | `cwd` | string | Current working directory |
14
+ | `permission_mode` | string | Current permission mode |
15
+ | `hook_event_name` | string | Event that triggered this hook |
16
+
17
+ ## Event-Specific Input Fields
18
+
19
+ ### PreToolUse / PostToolUse / PostToolUseFailure / PermissionRequest
20
+
21
+ | Field | Type | Events | Description |
22
+ | ------------------------ | ------- | ------------------ | --------------------------------------------- |
23
+ | `tool_name` | string | All four | Name of the tool |
24
+ | `tool_input` | object | All four | Arguments sent to the tool (see tool schemas) |
25
+ | `tool_result` | string | PostToolUse | Tool execution result |
26
+ | `tool_use_id` | string | PostToolUse | Unique tool use identifier |
27
+ | `error` | string | PostToolUseFailure | Error message from the failed tool |
28
+ | `is_interrupt` | boolean | PostToolUseFailure | Whether failure was caused by user interrupt |
29
+ | `permission_suggestions` | array | PermissionRequest | Suggested permission decisions |
30
+
31
+ ### UserPromptSubmit
32
+
33
+ | Field | Type | Description |
34
+ | -------- | ------ | ------------------------------ |
35
+ | `prompt` | string | The user-submitted prompt text |
36
+
37
+ ### Stop / SubagentStop
38
+
39
+ | Field | Type | Events | Description |
40
+ | ----------------------- | ------- | ------------ | ----------------------------------------------- |
41
+ | `stop_hook_active` | boolean | Both | Whether hook is already continuing (loop guard) |
42
+ | `agent_id` | string | SubagentStop | Unique subagent identifier |
43
+ | `agent_type` | string | SubagentStop | Agent name |
44
+ | `agent_transcript_path` | string | SubagentStop | Path to subagent transcript |
45
+
46
+ ### SubagentStart
47
+
48
+ | Field | Type | Description |
49
+ | ------------ | ------ | -------------------------- |
50
+ | `agent_id` | string | Unique subagent identifier |
51
+ | `agent_type` | string | Agent name |
52
+
53
+ ### SessionStart
54
+
55
+ | Field | Type | Description |
56
+ | ------------ | ------ | ------------------------------------------------ |
57
+ | `source` | string | Matcher: `startup`, `resume`, `clear`, `compact` |
58
+ | `model` | string | Model identifier |
59
+ | `agent_type` | string | If running as an agent (optional) |
60
+
61
+ ### SessionEnd
62
+
63
+ | Field | Type | Description |
64
+ | -------- | ------ | -------------------------------------------------------------------------------------- |
65
+ | `source` | string | Values: `clear`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` |
66
+
67
+ ### PreCompact
68
+
69
+ | Field | Type | Description |
70
+ | --------------------- | ------ | ------------------------------------------ |
71
+ | `trigger` | string | `manual` or `auto` |
72
+ | `custom_instructions` | string | User instructions (manual) or empty (auto) |
73
+
74
+ ### Notification
75
+
76
+ | Field | Type | Description |
77
+ | ------------------- | ------ | ------------------------------------------------------------------------ |
78
+ | `message` | string | Notification text |
79
+ | `title` | string | Notification title (optional) |
80
+ | `notification_type` | string | `permission_prompt`, `idle_prompt`, `auth_success`, `elicitation_dialog` |
81
+
82
+ ### TeammateIdle
83
+
84
+ | Field | Type | Description |
85
+ | --------------- | ------ | ------------- |
86
+ | `teammate_name` | string | Teammate name |
87
+ | `team_name` | string | Team name |
88
+
89
+ ### TaskCompleted
90
+
91
+ | Field | Type | Description |
92
+ | ------------------ | ------ | --------------------------- |
93
+ | `task_id` | string | Task identifier |
94
+ | `task_subject` | string | Task subject line |
95
+ | `task_description` | string | Task description (optional) |
96
+ | `teammate_name` | string | Teammate name (optional) |
97
+ | `team_name` | string | Team name (optional) |
98
+
99
+ ## Tool Input Schemas (for PreToolUse/PostToolUse)
100
+
101
+ The `tool_input` object varies by tool. Common tool schemas:
102
+
103
+ | Tool | `tool_input` Fields |
104
+ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
105
+ | Bash | `command` (string), `description` (string, optional), `timeout` (number, optional), `run_in_background` (boolean, optional) |
106
+ | Write | `file_path` (string), `content` (string) |
107
+ | Edit | `file_path` (string), `old_string` (string), `new_string` (string), `replace_all` (boolean, optional) |
108
+ | Read | `file_path` (string), `offset` (number, optional), `limit` (number, optional) |
109
+ | Glob | `pattern` (string), `path` (string, optional) |
110
+ | Grep | `pattern` (string), `path` (string, optional), `glob` (string, optional), `output_mode` (string, optional), `-i` (boolean, optional), `multiline` (boolean, optional) |
111
+ | WebFetch | `url` (string), `prompt` (string) |
112
+ | WebSearch | `query` (string), `allowed_domains` (array, optional), `blocked_domains` (array, optional) |
113
+ | Task | `prompt` (string), `description` (string), `subagent_type` (string), `model` (string, optional) |
114
+ | Skill | `skill` (string), `args` (string, optional) |
115
+ | NotebookEdit | `notebook_path` (string), `new_source` (string), `cell_type` (string, optional), `edit_mode` (string, optional) |
116
+
117
+ ## Practical Example
118
+
119
+ Extracting fields in a bash hook script using `jq`:
120
+
121
+ ```bash
122
+ #!/bin/bash
123
+ set -euo pipefail
124
+
125
+ # Read full input from stdin
126
+ input=$(cat)
127
+
128
+ # Extract common fields
129
+ session_id=$(echo "$input" | jq -r '.session_id')
130
+ hook_event=$(echo "$input" | jq -r '.hook_event_name')
131
+
132
+ # Extract tool-specific fields (PreToolUse/PostToolUse)
133
+ tool_name=$(echo "$input" | jq -r '.tool_name // empty')
134
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')
135
+ command=$(echo "$input" | jq -r '.tool_input.command // empty')
136
+
137
+ # Example: block writes to sensitive paths
138
+ if [[ "$tool_name" == "Write" && "$file_path" == *".env"* ]]; then
139
+ echo '{"decision": "deny", "reason": "Cannot write to .env files"}' >&2
140
+ exit 2
141
+ fi
142
+
143
+ # Allow by default
144
+ exit 0
145
+ ```
@@ -0,0 +1,392 @@
1
+ # Migrating from Basic to Advanced Hooks
2
+
3
+ This guide shows how to migrate from basic command hooks to advanced prompt-based hooks for better maintainability and flexibility.
4
+
5
+ ## Why Migrate?
6
+
7
+ Prompt-based hooks offer several advantages:
8
+
9
+ - **Natural language reasoning**: LLM understands context and intent
10
+ - **Better edge case handling**: Adapts to unexpected scenarios
11
+ - **No bash scripting required**: Simpler to write and maintain
12
+ - **More flexible validation**: Can handle complex logic without coding
13
+
14
+ ## Migration Example: Bash Command Validation
15
+
16
+ ### Before (Basic Command Hook)
17
+
18
+ **Configuration:**
19
+
20
+ ```json
21
+ {
22
+ "PreToolUse": [
23
+ {
24
+ "matcher": "Bash",
25
+ "hooks": [
26
+ {
27
+ "type": "command",
28
+ "command": "bash validate-bash.sh"
29
+ }
30
+ ]
31
+ }
32
+ ]
33
+ }
34
+ ```
35
+
36
+ **Script (validate-bash.sh):**
37
+
38
+ ```bash
39
+ #!/bin/bash
40
+ input=$(cat)
41
+ command=$(echo "$input" | jq -r '.tool_input.command')
42
+
43
+ # Hard-coded validation logic
44
+ if [[ "$command" == *"rm -rf"* ]]; then
45
+ echo "Dangerous command detected" >&2
46
+ exit 2
47
+ fi
48
+ ```
49
+
50
+ **Problems:**
51
+
52
+ - Only checks for exact "rm -rf" pattern
53
+ - Doesn't catch variations like `rm -fr` or `rm -r -f`
54
+ - Misses other dangerous commands (`dd`, `mkfs`, etc.)
55
+ - No context awareness
56
+ - Requires bash scripting knowledge
57
+
58
+ ### After (Advanced Prompt Hook)
59
+
60
+ **Configuration:**
61
+
62
+ ```json
63
+ {
64
+ "PreToolUse": [
65
+ {
66
+ "matcher": "Bash",
67
+ "hooks": [
68
+ {
69
+ "type": "prompt",
70
+ "prompt": "Command: $TOOL_INPUT.command. Analyze for: 1) Destructive operations (rm -rf, dd, mkfs, etc) 2) Privilege escalation (sudo) 3) Network operations without user consent. Return 'approve' or 'deny' with explanation.",
71
+ "timeout": 15
72
+ }
73
+ ]
74
+ }
75
+ ]
76
+ }
77
+ ```
78
+
79
+ **Benefits:**
80
+
81
+ - Catches all variations and patterns
82
+ - Understands intent, not just literal strings
83
+ - No script file needed
84
+ - Easy to extend with new criteria
85
+ - Context-aware decisions
86
+ - Natural language explanation in denial
87
+
88
+ ## Migration Example: File Write Validation
89
+
90
+ ### Before (Basic Command Hook)
91
+
92
+ **Configuration:**
93
+
94
+ ```json
95
+ {
96
+ "PreToolUse": [
97
+ {
98
+ "matcher": "Write",
99
+ "hooks": [
100
+ {
101
+ "type": "command",
102
+ "command": "bash validate-write.sh"
103
+ }
104
+ ]
105
+ }
106
+ ]
107
+ }
108
+ ```
109
+
110
+ **Script (validate-write.sh):**
111
+
112
+ ```bash
113
+ #!/bin/bash
114
+ input=$(cat)
115
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path')
116
+
117
+ # Check for path traversal
118
+ # NOTE: This basic check catches literal ".." but has limitations:
119
+ # - Does not detect URL-encoded traversal (%2e%2e)
120
+ # - Cannot detect symlink-based traversal where resolved path escapes bounds
121
+ # - Shell expansion could bypass in some contexts
122
+ # For production hooks, consider using:
123
+ # resolved=$(realpath -m "$file_path" 2>/dev/null || echo "$file_path")
124
+ # and comparing against an allowed directory prefix
125
+ if [[ "$file_path" == *".."* ]]; then
126
+ echo '{"decision": "deny", "reason": "Path traversal detected"}' >&2
127
+ exit 2
128
+ fi
129
+
130
+ # Check for system paths
131
+ if [[ "$file_path" == "/etc/"* ]] || [[ "$file_path" == "/sys/"* ]]; then
132
+ echo '{"decision": "deny", "reason": "System file"}' >&2
133
+ exit 2
134
+ fi
135
+ ```
136
+
137
+ **Problems:**
138
+
139
+ - Hard-coded path patterns
140
+ - Doesn't understand symlinks
141
+ - Missing edge cases (e.g., `/etc` vs `/etc/`)
142
+ - No consideration of file content
143
+
144
+ ### After (Advanced Prompt Hook)
145
+
146
+ **Configuration:**
147
+
148
+ ```json
149
+ {
150
+ "PreToolUse": [
151
+ {
152
+ "matcher": "Write|Edit",
153
+ "hooks": [
154
+ {
155
+ "type": "prompt",
156
+ "prompt": "File path: $TOOL_INPUT.file_path. Content preview: $TOOL_INPUT.content (first 200 chars). Verify: 1) Not system directories (/etc, /sys, /usr) 2) Not credentials (.env, tokens, secrets) 3) No path traversal 4) Content doesn't expose secrets. Return 'approve' or 'deny'."
157
+ }
158
+ ]
159
+ }
160
+ ]
161
+ }
162
+ ```
163
+
164
+ **Benefits:**
165
+
166
+ - Context-aware (considers content too)
167
+ - Handles symlinks and edge cases
168
+ - Natural understanding of "system directories"
169
+ - Can detect secrets in content
170
+ - Easy to extend criteria
171
+
172
+ ## When to Keep Command Hooks
173
+
174
+ Command hooks still have their place:
175
+
176
+ ### 1. Deterministic Performance Checks
177
+
178
+ ```bash
179
+ #!/bin/bash
180
+ # Check file size quickly
181
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path')
182
+ size=$(stat -f%z "$file_path" 2>/dev/null || stat -c%s "$file_path" 2>/dev/null)
183
+
184
+ if [ "$size" -gt 10000000 ]; then
185
+ echo '{"decision": "deny", "reason": "File too large"}' >&2
186
+ exit 2
187
+ fi
188
+ ```
189
+
190
+ **Use command hooks when:** Validation is purely mathematical or deterministic.
191
+
192
+ ### 2. External Tool Integration
193
+
194
+ ```bash
195
+ #!/bin/bash
196
+ # Run security scanner
197
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path')
198
+ scan_result=$(security-scanner "$file_path")
199
+
200
+ if [ "$?" -ne 0 ]; then
201
+ echo "Security scan failed: $scan_result" >&2
202
+ exit 2
203
+ fi
204
+ ```
205
+
206
+ **Use command hooks when:** Integrating with external tools that provide yes/no answers.
207
+
208
+ ### 3. Very Fast Checks (< 50ms)
209
+
210
+ ```bash
211
+ #!/bin/bash
212
+ # Quick regex check
213
+ command=$(echo "$input" | jq -r '.tool_input.command')
214
+
215
+ if [[ "$command" =~ ^(ls|pwd|echo)$ ]]; then
216
+ exit 0 # Safe commands
217
+ fi
218
+ ```
219
+
220
+ **Use command hooks when:** Performance is critical and logic is simple.
221
+
222
+ ## Hybrid Approach
223
+
224
+ Combine both for multi-stage validation:
225
+
226
+ ```json
227
+ {
228
+ "PreToolUse": [
229
+ {
230
+ "matcher": "Bash",
231
+ "hooks": [
232
+ {
233
+ "type": "command",
234
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/quick-check.sh",
235
+ "timeout": 5
236
+ },
237
+ {
238
+ "type": "prompt",
239
+ "prompt": "Deep analysis of bash command: $TOOL_INPUT",
240
+ "timeout": 15
241
+ }
242
+ ]
243
+ }
244
+ ]
245
+ }
246
+ ```
247
+
248
+ The command hook does fast deterministic checks, while the prompt hook handles complex reasoning.
249
+
250
+ ## Migration Checklist
251
+
252
+ When migrating hooks:
253
+
254
+ - [ ] Identify the validation logic in the command hook
255
+ - [ ] Convert hard-coded patterns to natural language criteria
256
+ - [ ] Test with edge cases the old hook missed
257
+ - [ ] Verify LLM understands the intent
258
+ - [ ] Set appropriate timeout (usually 15-30s for prompt hooks)
259
+ - [ ] Document the new hook in README
260
+ - [ ] Remove or archive old script files
261
+
262
+ ## Migration Tips
263
+
264
+ 1. **Start with one hook**: Don't migrate everything at once
265
+ 2. **Test thoroughly**: Verify prompt hook catches what command hook caught
266
+ 3. **Look for improvements**: Use migration as opportunity to enhance validation
267
+ 4. **Keep scripts for reference**: Archive old scripts in case you need to reference the logic
268
+ 5. **Document reasoning**: Explain why prompt hook is better in README
269
+
270
+ ## Complete Migration Example
271
+
272
+ ### Original Plugin Structure
273
+
274
+ ```
275
+ my-plugin/
276
+ ├── .claude-plugin/plugin.json
277
+ ├── hooks/hooks.json
278
+ └── scripts/
279
+ ├── validate-bash.sh
280
+ ├── validate-write.sh
281
+ └── check-tests.sh
282
+ ```
283
+
284
+ ### After Migration
285
+
286
+ ```
287
+ my-plugin/
288
+ ├── .claude-plugin/plugin.json
289
+ ├── hooks/hooks.json # Now uses prompt hooks
290
+ └── scripts/ # Archive or delete
291
+ └── archive/
292
+ ├── validate-bash.sh
293
+ ├── validate-write.sh
294
+ └── check-tests.sh
295
+ ```
296
+
297
+ ### Updated hooks.json
298
+
299
+ ```json
300
+ {
301
+ "PreToolUse": [
302
+ {
303
+ "matcher": "Bash",
304
+ "hooks": [
305
+ {
306
+ "type": "prompt",
307
+ "prompt": "Validate bash command safety: destructive ops, privilege escalation, network access"
308
+ }
309
+ ]
310
+ },
311
+ {
312
+ "matcher": "Write|Edit",
313
+ "hooks": [
314
+ {
315
+ "type": "prompt",
316
+ "prompt": "Validate file write safety: system paths, credentials, path traversal, content secrets"
317
+ }
318
+ ]
319
+ }
320
+ ],
321
+ "Stop": [
322
+ {
323
+ "matcher": "*",
324
+ "hooks": [
325
+ {
326
+ "type": "prompt",
327
+ "prompt": "Verify tests were run if code was modified"
328
+ }
329
+ ]
330
+ }
331
+ ]
332
+ }
333
+ ```
334
+
335
+ **Result:** Simpler, more maintainable, more powerful.
336
+
337
+ ## Common Migration Patterns
338
+
339
+ ### Pattern: String Contains → Natural Language
340
+
341
+ **Before:**
342
+
343
+ ```bash
344
+ if [[ "$command" == *"sudo"* ]]; then
345
+ echo "Privilege escalation" >&2
346
+ exit 2
347
+ fi
348
+ ```
349
+
350
+ **After:**
351
+
352
+ ```
353
+ "Check for privilege escalation (sudo, su, etc)"
354
+ ```
355
+
356
+ ### Pattern: Regex → Intent
357
+
358
+ **Before:**
359
+
360
+ ```bash
361
+ if [[ "$file" =~ \.(env|secret|key|token)$ ]]; then
362
+ echo "Credential file" >&2
363
+ exit 2
364
+ fi
365
+ ```
366
+
367
+ **After:**
368
+
369
+ ```
370
+ "Verify not writing to credential files (.env, secrets, keys, tokens)"
371
+ ```
372
+
373
+ ### Pattern: Multiple Conditions → Criteria List
374
+
375
+ **Before:**
376
+
377
+ ```bash
378
+ if [ condition1 ] || [ condition2 ] || [ condition3 ]; then
379
+ echo "Invalid" >&2
380
+ exit 2
381
+ fi
382
+ ```
383
+
384
+ **After:**
385
+
386
+ ```
387
+ "Check: 1) condition1 2) condition2 3) condition3. Deny if any fail."
388
+ ```
389
+
390
+ ## Conclusion
391
+
392
+ Migrating to prompt-based hooks makes plugins more maintainable, flexible, and powerful. Reserve command hooks for deterministic checks and external tool integration.