+
+Environment Variables:
+ GITHUB_ACCESS_TOKEN or GITHUB_PAT: GitHub personal access token with repo scope
+"""
+
+import os
+import sys
+import argparse
+import requests
+
+
+def get_github_token() -> str:
+ """Get GitHub token from environment variables."""
+ token = os.environ.get("GITHUB_ACCESS_TOKEN") or os.environ.get("GITHUB_PAT")
+ if not token:
+ raise ValueError(
+ "GitHub token not found. Set GITHUB_ACCESS_TOKEN or GITHUB_PAT environment variable."
+ )
+ return token
+
+
+def add_labels(
+ owner: str, repo: str, issue_number: int, labels: list[str], token: str
+) -> dict:
+ """Add labels to a GitHub issue."""
+ url = f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/labels"
+ headers = {
+ "Authorization": f"Bearer {token}",
+ "Accept": "application/vnd.github+json",
+ "X-GitHub-Api-Version": "2022-11-28",
+ }
+ response = requests.post(url, headers=headers, json={"labels": labels})
+ response.raise_for_status()
+ return response.json()
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Add labels to GitHub issues."
+ )
+ parser.add_argument("owner", help="Repository owner (e.g., 'microsoft')")
+ parser.add_argument("repo", help="Repository name (e.g., 'vscode')")
+ parser.add_argument("issue_number", type=int, help="Issue number to label")
+ parser.add_argument(
+ "labels", help="Comma-separated list of labels (e.g., 'bug,priority:high')"
+ )
+
+ args = parser.parse_args()
+ labels = [label.strip() for label in args.labels.split(",") if label.strip()]
+
+ if not labels:
+ print("❌ No labels provided.", file=sys.stderr)
+ sys.exit(1)
+
+ try:
+ token = get_github_token()
+ result = add_labels(args.owner, args.repo, args.issue_number, labels, token)
+ applied_labels = [label["name"] for label in result]
+ print(f"✅ Labels added to issue #{args.issue_number}: {', '.join(applied_labels)}")
+ sys.exit(0)
+ except ValueError as e:
+ print(f"❌ Configuration error: {e}", file=sys.stderr)
+ sys.exit(1)
+ except requests.HTTPError as e:
+ print(f"❌ GitHub API error: {e}", file=sys.stderr)
+ if e.response is not None:
+ print(f" Response: {e.response.text}", file=sys.stderr)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/skills/send-email/SKILL.md b/.github/skills/send-email/SKILL.md
new file mode 100644
index 00000000..01bccf64
--- /dev/null
+++ b/.github/skills/send-email/SKILL.md
@@ -0,0 +1,116 @@
+---
+name: send-email
+description: Send HTML email notifications via Azure Logic App. Use when (1) sending formatted emails to recipients, (2) delivering reports or summaries via email, (3) triggering email notifications from workflows. Triggers on requests like "send email", "email this", "send via email", "mail to".
+---
+
+# Send Email Skill
+
+Send HTML email notifications to specified recipients via an Azure Logic App HTTP trigger.
+
+## Overview
+
+This skill constructs a well-formatted HTML email from user-provided content and posts it to a configured Logic App endpoint for delivery.
+
+## Usage
+
+### Required Environment Variable
+
+The mailing URL must be set via environment variable:
+- `MAILING_URL`: The Azure Logic App HTTP trigger URL for email sending
+
+### Required Input from User
+
+The user must provide:
+1. **Content**: The information/message to be sent (any format - text, data, structured content)
+2. **Recipients**: One or more email addresses
+3. **Title** (optional): Subject line for the email
+4. **Time frame** (optional): Relevant date/period context
+
+### Payload Schema
+
+The skill constructs and sends a JSON payload:
+
+```json
+{
+ "title": "Email Subject",
+ "timeFrame": "January 28, 2026",
+ "body": "...",
+ "workflowRunUrl": "https://github.com/org/repo/actions/runs/12345",
+ "recipients": ["user1@example.com", "user2@example.com"]
+}
+```
+
+For the full JSON schema, see [references/payload-schema.json](references/payload-schema.json).
+
+### HTML Body Construction
+
+The skill must transform user-provided content into well-formatted HTML:
+
+1. **Use semantic HTML structure with inline CSS** (email clients don't support external stylesheets)
+
+2. **Base template**:
+ ```html
+
+
+
+
{{title}}
+
{{timeFrame}}
+
+
+
+ {{content}}
+
+
+
+ Generated by GitHub Actions workflow
+
+
+
+ ```
+
+3. **Content formatting guidelines**:
+ - Plain text → Wrap in `` tags
+ - Lists → Use `
` or `` with appropriate styling
+ - Tables/data → Use `` with borders and padding
+ - Links → Use `` tags with `color: #0366d6`
+ - Emphasis → Use `` or styled `` elements
+ - Code → Use `` with monospace font and background
+
+## Workflow
+
+1. Receive content and recipients from user
+2. Validate that `MAILING_URL` environment variable is set
+3. Validate that recipients list is not empty
+4. Construct HTML body from the user-provided content
+5. POST the JSON payload to the Logic App endpoint
+6. Report success or failure to the user
+
+## Example Commands
+
+- "Send this to user@example.com via email"
+- "Email the following summary to the team"
+- "Mail this information to john@company.com"
+- "Send an email with these details"
+
+## Implementation
+
+Use curl or equivalent HTTP client to POST the JSON:
+
+```bash
+curl -X POST "$MAILING_URL" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "title": "Email Subject",
+ "timeFrame": "January 28, 2026",
+ "body": "...",
+ "workflowRunUrl": "https://github.com/org/repo/actions/runs/12345",
+ "recipients": ["user@example.com"]
+ }'
+```
+
+## Response Handling
+
+- **HTTP 2xx**: Email sent successfully ✅
+- **HTTP 4xx/5xx**: Failed to send email ❌
+
+Report the result to the user with the HTTP status code.
\ No newline at end of file
diff --git a/.github/skills/send-email/references/payload-schema.json b/.github/skills/send-email/references/payload-schema.json
new file mode 100644
index 00000000..cfe7a48b
--- /dev/null
+++ b/.github/skills/send-email/references/payload-schema.json
@@ -0,0 +1,34 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Email Notification Payload",
+ "description": "JSON schema for the email notification payload sent to the Logic App",
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "Title of the email/report, used in the email subject"
+ },
+ "timeFrame": {
+ "type": "string",
+ "description": "The time period covered by the report, appended to the subject"
+ },
+ "body": {
+ "type": "string",
+ "description": "Well-formatted HTML content for the email body"
+ },
+ "workflowRunUrl": {
+ "type": "string",
+ "description": "URL to the workflow run that generated this report"
+ },
+ "recipients": {
+ "type": "array",
+ "description": "List of email addresses to send the notification to",
+ "items": {
+ "type": "string",
+ "format": "email"
+ },
+ "minItems": 1
+ }
+ },
+ "required": ["title", "timeFrame", "body", "recipients"]
+}
diff --git a/.github/skills/send-notification/SKILL.md b/.github/skills/send-notification/SKILL.md
new file mode 100644
index 00000000..e6afa81c
--- /dev/null
+++ b/.github/skills/send-notification/SKILL.md
@@ -0,0 +1,91 @@
+---
+name: send-notification
+description: Send adaptive card notifications to Microsoft Teams via Azure Logic App. Use when (1) sending issue triage reports to Teams, (2) posting JSON payloads as Teams notifications, (3) triggering workflow result notifications. Triggers on requests like "send notification", "notify team", "post to Teams", "send report".
+---
+
+# Send Notification Skill
+
+Send adaptive card notifications to Microsoft Teams via an Azure Logic App HTTP trigger.
+
+## Overview
+
+This skill posts a JSON payload to a configured Logic App endpoint, which transforms the data into an adaptive card and sends it to a bound Teams group chat.
+
+## Usage
+
+### Required Environment Variable
+
+The notification URL must be set via environment variable:
+- `NOTIFICATION_URL`: The Azure Logic App HTTP trigger URL
+
+### Input Format
+
+The payload should be a JSON object matching the IssueLens triage report schema:
+
+```json
+{
+ "title": "Daily Issue Report for Java Tooling",
+ "timeFrame": "January 28, 2026",
+ "totalIssues": 8,
+ "criticalIssues": 3,
+ "overallSummary": "Today, 8 issues were reported. 3 were identified as critical.",
+ "criticalIssuesSummary": [
+ {
+ "issueNumber": 1234,
+ "url": "https://github.com/org/repo/issues/1234",
+ "title": "Issue title here",
+ "summary": "Brief description of the issue and reason for criticality.",
+ "labels": "🔴 **High Priority** | 🏷️ bug, critical"
+ }
+ ],
+ "allIssues": [
+ {
+ "issueNumber": 1234,
+ "url": "https://github.com/org/repo/issues/1234",
+ "title": "Issue title here"
+ }
+ ],
+ "workflowRunUrl": "https://github.com/org/repo/actions/runs/12345"
+}
+```
+
+For the full JSON schema, see [references/payload-schema.json](references/payload-schema.json).
+
+## Workflow
+
+1. Receive JSON payload from user or another skill/agent
+2. Validate that `NOTIFICATION_URL` environment variable is set
+3. POST the JSON payload to the Logic App endpoint
+4. Report success or failure to the user
+
+## Example Commands
+
+- "Send this triage report as a notification"
+- "Post the issue summary to Teams"
+- "Notify the team about critical issues"
+
+## Implementation
+
+Use curl or equivalent HTTP client to POST the JSON:
+
+```bash
+curl -X POST "$NOTIFICATION_URL" \
+ -H "Content-Type: application/json" \
+ -d ''
+```
+
+## Response Handling
+
+- **HTTP 2xx**: Notification sent successfully ✅
+- **HTTP 4xx/5xx**: Failed to send notification ❌
+
+Report the result to the user with the HTTP status code.
+
+## Integration with IssueLens Agent
+
+This skill is designed to work with the IssueLens triage agent. After the agent generates a JSON report, invoke this skill to send the notification:
+
+1. IssueLens agent triages issues and outputs JSON
+2. User requests "send notification" with the JSON payload
+3. This skill POSTs to the Logic App
+4. Teams receives an adaptive card notification
diff --git a/.github/skills/send-notification/references/payload-schema.json b/.github/skills/send-notification/references/payload-schema.json
new file mode 100644
index 00000000..8e331791
--- /dev/null
+++ b/.github/skills/send-notification/references/payload-schema.json
@@ -0,0 +1,85 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "IssueLens Notification Payload",
+ "description": "JSON schema for the notification payload sent to the Logic App",
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "Title of the notification/report"
+ },
+ "timeFrame": {
+ "type": "string",
+ "description": "The time period covered by the report"
+ },
+ "totalIssues": {
+ "type": "integer",
+ "description": "Total number of issues analyzed"
+ },
+ "criticalIssues": {
+ "type": "integer",
+ "description": "Number of critical issues identified"
+ },
+ "overallSummary": {
+ "type": "string",
+ "description": "Brief overview of the issues (no repo names)"
+ },
+ "criticalIssuesSummary": {
+ "type": "array",
+ "description": "Detailed summary of critical issues",
+ "items": {
+ "type": "object",
+ "properties": {
+ "issueNumber": {
+ "type": "integer",
+ "description": "GitHub issue number"
+ },
+ "url": {
+ "type": "string",
+ "description": "Full URL to the issue"
+ },
+ "title": {
+ "type": "string",
+ "description": "Issue title"
+ },
+ "summary": {
+ "type": "string",
+ "description": "Brief description including symptoms and reason for criticality"
+ },
+ "labels": {
+ "type": "string",
+ "description": "Priority level and labels, e.g., '🔴 **High Priority** | 🏷️ bug, critical'"
+ }
+ },
+ "required": ["issueNumber", "url", "title", "summary", "labels"]
+ }
+ },
+ "allIssues": {
+ "type": "array",
+ "description": "List of all issues analyzed",
+ "items": {
+ "type": "object",
+ "properties": {
+ "issueNumber": {
+ "type": "integer",
+ "description": "GitHub issue number"
+ },
+ "url": {
+ "type": "string",
+ "description": "Full URL to the issue"
+ },
+ "title": {
+ "type": "string",
+ "description": "Issue title"
+ }
+ },
+ "required": ["issueNumber", "url", "title"]
+ }
+ },
+ "workflowRunUrl": {
+ "type": "string",
+ "description": "URL to the workflow run that generated this report"
+ }
+ },
+ "required": ["title", "timeFrame", "totalIssues", "criticalIssues", "overallSummary", "criticalIssuesSummary", "allIssues"]
+}
diff --git a/.github/skills/send-personal-notification/SKILL.md b/.github/skills/send-personal-notification/SKILL.md
new file mode 100644
index 00000000..91a4a89b
--- /dev/null
+++ b/.github/skills/send-personal-notification/SKILL.md
@@ -0,0 +1,88 @@
+---
+name: send-personal-notification
+description: Send workflow bot messages to Teams personal chat via Azure Logic App. Use when (1) sending personal notifications to individuals, (2) delivering triage summaries to specific recipients, (3) triggering personal workflow alerts. Triggers on requests like "send personal notification", "notify user", "send message to", "personal message".
+---
+
+# Send Personal Notification Skill
+
+Send workflow bot messages to Microsoft Teams personal chat via an Azure Logic App HTTP trigger.
+
+## Overview
+
+This skill posts a JSON payload to a configured Logic App endpoint, which sends a workflow bot message directly to a specified recipient's Teams personal chat.
+
+## Usage
+
+### Required Environment Variable
+
+The notification URL must be set via environment variable:
+- `PERSONAL_NOTIFICATION_URL`: The Azure Logic App HTTP trigger URL for personal notifications
+
+### Input Format
+
+The payload should be a JSON object with the following structure:
+
+```json
+{
+ "title": "Daily Issue Triage Report - February 2, 2026",
+ "message": "## Triage Summary\n\nToday's triage identified **5 issues** requiring attention. 2 issues are SLA violations, 2 are compliant, and 1 is waiting on reporter.\n\n### Issues Triaged\n\n| Issue # | Title | Assignees |\n|---------|-------|----------|\n| #1234 | Java debugger crashes on Windows with JDK 21 | @javadev, @debugteam |\n| #1256 | Add support for Java 22 preview features | @featurelead |\n| #1278 | IntelliSense not working for record classes | @intellisense-team |\n| #1290 | Build fails with Gradle 8.5 | @buildtools, @qaengineer |\n| #1301 | Documentation missing for new refactoring options | @docwriter |",
+ "workflowRunUrl": "https://github.com/microsoft/vscode-java-pack/actions/runs/12345678/job/98765432",
+ "recipient": "johndeo@microsoft.com"
+}
+```
+
+For the full JSON schema, see [references/payload-schema.json](references/payload-schema.json).
+
+### Fields
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `title` | string | Title of the notification message |
+| `message` | string | Main content of the message (supports markdown) |
+| `workflowRunUrl` | string | URL to the workflow run that generated this notification |
+| `recipient` | string | Email address of the recipient |
+
+## Workflow
+
+1. Receive JSON payload from user or another skill/agent
+2. Validate that `PERSONAL_NOTIFICATION_URL` environment variable is set
+3. Validate that required fields are present (especially `recipient`)
+4. POST the JSON payload to the Logic App endpoint
+5. Report success or failure to the user
+
+## Example Commands
+
+- "Send this triage summary as a personal notification to user@example.com"
+- "Notify john@company.com about the issue report"
+- "Send a personal message to the assignee"
+
+## Implementation
+
+Use curl or equivalent HTTP client to POST the JSON:
+
+```bash
+curl -X POST "$PERSONAL_NOTIFICATION_URL" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "title": "Daily Issue Triage Report - February 2, 2026",
+ "message": "## Triage Summary\n\n...",
+ "workflowRunUrl": "https://github.com/org/repo/actions/runs/12345",
+ "recipient": "user@example.com"
+ }'
+```
+
+## Response Handling
+
+- **HTTP 2xx**: Personal notification sent successfully ✅
+- **HTTP 4xx/5xx**: Failed to send notification ❌
+
+Report the result to the user with the HTTP status code.
+
+## Integration with Other Skills
+
+This skill can be used in conjunction with the IssueLens triage agent or other reporting workflows to deliver personalized notifications:
+
+1. A triage agent or workflow generates a report
+2. User requests "send personal notification" with recipient and message
+3. This skill POSTs to the Logic App
+4. Recipient receives a personal Teams message from the workflow bot
diff --git a/.github/skills/send-personal-notification/references/payload-schema.json b/.github/skills/send-personal-notification/references/payload-schema.json
new file mode 100644
index 00000000..e51a3489
--- /dev/null
+++ b/.github/skills/send-personal-notification/references/payload-schema.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Personal Notification Payload",
+ "description": "JSON schema for personal notification payload sent to the Logic App",
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "Title of the notification message"
+ },
+ "message": {
+ "type": "string",
+ "description": "Main content of the message (supports markdown)"
+ },
+ "workflowRunUrl": {
+ "type": "string",
+ "description": "URL to the workflow run that generated this notification"
+ },
+ "recipient": {
+ "type": "string",
+ "description": "Email address of the recipient"
+ }
+ },
+ "required": ["title", "message", "workflowRunUrl", "recipient"]
+}
diff --git a/.github/workflows/issueLens-run.yml b/.github/workflows/issueLens-run.yml
index 422d007a..97e984b4 100644
--- a/.github/workflows/issueLens-run.yml
+++ b/.github/workflows/issueLens-run.yml
@@ -1,10 +1,14 @@
name: Run IssueLens Agent
on:
- schedule:
- # Run once daily at 1am UTC
- - cron: '0 1 * * *'
+ # issues:
+ # types: [opened]
workflow_dispatch:
+ inputs:
+ issue_number:
+ description: 'Issue number to triage'
+ required: true
+ type: string
jobs:
run-issuelens:
@@ -21,44 +25,39 @@ jobs:
- name: Install GitHub Copilot CLI
run: npm install -g @github/copilot
+ - name: Determine issue number
+ id: issue
+ run: |
+ if [ "${{ github.event_name }}" = "issues" ]; then
+ echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT
+ else
+ echo "number=${{ inputs.issue_number }}" >> $GITHUB_OUTPUT
+ fi
+
- name: Run IssueLens with Copilot CLI
id: issuelens
run: |
# Create MCP config
- echo '{"mcpServers": {"mcp-datetime": {"type": "local", "command": "uvx", "args": ["mcp-datetime"], "tools": ["*"]}}}' > mcp-config.json
+ echo '{"mcpServers": {"javatooling-search": {"type": "http", "url": "${{ secrets.JAVATOOLING_INDEX_URL }}"}}}' > mcp-config.json
# Run copilot CLI with issuelens custom agent
- output=$(copilot --agent=issuelens --additional-mcp-config @mcp-config.json --prompt "triage issues for repo \"${{ github.repository }}\"" 2>&1 || true)
+ output=$(copilot --agent=issuelens --additional-mcp-config @mcp-config.json --prompt "triage issue #${{ steps.issue.outputs.number }} for repo \"${{ github.repository }}\"" 2>&1 || true)
echo "Raw output:"
echo "$output"
- # Extract JSON from output (looking for lines between curly braces)
- json_output=$(echo "$output" | sed -n '/^{/,/^}/p' | jq -c '.')
-
- # If no JSON found with that pattern, try to extract any JSON
- if [ -z "$json_output" ]; then
- json_output=$(echo "$output" | grep -o '{[^}]*}' | jq -c '.' | head -1)
- fi
-
- # If still no JSON, create a default payload with the raw output
- if [ -z "$json_output" ]; then
- json_output=$(jq -n --arg output "$output" '{"message": "IssueLens analysis complete", "output": $output}')
- fi
-
- echo "Extracted JSON:"
- echo "$json_output"
-
- # Save to output
- echo "payload=$json_output" >> $GITHUB_OUTPUT
+ # Save to file for artifact upload
+ echo "$output" > triage-output.txt
env:
- GITHUB_TOKEN: ${{ secrets.PAT }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COPILOT_GITHUB_TOKEN: ${{ secrets.PAT }}
- GH_TOKEN: ${{ secrets.PAT }}
-
-
- - name: Trigger Notification
- uses: ./.github/actions/notification
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ JAVATOOLING_INDEX_URL: ${{ secrets.JAVATOOLING_INDEX_URL }}
+ MAILING_URL: ${{ secrets.MAILING_URL }}
+
+ - name: Upload triage output
+ uses: actions/upload-artifact@v4
with:
- url: ${{ secrets.NOTIFICATION_URL }}
- payload: ${{ steps.issuelens.outputs.payload }}
+ name: triage-output
+ path: triage-output.txt
+ retention-days: 30