Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cecd02e
ci(windsurf): init and new-branch workflows updates
marc-romu Jul 19, 2025
6e313c7
feat(chat): enhance chat greeting with AI-generated context-aware mes…
marc-romu Jul 19, 2025
183bbac
ci(windsurf): stop new-branch at the end
marc-romu Jul 20, 2025
d738714
feat(chat): loading greeting message with new feature to remove messa…
marc-romu Jul 20, 2025
d773020
feat(chat): formatted loading message automatically used when finish …
marc-romu Jul 20, 2025
73dbdf6
feat: use default provider if none is specified in aiutils.getresponse
marc-romu Jul 20, 2025
b5bfce3
refactor(chat): use default model for greeting generation
marc-romu Jul 20, 2025
3ca2348
refactor(chat): improved greeting generation prompt
marc-romu Jul 20, 2025
1641402
fix(componentbase): fix incorrect model handling
marc-romu Jul 20, 2025
a79f442
Merge branch 'dev' into feature/0.4.0-chat-greeting
marc-romu Jul 20, 2025
1340d91
refactor: omit unnecessary awaition
marc-romu Jul 20, 2025
9842558
refactor: avoid possible null provider
marc-romu Jul 20, 2025
036e5e3
fix: potential injection in js
marc-romu Jul 20, 2025
81e7cc5
refactor: removed timeout 30s in greeting generation since it is not …
marc-romu Jul 20, 2025
1753ac0
Merge branch 'dev' into feature/0.4.0-chat-greeting
marc-romu Jul 20, 2025
2adb4ae
feat(chat): enhance chat greeting (#255)
marc-romu Jul 20, 2025
8d0f7c7
ci(tests): fix failing signature tests on non-windows
marc-romu Jul 20, 2025
1176f37
ci(windsurf): improved new-branch workflow logic
marc-romu Jul 20, 2025
8d6ce71
ci(github): new milestone-management workflow to move open issues and…
marc-romu Jul 20, 2025
1e0c382
ci: add milestone to release pr
marc-romu Jul 20, 2025
3afa615
docs(changelog)
marc-romu Jul 20, 2025
b48e573
ci(github): new pr-milestone workflow to automatically assign pr to m…
marc-romu Jul 20, 2025
f8e2579
fix(github): minor bugs in workflows
marc-romu Jul 20, 2025
92a996c
Update src/SmartHopper.Infrastructure.Tests/ProviderManagerSignatureT…
marc-romu Jul 20, 2025
38e137e
Update .github/workflows/milestone-management.yml
marc-romu Jul 20, 2025
46d1fdc
Update .github/workflows/pr-milestone.yml
marc-romu Jul 20, 2025
273afe1
feat(ci): add milestone management workflow and update release proces…
marc-romu Jul 20, 2025
489a1b8
ci(labels): added component base and ai-text-list-generate labels for…
marc-romu Jul 22, 2025
58a199f
fix(airetrievecomponents): use the correct tool name
marc-romu Jul 22, 2025
eabfc7b
fix(openai): json wrapper to prevent incorrect json schemas to api
marc-romu Jul 22, 2025
f374b40
fix(deepseek): json cleaner to extract data from malformed responses …
marc-romu Jul 22, 2025
1cfc099
feat(ai-tools): Strip reasoning tags from AI responses before processing
marc-romu Jul 22, 2025
a782caa
Update src/SmartHopper.Providers.OpenAI/OpenAIProvider.cs
marc-romu Jul 22, 2025
5dae04f
fix(aitools): correct OpenAI integration in text-list-generation and …
marc-romu Jul 22, 2025
c0c8fcc
chore: prepare release 0.4.0-alpha with version update and code style…
actions-user Jul 22, 2025
5f4bbd9
Update CHANGELOG.md
marc-romu Jul 22, 2025
429549e
chore: prepare release 0.4.0-alpha with version update and code style…
marc-romu Jul 22, 2025
6c7f1ae
docs
marc-romu Jul 22, 2025
0c4dc7e
docs
marc-romu Jul 22, 2025
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
6 changes: 6 additions & 0 deletions .github/labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
- name: "component: AI TextGenerate"
color: "000"
description: "Issues related to the AI Text Generate component"
- name: "component: AI TextListGenerate"
color: "000"
description: "Issues related to the AI Text List Generate component"
- name: "component: AI ScriptReview"
color: "000"
description: "Issues related to the AI Script Review component"
Expand Down Expand Up @@ -141,3 +144,6 @@
- name: "scope: Toolbar menu"
color: "000"
description: "Issues related to the Toolbar menu"
- name: "scope: Component Base"
color: "000"
description: "Issues related to the Component Base"
200 changes: 200 additions & 0 deletions .github/workflows/milestone-management.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
name: move-open-issues-and-pr-to-next-milestone

# Milestone Management Workflow
# Automatically moves open issues and PRs from closed milestones to the next appropriate milestone

on:
milestone:
types: [closed]

permissions:
issues: write
pull-requests: write
contents: read

jobs:
move-open-items:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Move open issues and PRs to next milestone
uses: actions/github-script@v7
with:
script: |
// Parse semantic version from milestone title
function parseVersion(versionStr) {
const match = versionStr.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
if (!match) return null;

return {
major: parseInt(match[1]),
minor: parseInt(match[2]),
patch: parseInt(match[3]),
prerelease: match[4] || null,
original: versionStr
};
}

// Compare versions to determine next MINOR or PATCH
function getNextVersions(closedVersion) {
const nextMinor = {
major: closedVersion.major,
minor: closedVersion.minor + 1,
patch: 0,
prerelease: 'alpha'
};

const nextPatch = {
major: closedVersion.major,
minor: closedVersion.minor,
patch: closedVersion.patch + 1,
prerelease: closedVersion.prerelease
};

return { nextMinor, nextPatch };
}

// Format version object back to string
function formatVersion(version) {
let versionStr = `${version.major}.${version.minor}.${version.patch}`;
if (version.prerelease) {
versionStr += `-${version.prerelease}`;
}
return versionStr;
}

// Find milestone by title
async function findMilestone(title) {
const milestones = await github.rest.issues.listMilestones({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open'
});

return milestones.data.find(m => m.title === title);
}

// Create new milestone
async function createMilestone(title, description) {
const response = await github.rest.issues.createMilestone({
owner: context.repo.owner,
repo: context.repo.repo,
title: title,
description: description || `Auto-created milestone for version ${title}`
});

console.log(`Created new milestone: ${title}`);
return response.data;
}

// Get open issues and PRs for a milestone
async function getOpenItemsInMilestone(milestoneNumber) {
const [issues, pulls] = await Promise.all([
github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
milestone: milestoneNumber,
state: 'open'
}),
github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open'
})
]);

