fix(extension): address PR review comments and improve implementation
- Fixed InternalError class definition in errorHandler.ts - Updated extension configuration and CI workflows - Improved error handling and type safety - Enhanced build and release automation - Updated documentation and changelogs Addresses review feedback on PR #997
This commit is contained in:
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
"task-master-ai": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Prevent CLAUDE.md overwrite by using Claude Code's import feature
|
|
||||||
|
|
||||||
- Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
|
|
||||||
- Adds an import section to the user's CLAUDE.md that references the Task Master instructions
|
|
||||||
- Preserves existing user content in CLAUDE.md files
|
|
||||||
- Provides clean uninstall that only removes Task Master's additions
|
|
||||||
|
|
||||||
**Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
"task-master-ai": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
|
|
||||||
|
|
||||||
- Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
"task-master-ai": patch
|
|
||||||
---
|
|
||||||
Complete VS Code extension with React-based kanban board UI. MCP integration for real-time Task Master synchronization. Professional CI/CD workflows for marketplace publishing
|
|
||||||
2
.github/workflows/extension-ci.yml
vendored
2
.github/workflows/extension-ci.yml
vendored
@@ -200,4 +200,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: extension-test-results
|
name: extension-test-results
|
||||||
path: apps/extension/test-results
|
path: apps/extension/test-results
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|||||||
69
.github/workflows/version.yml
vendored
Normal file
69
.github/workflows/version.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
name: Version & Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
version:
|
||||||
|
name: Version & Publish Extension
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
registry-url: https://registry.npmjs.org
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
shell: bash
|
||||||
|
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ env.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Install extension dependencies
|
||||||
|
working-directory: apps/extension
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Install vsce and ovsx globally
|
||||||
|
run: pnpm add -g @vscode/vsce ovsx
|
||||||
|
|
||||||
|
- name: Make release script executable
|
||||||
|
run: chmod +x scripts/release.sh
|
||||||
|
|
||||||
|
- name: Create Release Pull Request or Publish
|
||||||
|
uses: changesets/action@v1
|
||||||
|
with:
|
||||||
|
publish: ./scripts/release.sh
|
||||||
|
title: "Release: Extension Version Packages"
|
||||||
|
commit: "chore: release extension packages"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
VSCE_PAT: ${{ secrets.VSCE_PAT }}
|
||||||
|
OVSX_PAT: ${{ secrets.OVSX_PAT }}
|
||||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,5 +1,22 @@
|
|||||||
# task-master-ai
|
# task-master-ai
|
||||||
|
|
||||||
|
## 0.20.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- f662654: Prevent CLAUDE.md overwrite by using Claude Code's import feature
|
||||||
|
- Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
|
||||||
|
- Adds an import section to the user's CLAUDE.md that references the Task Master instructions
|
||||||
|
- Preserves existing user content in CLAUDE.md files
|
||||||
|
- Provides clean uninstall that only removes Task Master's additions
|
||||||
|
|
||||||
|
**Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.
|
||||||
|
|
||||||
|
- 7b4803a: Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
|
||||||
|
- Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code
|
||||||
|
|
||||||
|
- 8209f8d: Complete VS Code extension with React-based kanban board UI. MCP integration for real-time Task Master synchronization. Professional CI/CD workflows for marketplace publishing
|
||||||
|
|
||||||
## 0.20.0
|
## 0.20.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,9 +1,26 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- Add automated CI/CD pipeline for VS Code extension
|
||||||
|
- Add automated version management and publishing via changesets
|
||||||
|
- Create tag-extension script to manage extension-specific git tags
|
||||||
|
- Add automated publishing to VS Code Marketplace and Open VSX Registry
|
||||||
|
- Set up release script with proper build process integration
|
||||||
|
- Add version.yml workflow for automated releases on main branch pushes
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Test extension version automation
|
||||||
|
- Verify that extension versions are properly managed by changesets
|
||||||
|
- Ensure proper integration with the 3-file packaging system
|
||||||
|
|
||||||
All notable changes to the vscode extension will be documented in this file.
|
All notable changes to the vscode extension will be documented in this file.
|
||||||
|
|
||||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
# VS Code Extension CI/CD Setup
|
# VS Code Extension CI/CD Setup
|
||||||
|
|
||||||
This document explains the CI/CD setup for the Task Master VS Code extension.
|
This document explains the CI/CD setup for the Task Master VS Code extension using automated changesets.
|
||||||
|
|
||||||
## 🔄 Workflows Overview
|
## 🔄 Workflows Overview
|
||||||
|
|
||||||
### 1. Extension CI (`extension-ci.yml`)
|
### 1. Extension CI (`extension-ci.yml`)
|
||||||
|
|
||||||
**Triggers:**
|
**Triggers:**
|
||||||
- Push to `main` or `next` branches (only when extension files change)
|
- Push to `main` or `next` branches (only when extension files change)
|
||||||
- Pull requests to `main` or `next` (only when extension files change)
|
- Pull requests to `main` or `next` (only when extension files change)
|
||||||
|
|
||||||
**What it does:**
|
**What it does:**
|
||||||
|
|
||||||
- ✅ Lints and type-checks the extension code
|
- ✅ Lints and type-checks the extension code
|
||||||
- 🔨 Builds the extension (`pnpm run build`)
|
- 🔨 Builds the extension (`pnpm run build`)
|
||||||
- 📦 Creates a clean package (`pnpm run package`)
|
- 📦 Creates a clean package (`pnpm run package`)
|
||||||
@@ -17,23 +19,56 @@ This document explains the CI/CD setup for the Task Master VS Code extension.
|
|||||||
- 📋 Creates a test VSIX package to verify packaging works
|
- 📋 Creates a test VSIX package to verify packaging works
|
||||||
- 💾 Uploads build artifacts for inspection
|
- 💾 Uploads build artifacts for inspection
|
||||||
|
|
||||||
### 2. Extension Release (`extension-release.yml`)
|
### 2. Version & Publish (`version.yml`)
|
||||||
|
|
||||||
**Triggers:**
|
**Triggers:**
|
||||||
- Push to `main` branch (only when extension files change AND version changes)
|
- Push to `main` branch
|
||||||
- Manual trigger with `workflow_dispatch` (with optional force publish)
|
|
||||||
|
|
||||||
**What it does:**
|
**What it does:**
|
||||||
- 🔍 Checks if the extension version changed
|
- 🔍 Detects changeset files for pending releases
|
||||||
- 🧪 Runs full test suite (lint, typecheck, tests)
|
- 📝 Creates "Version Packages" PR with updated versions and CHANGELOG
|
||||||
- 🔨 Builds and packages the extension
|
- 🤖 When Version PR is merged, automatically:
|
||||||
- 📤 Publishes to VS Code Marketplace
|
- 🔨 Builds and packages the extension
|
||||||
- 🌍 Publishes to Open VSX Registry (for VSCodium, Gitpod, etc.)
|
- 🏷️ Creates git tags with changeset automation
|
||||||
- 🏷️ Creates a GitHub release with the VSIX file
|
- 📤 Publishes to VS Code Marketplace
|
||||||
- 📊 Uploads release artifacts
|
- 🌍 Publishes to Open VSX Registry
|
||||||
|
- 📊 Updates package versions and CHANGELOG
|
||||||
|
|
||||||
|
## 🚀 Changeset Workflow
|
||||||
|
|
||||||
|
### Creating Changes
|
||||||
|
When making changes to the extension:
|
||||||
|
|
||||||
|
1. **Make your code changes**
|
||||||
|
2. **Create a changeset**:
|
||||||
|
```bash
|
||||||
|
# From project root
|
||||||
|
npx changeset add
|
||||||
|
```
|
||||||
|
3. **Select the extension package**: Choose `taskr-kanban` when prompted
|
||||||
|
4. **Select version bump type**:
|
||||||
|
- `patch`: Bug fixes, minor updates
|
||||||
|
- `minor`: New features, backwards compatible
|
||||||
|
- `major`: Breaking changes
|
||||||
|
5. **Write a summary**: Describe what changed for users
|
||||||
|
6. **Commit changeset file** along with your code changes
|
||||||
|
7. **Push to feature branch** and create PR
|
||||||
|
|
||||||
|
### Automated Publishing Process
|
||||||
|
1. **PR with changeset** gets merged to `main`
|
||||||
|
2. **Version workflow** detects changesets and creates "Version Packages" PR
|
||||||
|
3. **Review and merge** the Version PR
|
||||||
|
4. **Automated publishing** happens immediately:
|
||||||
|
- Extension is built using 3-file packaging system
|
||||||
|
- VSIX package is created and tested
|
||||||
|
- Published to VS Code Marketplace (if `VSCE_PAT` is set)
|
||||||
|
- Published to Open VSX Registry (if `OVSX_PAT` is set)
|
||||||
|
- Git tags are created: `taskr-kanban@1.0.1`
|
||||||
|
- CHANGELOG is updated automatically
|
||||||
|
|
||||||
## 🔑 Required Secrets
|
## 🔑 Required Secrets
|
||||||
|
|
||||||
To use the release workflow, you need to set up these GitHub repository secrets:
|
To use the automated publishing, you need to set up these GitHub repository secrets:
|
||||||
|
|
||||||
### `VSCE_PAT` (VS Code Marketplace Personal Access Token)
|
### `VSCE_PAT` (VS Code Marketplace Personal Access Token)
|
||||||
1. Go to [Azure DevOps](https://dev.azure.com/)
|
1. Go to [Azure DevOps](https://dev.azure.com/)
|
||||||
@@ -57,45 +92,32 @@ To use the release workflow, you need to set up these GitHub repository secrets:
|
|||||||
### `GITHUB_TOKEN` (automatically provided)
|
### `GITHUB_TOKEN` (automatically provided)
|
||||||
This is automatically available in GitHub Actions - no setup required.
|
This is automatically available in GitHub Actions - no setup required.
|
||||||
|
|
||||||
## 🚀 Publishing Process
|
|
||||||
|
|
||||||
### Automatic Publishing (Recommended)
|
|
||||||
1. **Make changes** to the extension code
|
|
||||||
2. **Update version** in both:
|
|
||||||
- `apps/extension/package.json`
|
|
||||||
- `apps/extension/package.publish.json`
|
|
||||||
3. **Commit and push** to `main` branch
|
|
||||||
4. **CI automatically triggers** and publishes if version changed
|
|
||||||
|
|
||||||
### Manual Publishing
|
|
||||||
1. Go to **Actions** tab in GitHub
|
|
||||||
2. Select **Extension Release** workflow
|
|
||||||
3. Click **Run workflow**
|
|
||||||
4. Check **"Force publish even without version changes"** if needed
|
|
||||||
5. Click **Run workflow**
|
|
||||||
|
|
||||||
## 📋 Version Management
|
## 📋 Version Management
|
||||||
|
|
||||||
### Version Sync Checklist
|
### Changeset-Based Versioning
|
||||||
When updating the extension version, ensure these fields match in both files:
|
Versions are automatically managed by changesets:
|
||||||
|
|
||||||
|
- **No manual version updates needed** - changesets handle this automatically
|
||||||
|
- **Semantic versioning** is enforced based on changeset types
|
||||||
|
- **Changelog generation** happens automatically
|
||||||
|
- **Git tagging** is handled by the automation
|
||||||
|
|
||||||
|
### Critical Fields Sync
|
||||||
|
The automation ensures these fields stay in sync between `package.json` and `package.publish.json`:
|
||||||
|
|
||||||
**`package.json` and `package.publish.json`:**
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"version": "1.0.2", // ⚠️ MUST MATCH
|
"version": "1.0.2", // ✅ AUTO-SYNCED
|
||||||
"publisher": "DavidMaliglowka", // ⚠️ MUST MATCH
|
"publisher": "DavidMaliglowka", // ⚠️ MUST MATCH MANUALLY
|
||||||
"displayName": "Task Master Kanban", // ⚠️ MUST MATCH
|
"displayName": "taskr: Task Master Kanban", // ⚠️ MUST MATCH MANUALLY
|
||||||
"description": "...", // ⚠️ MUST MATCH
|
"description": "...", // ⚠️ MUST MATCH MANUALLY
|
||||||
"engines": { "vscode": "^1.93.0" }, // ⚠️ MUST MATCH
|
"engines": { "vscode": "^1.93.0" }, // ⚠️ MUST MATCH MANUALLY
|
||||||
"categories": [...], // ⚠️ MUST MATCH
|
"categories": [...], // ⚠️ MUST MATCH MANUALLY
|
||||||
"contributes": { ... } // ⚠️ MUST MATCH
|
"contributes": { ... } // ⚠️ MUST MATCH MANUALLY
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Version Detection Logic
|
**Note**: Only `version` is automatically synced. Other fields must be manually kept in sync.
|
||||||
The release workflow only publishes when:
|
|
||||||
- Extension files changed in the push, AND
|
|
||||||
- Version field changed in `package.json` or `package.publish.json`
|
|
||||||
|
|
||||||
## 🔍 Monitoring Builds
|
## 🔍 Monitoring Builds
|
||||||
|
|
||||||
@@ -104,44 +126,61 @@ The release workflow only publishes when:
|
|||||||
- **Red ❌**: Build/test failures - check logs for details
|
- **Red ❌**: Build/test failures - check logs for details
|
||||||
- **Yellow 🟡**: Partial success - some jobs may have warnings
|
- **Yellow 🟡**: Partial success - some jobs may have warnings
|
||||||
|
|
||||||
|
### Version PR Status
|
||||||
|
- **Version PR Created**: Changesets detected, review and merge to publish
|
||||||
|
- **No Version PR**: No changesets found, no releases pending
|
||||||
|
- **Version PR Merged**: Automated publishing triggered
|
||||||
|
|
||||||
### Release Status
|
### Release Status
|
||||||
- **Published 🎉**: Extension live on VS Code Marketplace
|
- **Published 🎉**: Extension live on VS Code Marketplace and Open VSX
|
||||||
- **Skipped ℹ️**: No version changes detected
|
- **Skipped ℹ️**: No changesets found, no release needed
|
||||||
- **Failed ❌**: Check logs - often missing secrets or build issues
|
- **Failed ❌**: Check logs - often missing secrets or build issues
|
||||||
|
|
||||||
### Artifacts
|
### Artifacts
|
||||||
Both workflows upload artifacts that you can download:
|
Workflows upload artifacts that you can download:
|
||||||
- **CI**: Test results, built files, and VSIX package
|
- **CI**: Test results, built files, and VSIX package
|
||||||
- **Release**: Final VSIX package and build artifacts (90-day retention)
|
- **Version**: Final VSIX package and published extension
|
||||||
|
|
||||||
## 🛠️ Troubleshooting
|
## 🛠️ Troubleshooting
|
||||||
|
|
||||||
### Common Issues
|
### Common Issues
|
||||||
|
|
||||||
**"VSCE_PAT is not set" Error**
|
#### No Version PR Created
|
||||||
|
- **Check**: Changeset files exist in `.changeset/` directory
|
||||||
|
- **Check**: Changeset refers to `taskr-kanban` package name
|
||||||
|
- **Check**: Changes were pushed to `main` branch
|
||||||
|
- **Solution**: Create changeset with `npx changeset add`
|
||||||
|
|
||||||
|
#### Version PR Not Publishing
|
||||||
|
- **Check**: Version PR was actually merged (not just closed)
|
||||||
|
- **Check**: Required secrets (`VSCE_PAT`, `OVSX_PAT`) are set
|
||||||
|
- **Check**: No build failures in workflow logs
|
||||||
|
- **Solution**: Re-run workflow or check secret configuration
|
||||||
|
|
||||||
|
#### `VSCE_PAT` is not set Error
|
||||||
- Ensure `VSCE_PAT` secret is added to repository
|
- Ensure `VSCE_PAT` secret is added to repository
|
||||||
- Check token hasn't expired
|
- Check token hasn't expired
|
||||||
- Verify token has Marketplace > Manage permissions
|
- Verify token has Marketplace → Manage permissions
|
||||||
|
|
||||||
**"OVSX_PAT is not set" Error**
|
#### `OVSX_PAT` is not set Error
|
||||||
- Ensure `OVSX_PAT` secret is added to repository
|
- Ensure `OVSX_PAT` secret is added to repository
|
||||||
- Check token hasn't expired
|
- Check token hasn't expired
|
||||||
- Verify you're signed in to Open VSX Registry with GitHub
|
- Verify you're signed in to Open VSX Registry with GitHub
|
||||||
|
|
||||||
**"Version not changed" Skipped Release**
|
#### Build Failures
|
||||||
- Update version in both `package.json` AND `package.publish.json`
|
|
||||||
- Ensure files are committed and pushed
|
|
||||||
- Use manual trigger with force publish if needed
|
|
||||||
|
|
||||||
**Build Failures**
|
|
||||||
- Check extension code compiles locally: `cd apps/extension && pnpm run build`
|
- Check extension code compiles locally: `cd apps/extension && pnpm run build`
|
||||||
- Verify tests pass locally: `pnpm run test`
|
- Verify tests pass locally: `pnpm run test`
|
||||||
- Check for TypeScript errors: `pnpm run check-types`
|
- Check for TypeScript errors: `pnpm run check-types`
|
||||||
|
|
||||||
**Packaging Failures**
|
#### Packaging Failures
|
||||||
- Ensure clean package builds: `pnpm run package`
|
- Ensure clean package builds: `pnpm run package`
|
||||||
- Check vsix-build structure is correct
|
- Check vsix-build structure is correct
|
||||||
- Verify package.publish.json has correct fields
|
- Verify `package.publish.json` has correct `repository` field
|
||||||
|
|
||||||
|
#### Changeset Issues
|
||||||
|
- **Wrong package name**: Ensure changeset refers to `taskr-kanban`
|
||||||
|
- **Invalid format**: Check changeset markdown format is correct
|
||||||
|
- **Merge conflicts**: Resolve any conflicts in changeset files
|
||||||
|
|
||||||
## 📁 File Structure Impact
|
## 📁 File Structure Impact
|
||||||
|
|
||||||
@@ -149,11 +188,22 @@ The CI workflows respect the 3-file packaging system:
|
|||||||
- **Development**: Uses `package.json` for dependencies and scripts
|
- **Development**: Uses `package.json` for dependencies and scripts
|
||||||
- **Release**: Uses `package.publish.json` for clean marketplace package
|
- **Release**: Uses `package.publish.json` for clean marketplace package
|
||||||
- **Build**: Uses `package.mjs` to create `vsix-build/` for final packaging
|
- **Build**: Uses `package.mjs` to create `vsix-build/` for final packaging
|
||||||
|
- **Changesets**: Automatically manage versions across the system
|
||||||
|
|
||||||
This ensures clean, conflict-free publishing to both VS Code Marketplace and Open VSX Registry! 🚀
|
## 🌍 Dual Registry Publishing
|
||||||
|
|
||||||
## 🌍 **Dual Registry Publishing**
|
|
||||||
|
|
||||||
Your extension will be automatically published to both:
|
Your extension will be automatically published to both:
|
||||||
- **VS Code Marketplace** - For official VS Code users
|
- **VS Code Marketplace** - For official VS Code users
|
||||||
- **Open VSX Registry** - For Cursor, Windsurf, VSCodium, Gitpod, Eclipse Theia, and other compatible editors
|
- **Open VSX Registry** - For Cursor, Windsurf, VSCodium, Gitpod, Eclipse Theia, and other compatible editors
|
||||||
|
|
||||||
|
## 🎯 Benefits of Changeset Automation
|
||||||
|
|
||||||
|
- ✅ **Automated versioning**: No manual version bumps needed
|
||||||
|
- ✅ **Generated changelogs**: Automatic, accurate release notes
|
||||||
|
- ✅ **Semantic versioning**: Enforced through changeset types
|
||||||
|
- ✅ **Git tagging**: Proper tags for extension releases
|
||||||
|
- ✅ **Conflict prevention**: Clear separation of extension vs. main package versions
|
||||||
|
- ✅ **Review process**: Version changes are reviewable via PR
|
||||||
|
- ✅ **Rollback capability**: Easy to revert if issues arise
|
||||||
|
|
||||||
|
This ensures clean, predictable, and fully automated publishing to both registries! 🚀
|
||||||
@@ -138,6 +138,65 @@ When updating extension metadata, ensure these fields match between `package.jso
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 🤖 Automated Release Process
|
||||||
|
|
||||||
|
### Changesets Workflow
|
||||||
|
This extension uses [Changesets](https://github.com/changesets/changesets) for automated version management and publishing.
|
||||||
|
|
||||||
|
#### Adding Changes
|
||||||
|
When making changes to the extension:
|
||||||
|
|
||||||
|
1. **Make your code changes**
|
||||||
|
2. **Create a changeset**:
|
||||||
|
```bash
|
||||||
|
# From project root
|
||||||
|
npx changeset add
|
||||||
|
```
|
||||||
|
3. **Select the extension package**: Choose `taskr-kanban` when prompted
|
||||||
|
4. **Select version bump type**:
|
||||||
|
- `patch`: Bug fixes, minor updates
|
||||||
|
- `minor`: New features, backwards compatible
|
||||||
|
- `major`: Breaking changes
|
||||||
|
5. **Write a summary**: Describe what changed for users
|
||||||
|
|
||||||
|
#### Automated Publishing
|
||||||
|
The automation workflow runs on pushes to `main`:
|
||||||
|
|
||||||
|
1. **Version Workflow** (`.github/workflows/version.yml`):
|
||||||
|
- Detects when changesets exist
|
||||||
|
- Creates a "Version Packages" PR with updated versions and CHANGELOG
|
||||||
|
- When the PR is merged, automatically publishes the extension
|
||||||
|
|
||||||
|
2. **Release Process** (`scripts/release.sh`):
|
||||||
|
- Builds the extension using the 3-file packaging system
|
||||||
|
- Creates VSIX package
|
||||||
|
- Publishes to VS Code Marketplace (if `VSCE_PAT` is set)
|
||||||
|
- Publishes to Open VSX Registry (if `OVSX_PAT` is set)
|
||||||
|
- Creates git tags for the extension version
|
||||||
|
|
||||||
|
#### Required Secrets
|
||||||
|
For automated publishing, these secrets must be set in the repository:
|
||||||
|
|
||||||
|
- `VSCE_PAT`: Personal Access Token for VS Code Marketplace
|
||||||
|
- `OVSX_PAT`: Personal Access Token for Open VSX Registry
|
||||||
|
- `GITHUB_TOKEN`: Automatically provided by GitHub Actions
|
||||||
|
|
||||||
|
#### Manual Release
|
||||||
|
If needed, you can manually trigger a release:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From project root
|
||||||
|
./scripts/release.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extension Tagging
|
||||||
|
The extension uses a separate tagging strategy from the main package:
|
||||||
|
|
||||||
|
- **Extension tags**: `taskr-kanban@1.0.1`
|
||||||
|
- **Main package tags**: `task-master-ai@2.1.0`
|
||||||
|
|
||||||
|
This allows independent versioning and prevents conflicts in the monorepo.
|
||||||
|
|
||||||
## 🔍 Troubleshooting
|
## 🔍 Troubleshooting
|
||||||
|
|
||||||
### Dependency Conflicts
|
### Dependency Conflicts
|
||||||
@@ -155,14 +214,32 @@ When updating extension metadata, ensure these fields match between `package.jso
|
|||||||
**Problem**: Extension works locally but fails when packaged
|
**Problem**: Extension works locally but fails when packaged
|
||||||
**Check**: Ensure critical fields are synced between package files
|
**Check**: Ensure critical fields are synced between package files
|
||||||
|
|
||||||
|
### Changeset Issues
|
||||||
|
**Problem**: Version workflow not triggering
|
||||||
|
**Check**:
|
||||||
|
1. Changeset files exist in `.changeset/`
|
||||||
|
2. Package name in changeset matches `package.publish.json`
|
||||||
|
3. Changes are pushed to `main` branch
|
||||||
|
|
||||||
|
**Problem**: Publishing fails
|
||||||
|
**Check**:
|
||||||
|
1. Required secrets are set in repository settings
|
||||||
|
2. `package.publish.json` has correct repository URL
|
||||||
|
3. Build process completes successfully
|
||||||
|
|
||||||
## 📝 Version Release Checklist
|
## 📝 Version Release Checklist
|
||||||
|
|
||||||
1. **Update version** in both `package.json` and `package.publish.json`
|
### Manual Releases
|
||||||
2. **Update CHANGELOG.md** with new features/fixes
|
1. **Create changeset**: `npx changeset add`
|
||||||
|
2. **Update critical fields** in both `package.json` and `package.publish.json`
|
||||||
3. **Test locally** with `F5` in VS Code
|
3. **Test locally** with `F5` in VS Code
|
||||||
4. **Build clean package**: `pnpm run package`
|
4. **Commit and push** to trigger automated workflow
|
||||||
5. **Test packaged extension**: Install `.vsix` file
|
|
||||||
6. **Publish**: Upload to marketplace or distribute `.vsix`
|
### Automated Releases (Recommended)
|
||||||
|
1. **Create changeset**: `npx changeset add`
|
||||||
|
2. **Push to feature branch** and create PR
|
||||||
|
3. **Merge PR** - this triggers version PR creation
|
||||||
|
4. **Review and merge version PR** - this triggers automated publishing
|
||||||
|
|
||||||
## 🎯 Why This System?
|
## 🎯 Why This System?
|
||||||
|
|
||||||
@@ -171,7 +248,9 @@ When updating extension metadata, ensure these fields match between `package.jso
|
|||||||
- **Faster packaging**: No dependency resolution during `vsce package`
|
- **Faster packaging**: No dependency resolution during `vsce package`
|
||||||
- **Maintainable**: Clear separation of dev vs. production configs
|
- **Maintainable**: Clear separation of dev vs. production configs
|
||||||
- **Reliable**: Consistent, conflict-free packaging process
|
- **Reliable**: Consistent, conflict-free packaging process
|
||||||
|
- **Automated**: Changesets handle versioning and publishing automatically
|
||||||
|
- **Traceable**: Clear changelog and git tags for every release
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Remember**: Always use `pnpm run package` → `cd vsix-build` → `vsce package --no-dependencies` for production builds! 🚀
|
**Remember**: Always use `npx changeset add` for changes, then push to trigger automated releases! 🚀
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "taskr",
|
"name": "taskr",
|
||||||
|
"private": true,
|
||||||
"displayName": "Task Master Kanban",
|
"displayName": "Task Master Kanban",
|
||||||
"description": "A visual Kanban board interface for Task Master projects in VS Code",
|
"description": "A visual Kanban board interface for Task Master projects in VS Code",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"publisher": "DavidMaliglowka",
|
"publisher": "DavidMaliglowka",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.93.0"
|
"vscode": "^1.93.0"
|
||||||
},
|
},
|
||||||
"categories": ["AI", "Visualization", "Education", "Other"],
|
"categories": [
|
||||||
|
"AI",
|
||||||
|
"Visualization",
|
||||||
|
"Education",
|
||||||
|
"Other"
|
||||||
|
],
|
||||||
"main": "./dist/extension.js",
|
"main": "./dist/extension.js",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
@@ -42,7 +48,11 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"default": ["-y", "--package=task-master-ai", "task-master-ai"],
|
"default": [
|
||||||
|
"-y",
|
||||||
|
"--package=task-master-ai",
|
||||||
|
"task-master-ai"
|
||||||
|
],
|
||||||
"description": "An array of arguments to pass to the MCP server command."
|
"description": "An array of arguments to pass to the MCP server command."
|
||||||
},
|
},
|
||||||
"taskmaster.mcp.cwd": {
|
"taskmaster.mcp.cwd": {
|
||||||
@@ -102,7 +112,11 @@
|
|||||||
},
|
},
|
||||||
"taskmaster.ui.theme": {
|
"taskmaster.ui.theme": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["auto", "light", "dark"],
|
"enum": [
|
||||||
|
"auto",
|
||||||
|
"light",
|
||||||
|
"dark"
|
||||||
|
],
|
||||||
"default": "auto",
|
"default": "auto",
|
||||||
"description": "UI theme preference"
|
"description": "UI theme preference"
|
||||||
},
|
},
|
||||||
@@ -163,7 +177,12 @@
|
|||||||
},
|
},
|
||||||
"taskmaster.debug.logLevel": {
|
"taskmaster.debug.logLevel": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["error", "warn", "info", "debug"],
|
"enum": [
|
||||||
|
"error",
|
||||||
|
"warn",
|
||||||
|
"info",
|
||||||
|
"debug"
|
||||||
|
],
|
||||||
"default": "info",
|
"default": "info",
|
||||||
"description": "Logging level"
|
"description": "Logging level"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -52,12 +52,30 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Copy and RENAME the clean manifest
|
// 5. Sync versions and prepare the final package.json
|
||||||
console.log('Copying and preparing the final package.json...');
|
console.log('Syncing versions and preparing the final package.json...');
|
||||||
fs.copySync(
|
|
||||||
path.resolve(__dirname, 'package.publish.json'),
|
// Read current versions
|
||||||
path.resolve(packageDir, 'package.json')
|
const devPackagePath = path.resolve(__dirname, 'package.json');
|
||||||
);
|
const publishPackagePath = path.resolve(__dirname, 'package.publish.json');
|
||||||
|
|
||||||
|
const devPackage = JSON.parse(fs.readFileSync(devPackagePath, 'utf8'));
|
||||||
|
const publishPackage = JSON.parse(fs.readFileSync(publishPackagePath, 'utf8'));
|
||||||
|
|
||||||
|
// Check if versions are in sync
|
||||||
|
if (devPackage.version !== publishPackage.version) {
|
||||||
|
console.log(` - Version sync needed: ${publishPackage.version} → ${devPackage.version}`);
|
||||||
|
publishPackage.version = devPackage.version;
|
||||||
|
|
||||||
|
// Update the source package.publish.json file
|
||||||
|
fs.writeFileSync(publishPackagePath, JSON.stringify(publishPackage, null, '\t') + '\n');
|
||||||
|
console.log(` - Updated package.publish.json version to ${devPackage.version}`);
|
||||||
|
} else {
|
||||||
|
console.log(` - Versions already in sync: ${devPackage.version}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the (now synced) package.publish.json as package.json
|
||||||
|
fs.copySync(publishPackagePath, path.resolve(packageDir, 'package.json'));
|
||||||
console.log(' - Copied package.publish.json as package.json');
|
console.log(' - Copied package.publish.json as package.json');
|
||||||
|
|
||||||
// 6. Copy .vscodeignore if it exists
|
// 6. Copy .vscodeignore if it exists
|
||||||
@@ -97,13 +115,10 @@ try {
|
|||||||
`cd vsix-build && pnpm exec vsce package --no-dependencies`
|
`cd vsix-build && pnpm exec vsce package --no-dependencies`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Read version from package.publish.json
|
// Use the synced version for output
|
||||||
const publishPackage = JSON.parse(
|
const finalVersion = devPackage.version;
|
||||||
fs.readFileSync(path.resolve(__dirname, 'package.publish.json'), 'utf8')
|
|
||||||
);
|
|
||||||
const version = publishPackage.version;
|
|
||||||
console.log(
|
console.log(
|
||||||
`\nYour extension will be packaged to: vsix-build/taskr-${version}.vsix`
|
`\nYour extension will be packaged to: vsix-build/taskr-kanban-${finalVersion}.vsix`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('\n❌ Packaging failed!');
|
console.error('\n❌ Packaging failed!');
|
||||||
|
|||||||
@@ -8,7 +8,12 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.93.0"
|
"vscode": "^1.93.0"
|
||||||
},
|
},
|
||||||
"categories": ["AI", "Visualization", "Education", "Other"],
|
"categories": [
|
||||||
|
"AI",
|
||||||
|
"Visualization",
|
||||||
|
"Education",
|
||||||
|
"Other"
|
||||||
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"kanban",
|
"kanban",
|
||||||
"kanban board",
|
"kanban board",
|
||||||
@@ -82,7 +87,11 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"default": ["-y", "--package=task-master-ai", "task-master-ai"],
|
"default": [
|
||||||
|
"-y",
|
||||||
|
"--package=task-master-ai",
|
||||||
|
"task-master-ai"
|
||||||
|
],
|
||||||
"description": "An array of arguments to pass to the MCP server command."
|
"description": "An array of arguments to pass to the MCP server command."
|
||||||
},
|
},
|
||||||
"taskmaster.mcp.cwd": {
|
"taskmaster.mcp.cwd": {
|
||||||
@@ -142,7 +151,11 @@
|
|||||||
},
|
},
|
||||||
"taskmaster.ui.theme": {
|
"taskmaster.ui.theme": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["auto", "light", "dark"],
|
"enum": [
|
||||||
|
"auto",
|
||||||
|
"light",
|
||||||
|
"dark"
|
||||||
|
],
|
||||||
"default": "auto",
|
"default": "auto",
|
||||||
"description": "UI theme preference"
|
"description": "UI theme preference"
|
||||||
},
|
},
|
||||||
@@ -203,7 +216,12 @@
|
|||||||
},
|
},
|
||||||
"taskmaster.debug.logLevel": {
|
"taskmaster.debug.logLevel": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["error", "warn", "info", "debug"],
|
"enum": [
|
||||||
|
"error",
|
||||||
|
"warn",
|
||||||
|
"info",
|
||||||
|
"debug"
|
||||||
|
],
|
||||||
"default": "info",
|
"default": "info",
|
||||||
"description": "Logging level"
|
"description": "Logging level"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const context = useContext(VSCodeContext);
|
const context = useContext(VSCodeContext);
|
||||||
if (!context)
|
if (!context)
|
||||||
throw new Error('TaskDetailsView must be used within VSCodeContext');
|
{throw new Error('TaskDetailsView must be used within VSCodeContext');}
|
||||||
|
|
||||||
const { state, sendMessage } = context;
|
const { state, sendMessage } = context;
|
||||||
const { tasks } = state;
|
const { tasks } = state;
|
||||||
@@ -372,7 +372,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
|
|
||||||
// Handle running complexity analysis for a task
|
// Handle running complexity analysis for a task
|
||||||
const handleRunComplexityAnalysis = useCallback(async () => {
|
const handleRunComplexityAnalysis = useCallback(async () => {
|
||||||
if (!currentTask) return;
|
if (!currentTask) {return;}
|
||||||
|
|
||||||
setIsLoadingComplexity(true);
|
setIsLoadingComplexity(true);
|
||||||
try {
|
try {
|
||||||
@@ -416,7 +416,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
|
|
||||||
// Function to fetch task file data (implementation details and test strategy only)
|
// Function to fetch task file data (implementation details and test strategy only)
|
||||||
const fetchTaskFileData = async () => {
|
const fetchTaskFileData = async () => {
|
||||||
if (!currentTask?.id) return;
|
if (!currentTask?.id) {return;}
|
||||||
|
|
||||||
setIsLoadingTaskFileData(true);
|
setIsLoadingTaskFileData(true);
|
||||||
setTaskFileDataError(null);
|
setTaskFileDataError(null);
|
||||||
@@ -543,7 +543,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
|
|
||||||
// Handle AI Actions
|
// Handle AI Actions
|
||||||
const handleRegenerate = async () => {
|
const handleRegenerate = async () => {
|
||||||
if (!currentTask || !prompt.trim()) return;
|
if (!currentTask || !prompt.trim()) {return;}
|
||||||
|
|
||||||
setIsRegenerating(true);
|
setIsRegenerating(true);
|
||||||
try {
|
try {
|
||||||
@@ -584,7 +584,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAppend = async () => {
|
const handleAppend = async () => {
|
||||||
if (!currentTask || !prompt.trim()) return;
|
if (!currentTask || !prompt.trim()) {return;}
|
||||||
|
|
||||||
setIsAppending(true);
|
setIsAppending(true);
|
||||||
try {
|
try {
|
||||||
@@ -626,7 +626,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
|
|
||||||
// Handle adding a new subtask
|
// Handle adding a new subtask
|
||||||
const handleAddSubtask = async () => {
|
const handleAddSubtask = async () => {
|
||||||
if (!currentTask || !newSubtaskTitle.trim() || isSubtask) return;
|
if (!currentTask || !newSubtaskTitle.trim() || isSubtask) {return;}
|
||||||
|
|
||||||
setIsSubmittingSubtask(true);
|
setIsSubmittingSubtask(true);
|
||||||
try {
|
try {
|
||||||
@@ -672,7 +672,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
|||||||
|
|
||||||
// Handle status change
|
// Handle status change
|
||||||
const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
|
const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
|
||||||
if (!currentTask) return;
|
if (!currentTask) {return;}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sendMessage({
|
await sendMessage({
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
} from './utils/errorHandler';
|
} from './utils/errorHandler';
|
||||||
import { getToastDuration } from './utils/notificationPreferences';
|
import { getToastDuration } from './utils/notificationPreferences';
|
||||||
import { parseTaskFileData } from './utils/taskFileReader';
|
import { parseTaskFileData } from './utils/taskFileReader';
|
||||||
|
import { TaskMasterTask } from './utils/taskMasterApi';
|
||||||
|
|
||||||
// Global MCP client manager instance
|
// Global MCP client manager instance
|
||||||
let mcpClient: MCPClientManager | null = null;
|
let mcpClient: MCPClientManager | null = null;
|
||||||
@@ -39,7 +40,7 @@ interface PollingState {
|
|||||||
timer?: NodeJS.Timeout;
|
timer?: NodeJS.Timeout;
|
||||||
isPolling: boolean;
|
isPolling: boolean;
|
||||||
interval: number;
|
interval: number;
|
||||||
lastTaskData?: any[];
|
lastTaskData?: TaskMasterTask[];
|
||||||
errorCount: number;
|
errorCount: number;
|
||||||
maxErrors: number;
|
maxErrors: number;
|
||||||
// Adaptive frequency properties
|
// Adaptive frequency properties
|
||||||
@@ -55,7 +56,7 @@ interface PollingState {
|
|||||||
reconnectBackoffMultiplier: number;
|
reconnectBackoffMultiplier: number;
|
||||||
lastSuccessfulConnection?: number;
|
lastSuccessfulConnection?: number;
|
||||||
isOfflineMode: boolean;
|
isOfflineMode: boolean;
|
||||||
cachedTaskData?: any[];
|
cachedTaskData?: TaskMasterTask[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let pollingState: PollingState = {
|
let pollingState: PollingState = {
|
||||||
@@ -351,7 +352,7 @@ function adjustPollingFrequency(): void {
|
|||||||
// Low activity: reduce polling frequency with exponential backoff
|
// Low activity: reduce polling frequency with exponential backoff
|
||||||
const backoffMultiplier = Math.min(
|
const backoffMultiplier = Math.min(
|
||||||
4,
|
4,
|
||||||
Math.pow(1.5, pollingState.consecutiveNoChanges - 3)
|
1.5 ** (pollingState.consecutiveNoChanges - 3)
|
||||||
);
|
);
|
||||||
newInterval = Math.min(
|
newInterval = Math.min(
|
||||||
pollingState.maxInterval,
|
pollingState.maxInterval,
|
||||||
@@ -1031,43 +1032,65 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
case 'readTaskFileData':
|
case 'readTaskFileData':
|
||||||
console.log('📄 Reading task file data:', message.data);
|
console.log('📄 Reading task file data:', message.data);
|
||||||
const { requestId } = message;
|
{
|
||||||
try {
|
const { requestId } = message;
|
||||||
const { taskId, tag: tagName = 'master' } = message.data;
|
try {
|
||||||
|
const { taskId, tag: tagName = 'master' } = message.data;
|
||||||
|
|
||||||
// Get workspace folder
|
// Get workspace folder
|
||||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||||
if (!workspaceFolder) {
|
if (!workspaceFolder) {
|
||||||
throw new Error('No workspace folder found');
|
throw new Error('No workspace folder found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build path to tasks.json
|
// Build path to tasks.json
|
||||||
const tasksJsonPath = path.join(
|
const tasksJsonPath = path.join(
|
||||||
workspaceFolder.uri.fsPath,
|
|
||||||
'.taskmaster',
|
|
||||||
'tasks',
|
|
||||||
'tasks.json'
|
|
||||||
);
|
|
||||||
console.log('🔍 Looking for tasks.json at:', tasksJsonPath);
|
|
||||||
|
|
||||||
// Check if file exists
|
|
||||||
if (!fs.existsSync(tasksJsonPath)) {
|
|
||||||
// Try legacy location
|
|
||||||
const legacyPath = path.join(
|
|
||||||
workspaceFolder.uri.fsPath,
|
workspaceFolder.uri.fsPath,
|
||||||
|
'.taskmaster',
|
||||||
'tasks',
|
'tasks',
|
||||||
'tasks.json'
|
'tasks.json'
|
||||||
);
|
);
|
||||||
console.log('🔍 Trying legacy path:', legacyPath);
|
console.log('🔍 Looking for tasks.json at:', tasksJsonPath);
|
||||||
if (!fs.existsSync(legacyPath)) {
|
|
||||||
throw new Error(
|
// Check if file exists
|
||||||
'tasks.json not found in .taskmaster/tasks/ or tasks/ directory'
|
if (!fs.existsSync(tasksJsonPath)) {
|
||||||
|
// Try legacy location
|
||||||
|
const legacyPath = path.join(
|
||||||
|
workspaceFolder.uri.fsPath,
|
||||||
|
'tasks',
|
||||||
|
'tasks.json'
|
||||||
);
|
);
|
||||||
|
console.log('🔍 Trying legacy path:', legacyPath);
|
||||||
|
if (!fs.existsSync(legacyPath)) {
|
||||||
|
throw new Error(
|
||||||
|
'tasks.json not found in .taskmaster/tasks/ or tasks/ directory'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Use legacy path
|
||||||
|
const content = fs.readFileSync(legacyPath, 'utf8');
|
||||||
|
console.log(
|
||||||
|
'📖 Read legacy tasks.json, content length:',
|
||||||
|
content.length
|
||||||
|
);
|
||||||
|
const taskData = parseTaskFileData(
|
||||||
|
content,
|
||||||
|
taskId,
|
||||||
|
tagName,
|
||||||
|
workspaceFolder.uri.fsPath
|
||||||
|
);
|
||||||
|
console.log('✅ Parsed task data for legacy path:', taskData);
|
||||||
|
panel.webview.postMessage({
|
||||||
|
type: 'response',
|
||||||
|
requestId,
|
||||||
|
data: taskData
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// Use legacy path
|
|
||||||
const content = fs.readFileSync(legacyPath, 'utf8');
|
// Read and parse tasks.json
|
||||||
|
const content = fs.readFileSync(tasksJsonPath, 'utf8');
|
||||||
console.log(
|
console.log(
|
||||||
'📖 Read legacy tasks.json, content length:',
|
'📖 Read tasks.json, content length:',
|
||||||
content.length
|
content.length
|
||||||
);
|
);
|
||||||
const taskData = parseTaskFileData(
|
const taskData = parseTaskFileData(
|
||||||
@@ -1076,46 +1099,26 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
tagName,
|
tagName,
|
||||||
workspaceFolder.uri.fsPath
|
workspaceFolder.uri.fsPath
|
||||||
);
|
);
|
||||||
console.log('✅ Parsed task data for legacy path:', taskData);
|
console.log('✅ Parsed task data:', taskData);
|
||||||
|
|
||||||
panel.webview.postMessage({
|
panel.webview.postMessage({
|
||||||
type: 'response',
|
type: 'response',
|
||||||
requestId,
|
requestId,
|
||||||
data: taskData
|
data: taskData
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
|
console.log(`✅ Retrieved task file data for task ${taskId}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error reading task file data:', error);
|
||||||
|
panel.webview.postMessage({
|
||||||
|
type: 'error',
|
||||||
|
requestId,
|
||||||
|
error:
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Failed to read task file data'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and parse tasks.json
|
|
||||||
const content = fs.readFileSync(tasksJsonPath, 'utf8');
|
|
||||||
console.log(
|
|
||||||
'📖 Read tasks.json, content length:',
|
|
||||||
content.length
|
|
||||||
);
|
|
||||||
const taskData = parseTaskFileData(
|
|
||||||
content,
|
|
||||||
taskId,
|
|
||||||
tagName,
|
|
||||||
workspaceFolder.uri.fsPath
|
|
||||||
);
|
|
||||||
console.log('✅ Parsed task data:', taskData);
|
|
||||||
|
|
||||||
panel.webview.postMessage({
|
|
||||||
type: 'response',
|
|
||||||
requestId,
|
|
||||||
data: taskData
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`✅ Retrieved task file data for task ${taskId}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ Error reading task file data:', error);
|
|
||||||
panel.webview.postMessage({
|
|
||||||
type: 'error',
|
|
||||||
requestId,
|
|
||||||
error:
|
|
||||||
error instanceof Error
|
|
||||||
? error.message
|
|
||||||
: 'Failed to read task file data'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -648,14 +648,14 @@ const TaskEditModal: React.FC<{
|
|||||||
|
|
||||||
// Only include changed fields
|
// Only include changed fields
|
||||||
const updates: TaskUpdates = {};
|
const updates: TaskUpdates = {};
|
||||||
if (formData.title !== task.title) updates.title = formData.title;
|
if (formData.title !== task.title) {updates.title = formData.title;}
|
||||||
if (formData.description !== task.description)
|
if (formData.description !== task.description)
|
||||||
updates.description = formData.description;
|
{updates.description = formData.description;}
|
||||||
if (formData.details !== task.details) updates.details = formData.details;
|
if (formData.details !== task.details) {updates.details = formData.details;}
|
||||||
if (formData.priority !== task.priority)
|
if (formData.priority !== task.priority)
|
||||||
updates.priority = formData.priority;
|
{updates.priority = formData.priority;}
|
||||||
if (formData.testStrategy !== task.testStrategy)
|
if (formData.testStrategy !== task.testStrategy)
|
||||||
updates.testStrategy = formData.testStrategy;
|
{updates.testStrategy = formData.testStrategy;}
|
||||||
if (
|
if (
|
||||||
JSON.stringify(formData.dependencies) !==
|
JSON.stringify(formData.dependencies) !==
|
||||||
JSON.stringify(task.dependencies)
|
JSON.stringify(task.dependencies)
|
||||||
@@ -875,7 +875,7 @@ const TaskCard: React.FC<{
|
|||||||
const TaskMasterKanban: React.FC = () => {
|
const TaskMasterKanban: React.FC = () => {
|
||||||
const context = useContext(VSCodeContext);
|
const context = useContext(VSCodeContext);
|
||||||
if (!context)
|
if (!context)
|
||||||
throw new Error('TaskMasterKanban must be used within VSCodeContext');
|
{throw new Error('TaskMasterKanban must be used within VSCodeContext');}
|
||||||
|
|
||||||
const { state, dispatch, sendMessage, availableHeight } = context;
|
const { state, dispatch, sendMessage, availableHeight } = context;
|
||||||
const {
|
const {
|
||||||
@@ -984,14 +984,14 @@ const TaskMasterKanban: React.FC = () => {
|
|||||||
dispatch({ type: 'SET_USER_INTERACTING', payload: false });
|
dispatch({ type: 'SET_USER_INTERACTING', payload: false });
|
||||||
}, 1000); // 1 second delay to ensure smooth completion
|
}, 1000); // 1 second delay to ensure smooth completion
|
||||||
|
|
||||||
if (!over) return;
|
if (!over) {return;}
|
||||||
|
|
||||||
const taskId = active.id as string;
|
const taskId = active.id as string;
|
||||||
const newStatus = over.id as TaskMasterTask['status'];
|
const newStatus = over.id as TaskMasterTask['status'];
|
||||||
|
|
||||||
// Find the task that was moved
|
// Find the task that was moved
|
||||||
const task = tasks.find((t) => t.id === taskId);
|
const task = tasks.find((t) => t.id === taskId);
|
||||||
if (!task || task.status === newStatus) return;
|
if (!task || task.status === newStatus) {return;}
|
||||||
|
|
||||||
console.log(`🔄 Moving task ${taskId} from ${task.status} to ${newStatus}`);
|
console.log(`🔄 Moving task ${taskId} from ${task.status} to ${newStatus}`);
|
||||||
|
|
||||||
@@ -1382,7 +1382,7 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
// Handle messages from extension
|
// Handle messages from extension
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!vscode) return;
|
if (!vscode) {return;}
|
||||||
|
|
||||||
const handleMessage = (event: MessageEvent) => {
|
const handleMessage = (event: MessageEvent) => {
|
||||||
const message: WebviewMessage = event.data;
|
const message: WebviewMessage = event.data;
|
||||||
@@ -1526,13 +1526,13 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
// Map error severity to toast type
|
// Map error severity to toast type
|
||||||
let toastType: ToastNotification['type'] = 'error';
|
let toastType: ToastNotification['type'] = 'error';
|
||||||
if (errorData.severity === 'low') toastType = 'info';
|
if (errorData.severity === 'low') {toastType = 'info';}
|
||||||
else if (errorData.severity === 'medium') toastType = 'warning';
|
else if (errorData.severity === 'medium') {toastType = 'warning';}
|
||||||
else if (
|
else if (
|
||||||
errorData.severity === 'high' ||
|
errorData.severity === 'high' ||
|
||||||
errorData.severity === 'critical'
|
errorData.severity === 'critical'
|
||||||
)
|
)
|
||||||
toastType = 'error';
|
{toastType = 'error';}
|
||||||
|
|
||||||
// Create appropriate toast based on error category
|
// Create appropriate toast based on error category
|
||||||
const title =
|
const title =
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.20.0",
|
"version": "0.20.1",
|
||||||
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -9,7 +9,10 @@
|
|||||||
"task-master-mcp": "mcp-server/server.js",
|
"task-master-mcp": "mcp-server/server.js",
|
||||||
"task-master-ai": "mcp-server/server.js"
|
"task-master-ai": "mcp-server/server.js"
|
||||||
},
|
},
|
||||||
"workspaces": ["apps/*", "."],
|
"workspaces": [
|
||||||
|
"apps/*",
|
||||||
|
"."
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
||||||
"test:fails": "node --experimental-vm-modules node_modules/.bin/jest --onlyFailures",
|
"test:fails": "node --experimental-vm-modules node_modules/.bin/jest --onlyFailures",
|
||||||
|
|||||||
91
scripts/release.sh
Executable file
91
scripts/release.sh
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🚀 Starting release process..."
|
||||||
|
|
||||||
|
# Ensure we're in the project root
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
echo "📦 Building and packaging extension..."
|
||||||
|
|
||||||
|
# Navigate to extension directory and build
|
||||||
|
cd apps/extension
|
||||||
|
|
||||||
|
# Install dependencies (in case they're not cached)
|
||||||
|
echo "📥 Installing extension dependencies..."
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Run quality checks first (same as CI)
|
||||||
|
echo "🔍 Running lint checks..."
|
||||||
|
pnpm run lint
|
||||||
|
|
||||||
|
echo "🔍 Running type checks..."
|
||||||
|
pnpm run check-types
|
||||||
|
|
||||||
|
# Build the extension
|
||||||
|
echo "🔨 Building extension..."
|
||||||
|
pnpm run build
|
||||||
|
|
||||||
|
# Create clean package
|
||||||
|
echo "📦 Creating clean package..."
|
||||||
|
pnpm run package
|
||||||
|
|
||||||
|
# Verify package contents (same as CI)
|
||||||
|
echo "🔍 Verifying package contents..."
|
||||||
|
echo "Checking vsix-build contents..."
|
||||||
|
ls -la vsix-build/
|
||||||
|
echo "Checking dist contents..."
|
||||||
|
ls -la vsix-build/dist/
|
||||||
|
echo "Checking package.json exists..."
|
||||||
|
test -f vsix-build/package.json
|
||||||
|
|
||||||
|
# Create VSIX package
|
||||||
|
echo "📦 Creating VSIX package..."
|
||||||
|
cd vsix-build
|
||||||
|
pnpm exec vsce package --no-dependencies --out "$PWD"
|
||||||
|
|
||||||
|
# Run tests before publishing
|
||||||
|
echo "🧪 Running extension tests..."
|
||||||
|
cd ..
|
||||||
|
# Note: Tests run with xvfb-run in CI, but in release context we'll skip or handle differently
|
||||||
|
echo "⚠️ Skipping tests in release context (run in CI validation)"
|
||||||
|
|
||||||
|
# Go back to project root for tagging and changeset operations
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "🏷️ Checking extension tag..."
|
||||||
|
node scripts/tag-extension.mjs
|
||||||
|
|
||||||
|
echo "📝 Publishing packages with changesets..."
|
||||||
|
# Let changesets handle all the npm publishing first
|
||||||
|
npx changeset publish
|
||||||
|
|
||||||
|
echo "🌐 Publishing extension to VS Code Marketplace..."
|
||||||
|
# Find the generated VSIX file
|
||||||
|
VSIX_FILE=$(find apps/extension/vsix-build -name "*.vsix" | head -n 1)
|
||||||
|
|
||||||
|
if [ -n "$VSIX_FILE" ]; then
|
||||||
|
echo "Found VSIX file: $VSIX_FILE"
|
||||||
|
|
||||||
|
# Publish to VS Code Marketplace
|
||||||
|
if [ -n "$VSCE_PAT" ]; then
|
||||||
|
echo "Publishing to VS Code Marketplace..."
|
||||||
|
npx vsce publish --packagePath "$VSIX_FILE"
|
||||||
|
else
|
||||||
|
echo "⚠️ VSCE_PAT not set, skipping VS Code Marketplace publish"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Publish to Open VSX Registry
|
||||||
|
if [ -n "$OVSX_PAT" ]; then
|
||||||
|
echo "Publishing to Open VSX Registry..."
|
||||||
|
npx ovsx publish --packagePath "$VSIX_FILE"
|
||||||
|
else
|
||||||
|
echo "⚠️ OVSX_PAT not set, skipping Open VSX publish"
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "❌ No VSIX file found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Release process completed!"
|
||||||
52
scripts/tag-extension.mjs
Normal file
52
scripts/tag-extension.mjs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { spawnSync } from 'node:child_process'
|
||||||
|
import { readFileSync } from 'node:fs'
|
||||||
|
import { join, dirname } from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
|
// Read the extension's publishing package.json for accurate version/name
|
||||||
|
const extensionDir = join(__dirname, '..', 'apps', 'extension')
|
||||||
|
const publishPkgPath = join(extensionDir, 'package.publish.json')
|
||||||
|
|
||||||
|
let pkg
|
||||||
|
try {
|
||||||
|
const pkgContent = readFileSync(publishPkgPath, 'utf8')
|
||||||
|
pkg = JSON.parse(pkgContent)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to read package.publish.json:', error.message)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have required fields
|
||||||
|
assert(pkg.name, 'package.publish.json must have a name field')
|
||||||
|
assert(pkg.version, 'package.publish.json must have a version field')
|
||||||
|
assert(pkg.repository, 'package.publish.json must have a repository field')
|
||||||
|
|
||||||
|
const tag = `${pkg.name}@${pkg.version}`
|
||||||
|
|
||||||
|
// Get repository URL - handle both string and object format
|
||||||
|
const repoUrl = typeof pkg.repository === 'string'
|
||||||
|
? pkg.repository
|
||||||
|
: pkg.repository.url
|
||||||
|
|
||||||
|
assert(repoUrl, 'Repository URL not found in package.publish.json')
|
||||||
|
|
||||||
|
const { status, stdout, error } = spawnSync('git', [
|
||||||
|
'ls-remote',
|
||||||
|
repoUrl,
|
||||||
|
tag
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.equal(status, 0, error)
|
||||||
|
|
||||||
|
const exists = String(stdout).trim() !== ''
|
||||||
|
|
||||||
|
if (!exists) {
|
||||||
|
console.log(`\nNew extension tag: ${tag}`)
|
||||||
|
} else {
|
||||||
|
console.log(`\nExtension tag already exists: ${tag}`)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user