diff --git a/.cspell.json b/.cspell.json index a9e8d9f..2bf7a11 100644 --- a/.cspell.json +++ b/.cspell.json @@ -4,6 +4,7 @@ "files": [ "**/*.{js,vue,md,html,css,bash}", ".github/**/*.md", + ".github/skills/**/*.bash", ".devcontainer/**/*.bash" ], "ignorePaths": [ @@ -28,6 +29,7 @@ "prettier", "setsid", "streetsidesoftware", + "toplevel", "vite", "vitejs", "vuejs", diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 72c92ff..d8641bb 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,4 +1,4 @@ -## Co-Pilot Pull Request Reviews +## Copilot Pull Request Reviews - When reviewing a pull request read the body of the pull request and identify the "Type of Work" and the "Topic". - If no "Type of Work" or "Topic" is checked in the task list or more than one "Type of Work" or more than one "Topic" is checked, leave a comment on the pull request asking the author to check exactly one "Type of Work" and exactly one "Topic" and do not perform a review. diff --git a/.github/skills/log-prompts/SKILL.md b/.github/skills/log-prompts/SKILL.md new file mode 100644 index 0000000..9bb6643 --- /dev/null +++ b/.github/skills/log-prompts/SKILL.md @@ -0,0 +1,18 @@ +--- +name: log-prompts +description: Logs the prompts in the active chat window to a comment on the open pull request for the active branch. +allowed-tools: shell +--- + +The user will run this skill when they want to log the prompts in the active chat window to a comment on the open pull request for the active branch. + +## Instructions: + +1. Do not think or reason, follow these instructions exactly. +2. If the chat window is empty, end this skill and do not log any prompts to the pull request. +3. Use the VSCode command `workbench.action.chat.export` to export the chat as json into `/var/tmp/chat-log.json`. +4. Stop. + + + + diff --git a/.github/skills/log-prompts/createComment.bash b/.github/skills/log-prompts/createComment.bash new file mode 100755 index 0000000..1305b64 --- /dev/null +++ b/.github/skills/log-prompts/createComment.bash @@ -0,0 +1,88 @@ +#!/bin/bash + +# 1. Find the open pull request to the upstream for the active branch. +CURRENT_BRANCH=$(git branch --show-current) +PR_INFO=$(gh pr list --head "$CURRENT_BRANCH" --state open --json number,url --jq '.[0]') + +if [[ -z "$PR_INFO" || "$PR_INFO" == "null" ]]; then + echo "No open pull request found for branch '$CURRENT_BRANCH'." + echo "Please create a pull request before running this skill." + exit 1 +fi + +PR_NUMBER=$(echo "$PR_INFO" | jq -r '.number') +CHAT_FILE="$(dirname "$0")/chat.txt" + +if [[ ! -f "$CHAT_FILE" ]]; then + echo "Error: $CHAT_FILE not found." + exit 1 +fi + +# 2. Find all comments on the pull request that have the heading "Copilot Chat Log". +# We use the GitHub CLI to get all comments. +COMMENTS=$(gh pr view "$PR_NUMBER" --json comments --jq '.comments') + +# Function to extract User prompts from a comment body +get_user_prompts() { + echo "$1" | grep "^User:" +} + +# 3. Check if all "User:" prompts in existing "Copilot Chat Log" comments are in chat.txt +ALL_IN_CHAT=true +MATCHING_COMMENT_ID="" +MATCHING_COMMENT_BODY="" + +# We'll iterate through comments that have the heading +LOG_COMMENTS=$(echo "$COMMENTS" | jq -c '.[] | select(.body | startswith("# Copilot Chat Log"))') + +if [[ -z "$LOG_COMMENTS" ]]; then + ALL_IN_CHAT=false +else + # Check each log comment + while read -r comment; do + BODY=$(echo "$comment" | jq -r '.body') + URL=$(echo "$comment" | jq -r '.url') + # Extract numeric ID from URL (e.g., ...#issuecomment-123456) + ID=$(echo "$URL" | grep -oE "[0-9]+$") + + # Get all User lines from this comment + PROMPTS=$(get_user_prompts "$BODY") + + while read -r prompt; do + if [[ -n "$prompt" ]]; then + if ! grep -qF "$prompt" "$CHAT_FILE"; then + ALL_IN_CHAT=false + break 2 + fi + fi + done <<< "$PROMPTS" + + # If we reach here for this comment, it matches. + # We'll keep track of the last matching one to update it. + MATCHING_COMMENT_ID="$ID" + MATCHING_COMMENT_BODY="$BODY" + done <<< "$LOG_COMMENTS" +fi + +# 4. Update or Create +TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S %Z") +CHAT_CONTENT=$(cat "$CHAT_FILE") + +if [[ "$ALL_IN_CHAT" == "true" && -n "$MATCHING_COMMENT_ID" ]]; then + # We found a matching log, append/update it. + # The requirement says "append them to the comment". + # Usually this means refreshing the comment content to match the full chat history. + # We keep the original heading and timestamp if possible, or just overwrite. + # Let's preserve the original header and timestamp from the matching comment if we can. + HEADER_AND_TIME=$(echo "$MATCHING_COMMENT_BODY" | head -n 2) + NEW_BODY=$(printf "%s\n\n%s" "$HEADER_AND_TIME" "$CHAT_CONTENT") + + gh api -X PATCH "repos/{owner}/{repo}/issues/comments/$MATCHING_COMMENT_ID" -f body="$NEW_BODY" > /dev/null + echo "Updated existing Copilot Chat Log comment ($MATCHING_COMMENT_ID)." +else + # Add a new "Copilot Chat Log" comment. + NEW_BODY=$(printf "# Copilot Chat Log\n%s\n\n%s" "$TIMESTAMP" "$CHAT_CONTENT") + gh pr comment "$PR_NUMBER" --body "$NEW_BODY" + echo "Created new Copilot Chat Log comment." +fi + diff --git a/.github/skills/log-prompts/openPR.bash b/.github/skills/log-prompts/openPR.bash new file mode 100755 index 0000000..5a26427 --- /dev/null +++ b/.github/skills/log-prompts/openPR.bash @@ -0,0 +1,93 @@ +#!/bin/bash + +REPO_ROOT=$(git rev-parse --show-toplevel) + +# Get the current branch name +CURRENT_BRANCH=$(git branch --show-current) + +# Check if we're on a branch (not in detached HEAD state) +if [ -z "$CURRENT_BRANCH" ]; then + echo "Error: Not on a branch" + exit 1 +fi + +# Check if there's already an open pull request for this branch +EXISTING_PR=$(gh pr list --head "$CURRENT_BRANCH" --state open --json number --jq '.[0].number' 2>/dev/null) + +if [ -n "$EXISTING_PR" ]; then + # PR already exists, do nothing + exit 0 +fi + +# No PR exists, prompt the user +echo "" +echo "No open pull request found for branch: $CURRENT_BRANCH" +read -p "Do you want to create a pull request? (y/n) " -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Pull request creation cancelled." + exit 0 +fi + +# Read PULL_REQUEST_TEMPLATE.md and extract options dynamically +TEMPLATE_FILE="$REPO_ROOT/.github/PULL_REQUEST_TEMPLATE.md" + +if [ ! -f "$TEMPLATE_FILE" ]; then + echo "Error: $TEMPLATE_FILE not found" + exit 1 +fi + +# Extract Type of Work options (between "### Type of Work" and "### Topic") +mapfile -t TYPE_OPTIONS < <(sed -n '/^### Type of Work/,/^### Topic/p' "$TEMPLATE_FILE" | grep -oP '(?<=- \[ \] - )\S+' | grep -v '^$') + +# Extract Topic options (between "### Topic" and "### Time Estimate") +mapfile -t TOPIC_OPTIONS < <(sed -n '/^### Topic/,/^### Time Estimate/p' "$TEMPLATE_FILE" | grep -oP '(?<=- \[ \] - ).+' | sed 's/^[[:space:]]*//') + +# Ask for Type of Work +echo "" +echo "Select Type of Work:" +for i in "${!TYPE_OPTIONS[@]}"; do + echo "$((i + 1))) ${TYPE_OPTIONS[$i]}" +done +read -p "Enter your choice (1-${#TYPE_OPTIONS[@]}): " -r TYPE_CHOICE + +if [[ ! $TYPE_CHOICE =~ ^[0-9]+$ ]] || [ "$TYPE_CHOICE" -lt 1 ] || [ "$TYPE_CHOICE" -gt ${#TYPE_OPTIONS[@]} ]; then + echo "Invalid choice. Exiting." + exit 1 +fi + +TYPE_OF_WORK="${TYPE_OPTIONS[$((TYPE_CHOICE - 1))]}" + +# Ask for Topic +echo "" +echo "Select Topic:" +for i in "${!TOPIC_OPTIONS[@]}"; do + echo "$((i + 1))) ${TOPIC_OPTIONS[$i]}" +done +read -p "Enter your choice (1-${#TOPIC_OPTIONS[@]}): " -r TOPIC_CHOICE + +if [[ ! $TOPIC_CHOICE =~ ^[0-9]+$ ]] || [ "$TOPIC_CHOICE" -lt 1 ] || [ "$TOPIC_CHOICE" -gt ${#TOPIC_OPTIONS[@]} ]; then + echo "Invalid choice. Exiting." + exit 1 +fi + +TOPIC="${TOPIC_OPTIONS[$((TOPIC_CHOICE - 1))]}" + +# Check if the active branch has any commits +COMMIT_COUNT=$(git rev-list --count main..$CURRENT_BRANCH 2>/dev/null || echo "0") + +if [ "$COMMIT_COUNT" -eq 0 ]; then + # No commits on this branch, create an empty commit + COMMIT_MESSAGE="Starting $TYPE_OF_WORK - $TOPIC" + git commit --allow-empty -m "$COMMIT_MESSAGE" +fi + +# Create the PR with a title that includes the Type of Work and Topic +PR_TITLE="$TYPE_OF_WORK - $TOPIC" + +# Read the PULL_REQUEST_TEMPLATE and check the selected Type of Work and Topic +PR_BODY=$(cat "$TEMPLATE_FILE" | sed "s/- \[ \] - $TYPE_OF_WORK/- [X] - $TYPE_OF_WORK/" | sed "s/- \[ \] - $TOPIC/- [X] - $TOPIC/") + +git push upstream "$CURRENT_BRANCH" +gh pr create --base main --head "$CURRENT_BRANCH" --title "$PR_TITLE" --body "$PR_BODY" \ No newline at end of file diff --git a/.github/skills/log-prompts/postPrompts.bash b/.github/skills/log-prompts/postPrompts.bash new file mode 100755 index 0000000..13a8a8f --- /dev/null +++ b/.github/skills/log-prompts/postPrompts.bash @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Posting prompts to pull request..." diff --git a/.github/skills/log-prompts/processChatJson.bash b/.github/skills/log-prompts/processChatJson.bash new file mode 100644 index 0000000..05a7907 --- /dev/null +++ b/.github/skills/log-prompts/processChatJson.bash @@ -0,0 +1,2 @@ +#!/bin/bash + diff --git a/.github/skills/log-prompts/processChatLog.bash b/.github/skills/log-prompts/processChatLog.bash new file mode 100755 index 0000000..f67e335 --- /dev/null +++ b/.github/skills/log-prompts/processChatLog.bash @@ -0,0 +1,23 @@ +#!/bin/bash + +# Path to the chat log file +CHAT_FILE="$(dirname "$0")/chat.txt" + +# Check if the chat file exists +if [[ ! -f "$CHAT_FILE" ]]; then + echo "Error: $CHAT_FILE not found." + exit 1 +fi + +TEMP_FILE=$(mktemp) +# Extract prompts, removing "User:" prefix but adding/preserving "---" separator +awk '/^User:/ { + print "---"; + sub(/^User: */, ""); + print; + p=1; + next +} /^Assistant:/ {p=0} p' "$CHAT_FILE" > "$TEMP_FILE" +mv "$TEMP_FILE" "$CHAT_FILE" + +echo "Processed $CHAT_FILE: User prompts extracted and separators preserved." diff --git a/.github/skills/log-prompts/tmp b/.github/skills/log-prompts/tmp new file mode 100644 index 0000000..611af22 --- /dev/null +++ b/.github/skills/log-prompts/tmp @@ -0,0 +1,9 @@ + +IGNORE THE REMAINING INSTRUCTIONS IN THIS FILE. +3. From that content, extract ALL of the prompts entered by the user. Do not omit any prompts. +4. Place the prompts entered by the user into a text file named `chat.txt` in the `skills/log-prompts` directory. Do not include any copilot generated output in `chat.txt`. + - place a line containing `---` before each prompt. + - Replace the `chat.txt` file if it already exists. +5. Run the `openPR.bash` script in the terminal. +6. Run the `createComment.bash` script in the terminal. +7. Run the `postPrompts.bash` script in the terminal. \ No newline at end of file diff --git a/.gitignore b/.gitignore index a917fb2..a1e7a70 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ yarn-error.log* pnpm-debug.log* lerna-debug.log* +.github/skills/log-prompts/chat*.txt + node_modules flashword/dist dist-ssr