// Filter PRs that belong to the milestone
const prsInMilestone = pulls.data.filter(pr =>
pr.milestone && pr.milestone.number === milestoneNumber
);

return {
issues: issues.data.filter(issue => !issue.pull_request), // Exclude PRs from issues
prs: prsInMilestone
};
}

// Move item to new milestone
async function moveItemToMilestone(itemNumber, newMilestoneNumber) {
try {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: itemNumber,
milestone: newMilestoneNumber
});
console.log(`Successfully moved item #${itemNumber} to milestone #${newMilestoneNumber}`);
} catch (error) {
console.error(`Failed to move item #${itemNumber} to milestone #${newMilestoneNumber}:`, error.message);
// Optionally rethrow the error or handle it gracefully
}
}

// Main logic
const closedMilestone = context.payload.milestone;
console.log(`Processing closed milestone: ${closedMilestone.title}`);

// Parse the closed milestone version
const closedVersion = parseVersion(closedMilestone.title);
if (!closedVersion) {
console.log('Milestone title is not a valid semantic version, skipping.');
return;
}

console.log(`Parsed closed version: ${JSON.stringify(closedVersion)}`);

// Get open items in the closed milestone
const openItems = await getOpenItemsInMilestone(closedMilestone.number);
const totalItems = openItems.issues.length + openItems.prs.length;

console.log(`Found ${openItems.issues.length} open issues and ${openItems.prs.length} open PRs in milestone`);

if (totalItems === 0) {
console.log('No open items to move, exiting.');
return;
}

// Determine next versions
const { nextMinor, nextPatch } = getNextVersions(closedVersion);
const nextMinorTitle = formatVersion(nextMinor);
const nextPatchTitle = formatVersion(nextPatch);

console.log(`Looking for next milestones: MINOR=${nextMinorTitle}, PATCH=${nextPatchTitle}`);

// Try to find next MINOR milestone first
let targetMilestone = await findMilestone(nextMinorTitle);
let milestoneType = 'MINOR';

if (!targetMilestone) {
// Try to find next PATCH milestone
targetMilestone = await findMilestone(nextPatchTitle);
milestoneType = 'PATCH';

if (!targetMilestone) {
// Create new MINOR milestone
targetMilestone = await createMilestone(nextMinorTitle);
milestoneType = 'MINOR (created)';
}
}

console.log(`Target milestone: ${targetMilestone.title} (${milestoneType})`);

// Move all open issues and PRs to the target milestone
const movePromises = [];

for (const issue of openItems.issues) {
console.log(`Moving issue #${issue.number}: ${issue.title}`);
movePromises.push(moveItemToMilestone(issue.number, targetMilestone.number));
}

for (const pr of openItems.prs) {
console.log(`Moving PR #${pr.number}: ${pr.title}`);
movePromises.push(moveItemToMilestone(pr.number, targetMilestone.number));
}

await Promise.all(movePromises);

console.log(`Successfully moved ${totalItems} items to milestone "${targetMilestone.title}"`);
115 changes: 115 additions & 0 deletions .github/workflows/pr-milestone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: pr-milestone

# PR Milestone Assignment Workflow
# Automatically assigns PRs to milestones based on version in Solution.props

on:
pull_request:
types: [opened]

permissions:
issues: write
pull-requests: write
contents: read

jobs:
assign-pr-to-milestone:
runs-on: ubuntu-latest

