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:
|
||||
name: 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
|
||||
|
||||
## 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
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
# 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.
|
||||
|
||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Initial release
|
||||
- Initial release
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# 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
|
||||
|
||||
### 1. Extension CI (`extension-ci.yml`)
|
||||
|
||||
**Triggers:**
|
||||
- Push to `main` or `next` branches (only when extension files change)
|
||||
- Pull requests to `main` or `next` (only when extension files change)
|
||||
|
||||
**What it does:**
|
||||
|
||||
- ✅ Lints and type-checks the extension code
|
||||
- 🔨 Builds the extension (`pnpm run build`)
|
||||
- 📦 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
|
||||
- 💾 Uploads build artifacts for inspection
|
||||
|
||||
### 2. Extension Release (`extension-release.yml`)
|
||||
### 2. Version & Publish (`version.yml`)
|
||||
|
||||
**Triggers:**
|
||||
- Push to `main` branch (only when extension files change AND version changes)
|
||||
- Manual trigger with `workflow_dispatch` (with optional force publish)
|
||||
- Push to `main` branch
|
||||
|
||||
**What it does:**
|
||||
- 🔍 Checks if the extension version changed
|
||||
- 🧪 Runs full test suite (lint, typecheck, tests)
|
||||
- 🔨 Builds and packages the extension
|
||||
- 📤 Publishes to VS Code Marketplace
|
||||
- 🌍 Publishes to Open VSX Registry (for VSCodium, Gitpod, etc.)
|
||||
- 🏷️ Creates a GitHub release with the VSIX file
|
||||
- 📊 Uploads release artifacts
|
||||
- 🔍 Detects changeset files for pending releases
|
||||
- 📝 Creates "Version Packages" PR with updated versions and CHANGELOG
|
||||
- 🤖 When Version PR is merged, automatically:
|
||||
- 🔨 Builds and packages the extension
|
||||
- 🏷️ Creates git tags with changeset automation
|
||||
- 📤 Publishes to VS Code Marketplace
|
||||
- 🌍 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
|
||||
|
||||
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)
|
||||
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)
|
||||
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 Sync Checklist
|
||||
When updating the extension version, ensure these fields match in both files:
|
||||
### Changeset-Based Versioning
|
||||
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
|
||||
{
|
||||
"version": "1.0.2", // ⚠️ MUST MATCH
|
||||
"publisher": "DavidMaliglowka", // ⚠️ MUST MATCH
|
||||
"displayName": "Task Master Kanban", // ⚠️ MUST MATCH
|
||||
"description": "...", // ⚠️ MUST MATCH
|
||||
"engines": { "vscode": "^1.93.0" }, // ⚠️ MUST MATCH
|
||||
"categories": [...], // ⚠️ MUST MATCH
|
||||
"contributes": { ... } // ⚠️ MUST MATCH
|
||||
"version": "1.0.2", // ✅ AUTO-SYNCED
|
||||
"publisher": "DavidMaliglowka", // ⚠️ MUST MATCH MANUALLY
|
||||
"displayName": "taskr: Task Master Kanban", // ⚠️ MUST MATCH MANUALLY
|
||||
"description": "...", // ⚠️ MUST MATCH MANUALLY
|
||||
"engines": { "vscode": "^1.93.0" }, // ⚠️ MUST MATCH MANUALLY
|
||||
"categories": [...], // ⚠️ MUST MATCH MANUALLY
|
||||
"contributes": { ... } // ⚠️ MUST MATCH MANUALLY
|
||||
}
|
||||
```
|
||||
|
||||
### Version Detection Logic
|
||||
The release workflow only publishes when:
|
||||
- Extension files changed in the push, AND
|
||||
- Version field changed in `package.json` or `package.publish.json`
|
||||
**Note**: Only `version` is automatically synced. Other fields must be manually kept in sync.
|
||||
|
||||
## 🔍 Monitoring Builds
|
||||
|
||||
@@ -104,44 +126,61 @@ The release workflow only publishes when:
|
||||
- **Red ❌**: Build/test failures - check logs for details
|
||||
- **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
|
||||
- **Published 🎉**: Extension live on VS Code Marketplace
|
||||
- **Skipped ℹ️**: No version changes detected
|
||||
- **Published 🎉**: Extension live on VS Code Marketplace and Open VSX
|
||||
- **Skipped ℹ️**: No changesets found, no release needed
|
||||
- **Failed ❌**: Check logs - often missing secrets or build issues
|
||||
|
||||
### Artifacts
|
||||
Both workflows upload artifacts that you can download:
|
||||
Workflows upload artifacts that you can download:
|
||||
- **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
|
||||
|
||||
### 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
|
||||
- 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
|
||||
- Check token hasn't expired
|
||||
- Verify you're signed in to Open VSX Registry with GitHub
|
||||
|
||||
**"Version not changed" Skipped Release**
|
||||
- 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**
|
||||
#### Build Failures
|
||||
- Check extension code compiles locally: `cd apps/extension && pnpm run build`
|
||||
- Verify tests pass locally: `pnpm run test`
|
||||
- Check for TypeScript errors: `pnpm run check-types`
|
||||
|
||||
**Packaging Failures**
|
||||
#### Packaging Failures
|
||||
- Ensure clean package builds: `pnpm run package`
|
||||
- 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
|
||||
|
||||
@@ -149,11 +188,22 @@ The CI workflows respect the 3-file packaging system:
|
||||
- **Development**: Uses `package.json` for dependencies and scripts
|
||||
- **Release**: Uses `package.publish.json` for clean marketplace package
|
||||
- **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:
|
||||
- **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
|
||||
|
||||
### 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
|
||||
**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
|
||||
|
||||
1. **Update version** in both `package.json` and `package.publish.json`
|
||||
2. **Update CHANGELOG.md** with new features/fixes
|
||||
### Manual Releases
|
||||
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
|
||||
4. **Build clean package**: `pnpm run package`
|
||||
5. **Test packaged extension**: Install `.vsix` file
|
||||
6. **Publish**: Upload to marketplace or distribute `.vsix`
|
||||
4. **Commit and push** to trigger automated workflow
|
||||
|
||||
### 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?
|
||||
|
||||
@@ -171,7 +248,9 @@ When updating extension metadata, ensure these fields match between `package.jso
|
||||
- **Faster packaging**: No dependency resolution during `vsce package`
|
||||
- **Maintainable**: Clear separation of dev vs. production configs
|
||||
- **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",
|
||||
"private": true,
|
||||
"displayName": "Task Master Kanban",
|
||||
"description": "A visual Kanban board interface for Task Master projects in VS Code",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"publisher": "DavidMaliglowka",
|
||||
"icon": "assets/icon.png",
|
||||
"engines": {
|
||||
"vscode": "^1.93.0"
|
||||
},
|
||||
"categories": ["AI", "Visualization", "Education", "Other"],
|
||||
"categories": [
|
||||
"AI",
|
||||
"Visualization",
|
||||
"Education",
|
||||
"Other"
|
||||
],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
@@ -42,7 +48,11 @@
|
||||
"items": {
|
||||
"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."
|
||||
},
|
||||
"taskmaster.mcp.cwd": {
|
||||
@@ -102,7 +112,11 @@
|
||||
},
|
||||
"taskmaster.ui.theme": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "light", "dark"],
|
||||
"enum": [
|
||||
"auto",
|
||||
"light",
|
||||
"dark"
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "UI theme preference"
|
||||
},
|
||||
@@ -163,7 +177,12 @@
|
||||
},
|
||||
"taskmaster.debug.logLevel": {
|
||||
"type": "string",
|
||||
"enum": ["error", "warn", "info", "debug"],
|
||||
"enum": [
|
||||
"error",
|
||||
"warn",
|
||||
"info",
|
||||
"debug"
|
||||
],
|
||||
"default": "info",
|
||||
"description": "Logging level"
|
||||
},
|
||||
|
||||
@@ -52,12 +52,30 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Copy and RENAME the clean manifest
|
||||
console.log('Copying and preparing the final package.json...');
|
||||
fs.copySync(
|
||||
path.resolve(__dirname, 'package.publish.json'),
|
||||
path.resolve(packageDir, 'package.json')
|
||||
);
|
||||
// 5. Sync versions and prepare the final package.json
|
||||
console.log('Syncing versions and preparing the final package.json...');
|
||||
|
||||
// Read current versions
|
||||
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');
|
||||
|
||||
// 6. Copy .vscodeignore if it exists
|
||||
@@ -97,13 +115,10 @@ try {
|
||||
`cd vsix-build && pnpm exec vsce package --no-dependencies`
|
||||
);
|
||||
|
||||
// Read version from package.publish.json
|
||||
const publishPackage = JSON.parse(
|
||||
fs.readFileSync(path.resolve(__dirname, 'package.publish.json'), 'utf8')
|
||||
);
|
||||
const version = publishPackage.version;
|
||||
// Use the synced version for output
|
||||
const finalVersion = devPackage.version;
|
||||
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) {
|
||||
console.error('\n❌ Packaging failed!');
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
"engines": {
|
||||
"vscode": "^1.93.0"
|
||||
},
|
||||
"categories": ["AI", "Visualization", "Education", "Other"],
|
||||
"categories": [
|
||||
"AI",
|
||||
"Visualization",
|
||||
"Education",
|
||||
"Other"
|
||||
],
|
||||
"keywords": [
|
||||
"kanban",
|
||||
"kanban board",
|
||||
@@ -82,7 +87,11 @@
|
||||
"items": {
|
||||
"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."
|
||||
},
|
||||
"taskmaster.mcp.cwd": {
|
||||
@@ -142,7 +151,11 @@
|
||||
},
|
||||
"taskmaster.ui.theme": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "light", "dark"],
|
||||
"enum": [
|
||||
"auto",
|
||||
"light",
|
||||
"dark"
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "UI theme preference"
|
||||
},
|
||||
@@ -203,7 +216,12 @@
|
||||
},
|
||||
"taskmaster.debug.logLevel": {
|
||||
"type": "string",
|
||||
"enum": ["error", "warn", "info", "debug"],
|
||||
"enum": [
|
||||
"error",
|
||||
"warn",
|
||||
"info",
|
||||
"debug"
|
||||
],
|
||||
"default": "info",
|
||||
"description": "Logging level"
|
||||
},
|
||||
|
||||
@@ -262,7 +262,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
}) => {
|
||||
const context = useContext(VSCodeContext);
|
||||
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 { tasks } = state;
|
||||
@@ -372,7 +372,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
|
||||
// Handle running complexity analysis for a task
|
||||
const handleRunComplexityAnalysis = useCallback(async () => {
|
||||
if (!currentTask) return;
|
||||
if (!currentTask) {return;}
|
||||
|
||||
setIsLoadingComplexity(true);
|
||||
try {
|
||||
@@ -416,7 +416,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
|
||||
// Function to fetch task file data (implementation details and test strategy only)
|
||||
const fetchTaskFileData = async () => {
|
||||
if (!currentTask?.id) return;
|
||||
if (!currentTask?.id) {return;}
|
||||
|
||||
setIsLoadingTaskFileData(true);
|
||||
setTaskFileDataError(null);
|
||||
@@ -543,7 +543,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
|
||||
// Handle AI Actions
|
||||
const handleRegenerate = async () => {
|
||||
if (!currentTask || !prompt.trim()) return;
|
||||
if (!currentTask || !prompt.trim()) {return;}
|
||||
|
||||
setIsRegenerating(true);
|
||||
try {
|
||||
@@ -584,7 +584,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
};
|
||||
|
||||
const handleAppend = async () => {
|
||||
if (!currentTask || !prompt.trim()) return;
|
||||
if (!currentTask || !prompt.trim()) {return;}
|
||||
|
||||
setIsAppending(true);
|
||||
try {
|
||||
@@ -626,7 +626,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
|
||||
// Handle adding a new subtask
|
||||
const handleAddSubtask = async () => {
|
||||
if (!currentTask || !newSubtaskTitle.trim() || isSubtask) return;
|
||||
if (!currentTask || !newSubtaskTitle.trim() || isSubtask) {return;}
|
||||
|
||||
setIsSubmittingSubtask(true);
|
||||
try {
|
||||
@@ -672,7 +672,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
|
||||
// Handle status change
|
||||
const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
|
||||
if (!currentTask) return;
|
||||
if (!currentTask) {return;}
|
||||
|
||||
try {
|
||||
await sendMessage({
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from './utils/errorHandler';
|
||||
import { getToastDuration } from './utils/notificationPreferences';
|
||||
import { parseTaskFileData } from './utils/taskFileReader';
|
||||
import { TaskMasterTask } from './utils/taskMasterApi';
|
||||
|
||||
// Global MCP client manager instance
|
||||
let mcpClient: MCPClientManager | null = null;
|
||||
@@ -39,7 +40,7 @@ interface PollingState {
|
||||
timer?: NodeJS.Timeout;
|
||||
isPolling: boolean;
|
||||
interval: number;
|
||||
lastTaskData?: any[];
|
||||
lastTaskData?: TaskMasterTask[];
|
||||
errorCount: number;
|
||||
maxErrors: number;
|
||||
// Adaptive frequency properties
|
||||
@@ -55,7 +56,7 @@ interface PollingState {
|
||||
reconnectBackoffMultiplier: number;
|
||||
lastSuccessfulConnection?: number;
|
||||
isOfflineMode: boolean;
|
||||
cachedTaskData?: any[];
|
||||
cachedTaskData?: TaskMasterTask[];
|
||||
}
|
||||
|
||||
let pollingState: PollingState = {
|
||||
@@ -351,7 +352,7 @@ function adjustPollingFrequency(): void {
|
||||
// Low activity: reduce polling frequency with exponential backoff
|
||||
const backoffMultiplier = Math.min(
|
||||
4,
|
||||
Math.pow(1.5, pollingState.consecutiveNoChanges - 3)
|
||||
1.5 ** (pollingState.consecutiveNoChanges - 3)
|
||||
);
|
||||
newInterval = Math.min(
|
||||
pollingState.maxInterval,
|
||||
@@ -1031,43 +1032,65 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
case 'readTaskFileData':
|
||||
console.log('📄 Reading task file data:', message.data);
|
||||
const { requestId } = message;
|
||||
try {
|
||||
const { taskId, tag: tagName = 'master' } = message.data;
|
||||
{
|
||||
const { requestId } = message;
|
||||
try {
|
||||
const { taskId, tag: tagName = 'master' } = message.data;
|
||||
|
||||
// Get workspace folder
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
if (!workspaceFolder) {
|
||||
throw new Error('No workspace folder found');
|
||||
}
|
||||
// Get workspace folder
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
if (!workspaceFolder) {
|
||||
throw new Error('No workspace folder found');
|
||||
}
|
||||
|
||||
// Build path to tasks.json
|
||||
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(
|
||||
// Build path to tasks.json
|
||||
const tasksJsonPath = path.join(
|
||||
workspaceFolder.uri.fsPath,
|
||||
'.taskmaster',
|
||||
'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'
|
||||
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,
|
||||
'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(
|
||||
'📖 Read legacy tasks.json, content length:',
|
||||
'📖 Read tasks.json, content length:',
|
||||
content.length
|
||||
);
|
||||
const taskData = parseTaskFileData(
|
||||
@@ -1076,46 +1099,26 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
tagName,
|
||||
workspaceFolder.uri.fsPath
|
||||
);
|
||||
console.log('✅ Parsed task data for legacy path:', taskData);
|
||||
console.log('✅ Parsed task data:', taskData);
|
||||
|
||||
panel.webview.postMessage({
|
||||
type: 'response',
|
||||
requestId,
|
||||
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;
|
||||
|
||||
|
||||
@@ -648,14 +648,14 @@ const TaskEditModal: React.FC<{
|
||||
|
||||
// Only include changed fields
|
||||
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)
|
||||
updates.description = formData.description;
|
||||
if (formData.details !== task.details) updates.details = formData.details;
|
||||
{updates.description = formData.description;}
|
||||
if (formData.details !== task.details) {updates.details = formData.details;}
|
||||
if (formData.priority !== task.priority)
|
||||
updates.priority = formData.priority;
|
||||
{updates.priority = formData.priority;}
|
||||
if (formData.testStrategy !== task.testStrategy)
|
||||
updates.testStrategy = formData.testStrategy;
|
||||
{updates.testStrategy = formData.testStrategy;}
|
||||
if (
|
||||
JSON.stringify(formData.dependencies) !==
|
||||
JSON.stringify(task.dependencies)
|
||||
@@ -875,7 +875,7 @@ const TaskCard: React.FC<{
|
||||
const TaskMasterKanban: React.FC = () => {
|
||||
const context = useContext(VSCodeContext);
|
||||
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 {
|
||||
@@ -984,14 +984,14 @@ const TaskMasterKanban: React.FC = () => {
|
||||
dispatch({ type: 'SET_USER_INTERACTING', payload: false });
|
||||
}, 1000); // 1 second delay to ensure smooth completion
|
||||
|
||||
if (!over) return;
|
||||
if (!over) {return;}
|
||||
|
||||
const taskId = active.id as string;
|
||||
const newStatus = over.id as TaskMasterTask['status'];
|
||||
|
||||
// Find the task that was moved
|
||||
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}`);
|
||||
|
||||
@@ -1382,7 +1382,7 @@ const App: React.FC = () => {
|
||||
|
||||
// Handle messages from extension
|
||||
useEffect(() => {
|
||||
if (!vscode) return;
|
||||
if (!vscode) {return;}
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
const message: WebviewMessage = event.data;
|
||||
@@ -1526,13 +1526,13 @@ const App: React.FC = () => {
|
||||
|
||||
// Map error severity to toast type
|
||||
let toastType: ToastNotification['type'] = 'error';
|
||||
if (errorData.severity === 'low') toastType = 'info';
|
||||
else if (errorData.severity === 'medium') toastType = 'warning';
|
||||
if (errorData.severity === 'low') {toastType = 'info';}
|
||||
else if (errorData.severity === 'medium') {toastType = 'warning';}
|
||||
else if (
|
||||
errorData.severity === 'high' ||
|
||||
errorData.severity === 'critical'
|
||||
)
|
||||
toastType = 'error';
|
||||
{toastType = 'error';}
|
||||
|
||||
// Create appropriate toast based on error category
|
||||
const title =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"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.",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -9,7 +9,10 @@
|
||||
"task-master-mcp": "mcp-server/server.js",
|
||||
"task-master-ai": "mcp-server/server.js"
|
||||
},
|
||||
"workspaces": ["apps/*", "."],
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"."
|
||||
],
|
||||
"scripts": {
|
||||
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
||||
"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