Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
"type": "command",
"command": "bash ${CURSOR_PLUGIN_ROOT}/hooks/scripts/track-telemetry.sh"
}
],
"afterMCPExecution": [
{
"type": "command",
"command": "bash ${CURSOR_PLUGIN_ROOT}/hooks/scripts/track-telemetry.sh"
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
# - Skill prefix: azure:<skill-name> (e.g., azure:azure-prepare)
# - Detection: has "hook_event_name", tool_use_id does NOT contain "__vscode"
#
# Cursor:
# - Field names: snake_case (tool_name, session_id, tool_input, hook_event_name)
# - Tool names: PascalCase for file reads (Read); raw MCP tool name from afterMCPExecution
# - Skill paths: .cursor/plugins/cache/<catalog>/azure/<revision>/skills/<name>/SKILL.md
# - Detection: has "hook_event_name" and "cursor_version"
# - MCP detection: afterMCPExecution event with mcp_server_name "azure"
#
# VS Code:
# - Field names: snake_case (tool_name, session_id, tool_input, hook_event_name)
# - Tool names: snake_case (read_file, replace_string_in_file)
Expand All @@ -42,7 +49,8 @@
#
# 2. tool_invocation
# - Triggered when: a tool matching an Azure MCP prefix is called
# (azure-*, mcp__plugin_azure_azure__*, mcp_azure_mcp_*)
# (azure-*, mcp__plugin_azure_azure__*, mcp_azure_mcp_*), or when Cursor
# sends afterMCPExecution with mcp_server_name "azure"
# - Tracked field: --tool-name <toolName>
#
# 3. reference_file_read
Expand All @@ -66,8 +74,8 @@
#
# === Reference File Detection ===
#
# When a file read tool is invoked (Copilot CLI: "view", Claude Code: "Read",
# VS Code: "read_file"), the script extracts the file path from the tool input
# When a file read tool is invoked (Copilot CLI: "view", Claude Code/Cursor:
# "Read", VS Code: "read_file"), the script extracts the file path from the tool input
# and checks if it falls within a recognized azure-skills folder:
#
# Path field lookup order:
Expand All @@ -82,10 +90,12 @@
# match the plugin's own name, "azure")
# - .claude/plugins/cache/azure-skills/azure/<version>/skills/...
# - .claude/plugins/cache/claude-plugins-official/azure/<version>/skills/...
# - .cursor/plugins/cache/<catalog-name>/azure/<revision>/skills/...
# - .vscode/agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-skills/skills/...
# azure-kusto-graph-skills:
# - .copilot/installed-plugins/<catalog-name>/azure-kusto-graph-skills/skills/...
# - .claude/plugins/cache/azure-skills/azure-kusto-graph-skills/<version>/skills/...
# - .cursor/plugins/cache/<catalog-name>/azure-kusto-graph-skills/<revision>/skills/...
# - .vscode/agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-kusto-graph-skills/skills/...
# shared:
# - .agents/skills/...
Expand Down Expand Up @@ -244,6 +254,8 @@ $sessionId = $inputData.sessionId
if (-not $sessionId) {
$sessionId = $inputData.session_id
}
$hookEventName = $inputData.hook_event_name
$mcpServerName = $inputData.mcp_server_name

# Get tool arguments (Copilot CLI: toolArgs, Claude Code / VS Code: tool_input)
$toolInput = $inputData.toolArgs
Expand Down Expand Up @@ -318,20 +330,22 @@ function Get-ToolInputPath {
# own name ("azure").
$pathPatternCopilot = '\.copilot/installed-plugins/[^/]+/azure/skills/'
$pathPatternClaude = '\.claude/plugins/cache/(azure-skills|claude-plugins-official)/azure/[0-9.]+/skills/'
$pathPatternCursor = '\.cursor/plugins/cache/[^/]+/azure/[^/]+/skills/'
$pathPatternVscodeAgentPlugins = 'agent-plugins/github\.com/microsoft/azure-skills/\.github/plugins/azure-skills/skills/'

# --- azure-kusto-graph-skills plugin ---
$pathPatternCopilotKustoGraph = '\.copilot/installed-plugins/[^/]+/azure-kusto-graph-skills/skills/'
$pathPatternClaudeKustoGraph = '\.claude/plugins/cache/azure-skills/azure-kusto-graph-skills/[0-9.]+/skills/'
$pathPatternCursorKustoGraph = '\.cursor/plugins/cache/[^/]+/azure-kusto-graph-skills/[^/]+/skills/'
$pathPatternVscodeAgentPluginsKustoGraph = 'agent-plugins/github\.com/microsoft/azure-skills/\.github/plugins/azure-kusto-graph-skills/skills/'

# --- shared across all plugins ---
$pathPatternAgentsSkills = '\.agents/skills/'

# Put the path patterns into an array for easier iteration
$pathPatterns = @(
$pathPatternCopilot, $pathPatternClaude, $pathPatternVscodeAgentPlugins,
$pathPatternCopilotKustoGraph, $pathPatternClaudeKustoGraph, $pathPatternVscodeAgentPluginsKustoGraph,
$pathPatternCopilot, $pathPatternClaude, $pathPatternCursor, $pathPatternVscodeAgentPlugins,
$pathPatternCopilotKustoGraph, $pathPatternClaudeKustoGraph, $pathPatternCursorKustoGraph, $pathPatternVscodeAgentPluginsKustoGraph,
$pathPatternAgentsSkills
)

Expand Down Expand Up @@ -397,9 +411,18 @@ if ($toolName -eq "view" -or $toolName -eq "Read" -or $toolName -eq "read_file")
# Check for Azure MCP tool invocation
# Copilot CLI: "azure-*" prefix (e.g., azure-documentation)
# Claude Code: "mcp__plugin_azure_azure__*" prefix (e.g., mcp__plugin_azure_azure__documentation)
# Cursor: afterMCPExecution with mcp_server_name "azure"; normalize the
# raw tool name to the postToolUse form (e.g., MCP:get_azure_bestpractices)
# VS Code: "mcp_azure_mcp_*" prefix (e.g., mcp_azure_mcp_documentation)
if ($toolName) {
if ($toolName.StartsWith("azure-") -or $toolName.StartsWith("mcp__plugin_azure_azure__") -or $toolName.StartsWith("mcp_azure_mcp_")) {
if ($clientName -eq "cursor" -and $hookEventName -eq "afterMCPExecution" -and $mcpServerName -eq "azure") {
$azureToolName = $toolName
if (-not $azureToolName.StartsWith("MCP:")) {
$azureToolName = "MCP:$azureToolName"
}
$eventType = "tool_invocation"
$shouldTrack = $true
} elseif ($toolName.StartsWith("azure-") -or $toolName.StartsWith("mcp__plugin_azure_azure__") -or $toolName.StartsWith("mcp_azure_mcp_")) {
$azureToolName = $toolName
$eventType = "tool_invocation"
$shouldTrack = $true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
# - Skill prefix: azure:<skill-name> (e.g., azure:azure-prepare)
# - Detection: has "hook_event_name", tool_use_id does NOT contain "__vscode"
#
# Cursor:
# - Field names: snake_case (tool_name, session_id, tool_input, hook_event_name)
# - Tool names: PascalCase for file reads (Read); raw MCP tool name from afterMCPExecution
# - Skill paths: .cursor/plugins/cache/<catalog>/azure/<revision>/skills/<name>/SKILL.md
# - Detection: has "hook_event_name" and "cursor_version"
# - MCP detection: afterMCPExecution event with mcp_server_name "azure"
#
# VS Code:
# - Field names: snake_case (tool_name, session_id, tool_input, hook_event_name)
# - Tool names: snake_case (read_file, replace_string_in_file)
Expand All @@ -44,7 +51,8 @@
#
# 2. tool_invocation
# - Triggered when: a tool matching an Azure MCP prefix is called
# (azure-*, mcp__plugin_azure_azure__*, mcp_azure_mcp_*)
# (azure-*, mcp__plugin_azure_azure__*, mcp_azure_mcp_*), or when Cursor
# sends afterMCPExecution with mcp_server_name "azure"
# - Tracked field: --tool-name <toolName>
#
# 3. reference_file_read
Expand All @@ -68,8 +76,8 @@
#
# === Reference File Detection ===
#
# When a file read tool is invoked (Copilot CLI: "view", Claude Code: "Read",
# VS Code: "read_file"), the script extracts the file path from the tool input
# When a file read tool is invoked (Copilot CLI: "view", Claude Code/Cursor:
# "Read", VS Code: "read_file"), the script extracts the file path from the tool input
# and checks if it falls within a recognized azure-skills folder:
#
# Path field lookup order:
Expand All @@ -84,10 +92,12 @@
# match the plugin's own name, "azure")
# - .claude/plugins/cache/azure-skills/azure/<version>/skills/...
# - .claude/plugins/cache/claude-plugins-official/azure/<version>/skills/...
# - .cursor/plugins/cache/<catalog-name>/azure/<revision>/skills/...
# - .vscode/agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-skills/skills/...
# azure-kusto-graph-skills:
# - .copilot/installed-plugins/<catalog-name>/azure-kusto-graph-skills/skills/...
# - .claude/plugins/cache/azure-skills/azure-kusto-graph-skills/<version>/skills/...
# - .cursor/plugins/cache/<catalog-name>/azure-kusto-graph-skills/<revision>/skills/...
# - .vscode/agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-kusto-graph-skills/skills/...
# shared:
# - .agents/skills/...
Expand Down Expand Up @@ -260,6 +270,8 @@ write_raw_input_to_file "$rawInput"
# Support Copilot CLI (camelCase), Claude Code (snake_case), and VS Code (snake_case) formats
toolName=$(extract_json_field "$rawInput" "toolName")
sessionId=$(extract_json_field "$rawInput" "sessionId")
hookEventName=$(extract_json_field "$rawInput" "hook_event_name")
mcpServerName=$(extract_json_field "$rawInput" "mcp_server_name")

# Fall back to Claude Code / VS Code snake_case field names
if [ -z "$toolName" ]; then
Expand Down Expand Up @@ -329,11 +341,13 @@ is_azure_skills_path() {
[[ "$p" == *".copilot/installed-plugins/"*"/azure/skills/"* ]] && return 0
[[ "$p" == *".claude/plugins/cache/azure-skills/azure/"*"/skills/"* ]] && return 0
[[ "$p" == *".claude/plugins/cache/claude-plugins-official/azure/"*"/skills/"* ]] && return 0
[[ "$p" == *".cursor/plugins/cache/"*"/azure/"*"/skills/"* ]] && return 0
[[ "$p" == *"agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-skills/skills/"* ]] && return 0

# --- azure-kusto-graph-skills plugin ---
[[ "$p" == *".copilot/installed-plugins/"*"/azure-kusto-graph-skills/skills/"* ]] && return 0
[[ "$p" == *".claude/plugins/cache/azure-skills/azure-kusto-graph-skills/"*"/skills/"* ]] && return 0
[[ "$p" == *".cursor/plugins/cache/"*"/azure-kusto-graph-skills/"*"/skills/"* ]] && return 0
[[ "$p" == *"agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-kusto-graph-skills/skills/"* ]] && return 0

# --- shared across all plugins ---
Expand Down Expand Up @@ -394,9 +408,16 @@ fi
# Check for Azure MCP tool invocation
# Copilot CLI: "azure-*" prefix (e.g., azure-documentation)
# Claude Code: "mcp__plugin_azure_azure__*" prefix (e.g., mcp__plugin_azure_azure__documentation)
# Cursor: afterMCPExecution with mcp_server_name "azure"; normalize the
# raw tool name to the postToolUse form (e.g., MCP:get_azure_bestpractices)
# VS Code: "mcp_azure_mcp_*" prefix (e.g., mcp_azure_mcp_documentation)
if [ -n "$toolName" ]; then
if [[ "$toolName" == azure-* ]] || [[ "$toolName" == mcp__plugin_azure_azure__* ]] || [[ "$toolName" == mcp_azure_mcp_* ]]; then
if [ "$clientName" = "cursor" ] && [ "$hookEventName" = "afterMCPExecution" ] && [ "$mcpServerName" = "azure" ]; then
azureToolName="$toolName"
[[ "$azureToolName" == MCP:* ]] || azureToolName="MCP:$azureToolName"
eventType="tool_invocation"
shouldTrack=true
elif [[ "$toolName" == azure-* ]] || [[ "$toolName" == mcp__plugin_azure_azure__* ]] || [[ "$toolName" == mcp_azure_mcp_* ]]; then
azureToolName="$toolName"
eventType="tool_invocation"
shouldTrack=true
Expand Down Expand Up @@ -466,4 +487,3 @@ fi

# Output success to stdout (required by hooks)
return_success

6 changes: 6 additions & 0 deletions .github/plugins/azure-skills/hooks/cursor-hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
"type": "command",
"command": "bash ${CURSOR_PLUGIN_ROOT}/hooks/scripts/track-telemetry.sh"
}
],
"afterMCPExecution": [
{
"type": "command",
"command": "bash ${CURSOR_PLUGIN_ROOT}/hooks/scripts/track-telemetry.sh"
}
]
}
}
35 changes: 29 additions & 6 deletions .github/plugins/azure-skills/hooks/scripts/track-telemetry.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
# - Skill prefix: azure:<skill-name> (e.g., azure:azure-prepare)
# - Detection: has "hook_event_name", tool_use_id does NOT contain "__vscode"
#
# Cursor:
# - Field names: snake_case (tool_name, session_id, tool_input, hook_event_name)
# - Tool names: PascalCase for file reads (Read); raw MCP tool name from afterMCPExecution
# - Skill paths: .cursor/plugins/cache/<catalog>/azure/<revision>/skills/<name>/SKILL.md
# - Detection: has "hook_event_name" and "cursor_version"
# - MCP detection: afterMCPExecution event with mcp_server_name "azure"
#
# VS Code:
# - Field names: snake_case (tool_name, session_id, tool_input, hook_event_name)
# - Tool names: snake_case (read_file, replace_string_in_file)
Expand All @@ -42,7 +49,8 @@
#
# 2. tool_invocation
# - Triggered when: a tool matching an Azure MCP prefix is called
# (azure-*, mcp__plugin_azure_azure__*, mcp_azure_mcp_*)
# (azure-*, mcp__plugin_azure_azure__*, mcp_azure_mcp_*), or when Cursor
# sends afterMCPExecution with mcp_server_name "azure"
# - Tracked field: --tool-name <toolName>
#
# 3. reference_file_read
Expand All @@ -66,8 +74,8 @@
#
# === Reference File Detection ===
#
# When a file read tool is invoked (Copilot CLI: "view", Claude Code: "Read",
# VS Code: "read_file"), the script extracts the file path from the tool input
# When a file read tool is invoked (Copilot CLI: "view", Claude Code/Cursor:
# "Read", VS Code: "read_file"), the script extracts the file path from the tool input
# and checks if it falls within a recognized azure-skills folder:
#
# Path field lookup order:
Expand All @@ -82,10 +90,12 @@
# match the plugin's own name, "azure")
# - .claude/plugins/cache/azure-skills/azure/<version>/skills/...
# - .claude/plugins/cache/claude-plugins-official/azure/<version>/skills/...
# - .cursor/plugins/cache/<catalog-name>/azure/<revision>/skills/...
# - .vscode/agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-skills/skills/...
# azure-kusto-graph-skills:
# - .copilot/installed-plugins/<catalog-name>/azure-kusto-graph-skills/skills/...
# - .claude/plugins/cache/azure-skills/azure-kusto-graph-skills/<version>/skills/...
# - .cursor/plugins/cache/<catalog-name>/azure-kusto-graph-skills/<revision>/skills/...
# - .vscode/agent-plugins/github.com/microsoft/azure-skills/.github/plugins/azure-kusto-graph-skills/skills/...
# shared:
# - .agents/skills/...
Expand Down Expand Up @@ -244,6 +254,8 @@ $sessionId = $inputData.sessionId
if (-not $sessionId) {
$sessionId = $inputData.session_id
}
$hookEventName = $inputData.hook_event_name
$mcpServerName = $inputData.mcp_server_name

# Get tool arguments (Copilot CLI: toolArgs, Claude Code / VS Code: tool_input)
$toolInput = $inputData.toolArgs
Expand Down Expand Up @@ -318,20 +330,22 @@ function Get-ToolInputPath {
# own name ("azure").
$pathPatternCopilot = '\.copilot/installed-plugins/[^/]+/azure/skills/'
$pathPatternClaude = '\.claude/plugins/cache/(azure-skills|claude-plugins-official)/azure/[0-9.]+/skills/'
$pathPatternCursor = '\.cursor/plugins/cache/[^/]+/azure/[^/]+/skills/'
$pathPatternVscodeAgentPlugins = 'agent-plugins/github\.com/microsoft/azure-skills/\.github/plugins/azure-skills/skills/'

# --- azure-kusto-graph-skills plugin ---
$pathPatternCopilotKustoGraph = '\.copilot/installed-plugins/[^/]+/azure-kusto-graph-skills/skills/'
$pathPatternClaudeKustoGraph = '\.claude/plugins/cache/azure-skills/azure-kusto-graph-skills/[0-9.]+/skills/'
$pathPatternCursorKustoGraph = '\.cursor/plugins/cache/[^/]+/azure-kusto-graph-skills/[^/]+/skills/'
$pathPatternVscodeAgentPluginsKustoGraph = 'agent-plugins/github\.com/microsoft/azure-skills/\.github/plugins/azure-kusto-graph-skills/skills/'

# --- shared across all plugins ---
$pathPatternAgentsSkills = '\.agents/skills/'

# Put the path patterns into an array for easier iteration
$pathPatterns = @(
$pathPatternCopilot, $pathPatternClaude, $pathPatternVscodeAgentPlugins,
$pathPatternCopilotKustoGraph, $pathPatternClaudeKustoGraph, $pathPatternVscodeAgentPluginsKustoGraph,
$pathPatternCopilot, $pathPatternClaude, $pathPatternCursor, $pathPatternVscodeAgentPlugins,
$pathPatternCopilotKustoGraph, $pathPatternClaudeKustoGraph, $pathPatternCursorKustoGraph, $pathPatternVscodeAgentPluginsKustoGraph,
$pathPatternAgentsSkills
)

Expand Down Expand Up @@ -397,9 +411,18 @@ if ($toolName -eq "view" -or $toolName -eq "Read" -or $toolName -eq "read_file")
# Check for Azure MCP tool invocation
# Copilot CLI: "azure-*" prefix (e.g., azure-documentation)
# Claude Code: "mcp__plugin_azure_azure__*" prefix (e.g., mcp__plugin_azure_azure__documentation)
# Cursor: afterMCPExecution with mcp_server_name "azure"; normalize the
# raw tool name to the postToolUse form (e.g., MCP:get_azure_bestpractices)
# VS Code: "mcp_azure_mcp_*" prefix (e.g., mcp_azure_mcp_documentation)
if ($toolName) {
if ($toolName.StartsWith("azure-") -or $toolName.StartsWith("mcp__plugin_azure_azure__") -or $toolName.StartsWith("mcp_azure_mcp_")) {
if ($clientName -eq "cursor" -and $hookEventName -eq "afterMCPExecution" -and $mcpServerName -eq "azure") {
$azureToolName = $toolName
if (-not $azureToolName.StartsWith("MCP:")) {
$azureToolName = "MCP:$azureToolName"
}
$eventType = "tool_invocation"
$shouldTrack = $true
} elseif ($toolName.StartsWith("azure-") -or $toolName.StartsWith("mcp__plugin_azure_azure__") -or $toolName.StartsWith("mcp_azure_mcp_")) {
$azureToolName = $toolName
$eventType = "tool_invocation"
$shouldTrack = $true
Expand Down
Loading
Loading