steps:
- name: Checkout PR source branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Read version from Solution.props and assign to milestone
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');

// Read Solution.props file
const solutionPropsPath = 'Solution.props';

if (!fs.existsSync(solutionPropsPath)) {
console.log('Solution.props file not found');
return;
}

const content = fs.readFileSync(solutionPropsPath, 'utf8');
console.log('Solution.props content:', content);

// Extract version from Solution.props
const versionMatch = content.match(/<SolutionVersion>(.*?)<\/SolutionVersion>/);
if (!versionMatch) {
console.log('Could not find SolutionVersion in Solution.props');
return;
}

const fullVersion = versionMatch[1];
console.log('Found full version:', fullVersion);

// Parse and process version
// The following logic processes the version string to make it suitable for milestone assignment:
// - Build numbers (e.g., ".250720") are removed because they are not relevant for milestone assignment.
// - The suffix "-dev" is replaced with "-alpha" because there are no milestones for development versions,
// and development versions are treated as alpha releases.
// Examples: "0.4.0-dev.250720" -> "0.4.0-alpha"
// "0.4.1-alpha" -> "0.4.1-alpha"
// "0.4.2-beta.250123" -> "0.4.2-beta"

// Remove everything after the last dot (suppress build number)
let processedVersion = fullVersion;
const lastDotIndex = processedVersion.lastIndexOf('.');
if (lastDotIndex > processedVersion.indexOf('-')) {
// Only remove if the dot is after the dash (part of build number)
processedVersion = processedVersion.substring(0, lastDotIndex);
}

// Replace -dev with -alpha (there are no dev milestones)
processedVersion = processedVersion.replace('-dev', '-alpha');

console.log('Processed version for milestone:', processedVersion);

// Find milestone with matching title
const { data: milestones } = await github.rest.issues.listMilestones({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all' // Include both open and closed milestones
});

const targetMilestone = milestones.find(milestone => milestone.title === processedVersion);

if (!targetMilestone) {
console.log(`No milestone found with title: ${processedVersion}`);
console.log('Available milestones:', milestones.map(m => m.title));
return;
}

console.log(`Found milestone: ${targetMilestone.title} (${targetMilestone.state})`);

// Assign PR to milestone
try {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
milestone: targetMilestone.number
});

console.log(`Successfully assigned PR #${context.payload.pull_request.number} to milestone "${targetMilestone.title}"`);

// Add a comment to the PR
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: `🏷️ This PR has been automatically assigned to milestone **${targetMilestone.title}** based on the version in \`Solution.props\`.`
});

} catch (error) {
console.error('Error assigning PR to milestone:', error);
core.setFailed(`Failed to assign PR to milestone: ${error.message}`);
}
3 changes: 2 additions & 1 deletion .github/workflows/release-1-milestone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ jobs:
git push origin release/${{ github.event.milestone.title }}

- name: Create Pull Request
id: create-pr
run: |
gh pr create \
--base dev \
--head release/${{ github.event.milestone.title }} \
--title "chore: prepare release ${{ github.event.milestone.title }} with version update and code style fixes" \
--body $'This PR prepares the release for version ${{ github.event.milestone.title }} with version update and code style fixes:\n\n- Fixed header code style\n- Sorted usings\n- Removed trailing whitespace\n- Updated version in Solution.props\n- Updated changelog with closed-solved issues\n- Updated README badges\n\nMILESTONE DESCRIPTION:\n${{ github.event.milestone.description }}'
--body $'This PR prepares the release for version ${{ github.event.milestone.title }} with version update and code style fixes:\n\n- Updated version in Solution.props\n- Updated changelog with closed-solved issues\n- Updated README badges'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12 changes: 8 additions & 4 deletions .windsurf/workflows/init.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
---
description: Initialize today's work session
description: Initialize work session
---

1. Update dev date to today in Solution.props. It must follow X.X.X-dev.YYMMDD format. If it currently is not a -dev version, increment the patch number and add the -dev.YYMMDD part. Examples:
1. Check if the current branch name has a X.Y.Z version indicator. If so, use this version in the following steps.

2. Update dev date to today in Solution.props. It must follow X.Y.Z-dev.YYMMDD format. If it currently is not a -dev version, increment the patch number or use the branch's version, and add the -dev.YYMMDD part. Examples:
- 0.1.0-beta -> 0.1.1-dev.YYMMDD
- 0.1.0-dev -> 0.1.0-dev.YYMMDD
- 0.1.0 -> 0.1.1-dev.YYMMDD
- 0.1.0-dev.250101-> 0.1.0-dev.YYMMDD

2. Update the version badge in README.md. Follow the logic in .github/actions/update-badges/action.yml.
3. Update the version badge in README.md. Follow the logic in .github/actions/update-badges/action.yml. Update also the color accordingly, specified in the update-badges action.

4. Update the status badge in README.md, according to the version, following the instructions in the update-badges action.

3. Ensure the top section in CHANGELOG.md is [Unreleased].
5. Ensure the top section in CHANGELOG.md is [Unreleased].
Loading
Loading