feat(extension): add VS Code extension with kanban board interface

- 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
- Comprehensive configuration system with user preferences
- ShadCN UI components with VS Code theme integration
- Drag-and-drop task management with status transitions
- AI-powered task features via MCP protocol
- Robust error handling and connection management
- Multi-registry publishing (VS Code Marketplace + Open VSX)
- Security audit completed with hardcoded paths removed

BREAKING CHANGE: Extension requires publisher setup and marketplace keys

Publisher and extension naming decisions required:
- Update publisher field from placeholder 'DavidMaliglowka'
- Choose unique extension name (currently 'taskr-kanban')
- Select appropriate extension icon
- Configure CI secrets (VSCE_PAT, OVSX_PAT) for publishing

See apps/extension/docs/ for detailed setup instructions
This commit is contained in:
DavidMaliglowka
2025-07-17 04:36:36 -05:00
parent fc81d574d0
commit 8e59647229
47 changed files with 24477 additions and 176 deletions

203
.github/workflows/extension-ci.yml vendored Normal file
View File

@@ -0,0 +1,203 @@
name: Extension CI
on:
push:
branches:
- main
- next
paths:
- 'apps/extension/**'
- '.github/workflows/extension-ci.yml'
pull_request:
branches:
- main
- next
paths:
- 'apps/extension/**'
- '.github/workflows/extension-ci.yml'
permissions:
contents: read
jobs:
setup:
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: latest
- name: Generate cache key
id: cache-key
run: echo "key=${{ runner.os }}-extension-pnpm-${{ hashFiles('apps/extension/pnpm-lock.yaml') }}" >> $GITHUB_OUTPUT
- name: Cache pnpm dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
apps/extension/node_modules
key: ${{ steps.cache-key.outputs.key }}
restore-keys: |
${{ runner.os }}-extension-pnpm-
- name: Install Extension Dependencies
working-directory: apps/extension
run: pnpm install --frozen-lockfile
timeout-minutes: 5
lint-and-typecheck:
needs: setup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: latest
- name: Restore pnpm dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
apps/extension/node_modules
key: ${{ needs.setup.outputs.cache-key }}
- name: Install if cache miss
working-directory: apps/extension
run: pnpm install --frozen-lockfile --prefer-offline
timeout-minutes: 3
- name: Lint Extension
working-directory: apps/extension
run: pnpm run lint
env:
FORCE_COLOR: 1
- name: Type Check Extension
working-directory: apps/extension
run: pnpm run check-types
env:
FORCE_COLOR: 1
build:
needs: setup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: latest
- name: Restore pnpm dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
apps/extension/node_modules
key: ${{ needs.setup.outputs.cache-key }}
- name: Install if cache miss
working-directory: apps/extension
run: pnpm install --frozen-lockfile --prefer-offline
timeout-minutes: 3
- name: Build Extension
working-directory: apps/extension
run: pnpm run build
env:
FORCE_COLOR: 1
- name: Package Extension
working-directory: apps/extension
run: pnpm run package
env:
FORCE_COLOR: 1
- name: Verify Package Contents
working-directory: apps/extension
run: |
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
- name: Create VSIX Package (Test)
working-directory: apps/extension/vsix-build
run: pnpm exec vsce package --no-dependencies
env:
FORCE_COLOR: 1
- name: Upload Extension Artifact
uses: actions/upload-artifact@v4
with:
name: extension-package
path: |
apps/extension/vsix-build/*.vsix
apps/extension/dist/
retention-days: 30
test:
needs: setup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: latest
- name: Restore pnpm dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
apps/extension/node_modules
key: ${{ needs.setup.outputs.cache-key }}
- name: Install if cache miss
working-directory: apps/extension
run: pnpm install --frozen-lockfile --prefer-offline
timeout-minutes: 3
- name: Run Extension Tests
working-directory: apps/extension
run: xvfb-run -a pnpm run test
env:
CI: true
FORCE_COLOR: 1
timeout-minutes: 10
- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: extension-test-results
path: apps/extension/test-results
retention-days: 30

240
.github/workflows/extension-release.yml vendored Normal file
View File

@@ -0,0 +1,240 @@
name: Extension Release
on:
push:
branches:
- main
paths:
- 'apps/extension/**'
workflow_dispatch:
inputs:
force_publish:
description: 'Force publish even without version changes'
required: false
default: false
type: boolean
permissions:
contents: read
concurrency: extension-release-${{ github.ref }}
jobs:
check-version:
runs-on: ubuntu-latest
outputs:
should-publish: ${{ steps.version-check.outputs.should-publish }}
current-version: ${{ steps.version-check.outputs.current-version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check version changes
id: version-check
run: |
# Get current version from package.json
CURRENT_VERSION=$(jq -r '.version' apps/extension/package.json)
echo "current-version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
# Check if this is a force publish
if [ "${{ github.event.inputs.force_publish }}" = "true" ]; then
echo "should-publish=true" >> $GITHUB_OUTPUT
echo "Force publish requested"
exit 0
fi
# Check if version changed in the last commit
if git diff HEAD~1 HEAD --name-only | grep -q "apps/extension/package.json\|apps/extension/package.publish.json"; then
# Check if version field actually changed
PREV_VERSION=$(git show HEAD~1:apps/extension/package.json | jq -r '.version')
if [ "$CURRENT_VERSION" != "$PREV_VERSION" ]; then
echo "should-publish=true" >> $GITHUB_OUTPUT
echo "Version changed from $PREV_VERSION to $CURRENT_VERSION"
else
echo "should-publish=false" >> $GITHUB_OUTPUT
echo "No version change detected"
fi
else
echo "should-publish=false" >> $GITHUB_OUTPUT
echo "No package.json changes detected"
fi
build-and-publish:
needs: check-version
if: needs.check-version.outputs.should-publish == 'true'
runs-on: ubuntu-latest
environment: extension-release
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
with:
version: latest
- name: Cache pnpm dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
apps/extension/node_modules
key: ${{ runner.os }}-extension-pnpm-${{ hashFiles('apps/extension/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-extension-pnpm-
- name: Install Extension Dependencies
working-directory: apps/extension
run: pnpm install --frozen-lockfile
timeout-minutes: 5
- name: Run Tests
working-directory: apps/extension
run: xvfb-run -a pnpm run test
env:
CI: true
FORCE_COLOR: 1
timeout-minutes: 10
- name: Lint Extension
working-directory: apps/extension
run: pnpm run lint
env:
FORCE_COLOR: 1
- name: Type Check Extension
working-directory: apps/extension
run: pnpm run check-types
env:
FORCE_COLOR: 1
- name: Build Extension
working-directory: apps/extension
run: pnpm run build
env:
FORCE_COLOR: 1
- name: Package Extension
working-directory: apps/extension
run: pnpm run package
env:
FORCE_COLOR: 1
- name: Verify Package Structure
working-directory: apps/extension
run: |
echo "=== Checking vsix-build structure ==="
ls -la vsix-build/
echo "=== Checking dist contents ==="
ls -la vsix-build/dist/
echo "=== Verifying required files ==="
test -f vsix-build/package.json || (echo "Missing package.json" && exit 1)
test -f vsix-build/dist/extension.js || (echo "Missing extension.js" && exit 1)
echo "=== Checking package.json content ==="
cat vsix-build/package.json | jq '.name, .version, .publisher'
- name: Create VSIX Package
working-directory: apps/extension/vsix-build
run: pnpm exec vsce package --no-dependencies
env:
FORCE_COLOR: 1
- name: Get VSIX filename
id: vsix-info
working-directory: apps/extension/vsix-build
run: |
VSIX_FILE=$(ls *.vsix)
echo "vsix-filename=$VSIX_FILE" >> $GITHUB_OUTPUT
echo "Found VSIX: $VSIX_FILE"
- name: Validate VSIX Package
working-directory: apps/extension/vsix-build
run: |
echo "=== VSIX Package Contents ==="
unzip -l "${{ steps.vsix-info.outputs.vsix-filename }}"
- name: Publish to VS Code Marketplace
working-directory: apps/extension/vsix-build
run: pnpm exec vsce publish --packagePath "${{ steps.vsix-info.outputs.vsix-filename }}"
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
FORCE_COLOR: 1
- name: Install Open VSX CLI
run: npm install -g ovsx
- name: Publish to Open VSX Registry
working-directory: apps/extension/vsix-build
run: ovsx publish "${{ steps.vsix-info.outputs.vsix-filename }}"
env:
OVSX_PAT: ${{ secrets.OVSX_PAT }}
FORCE_COLOR: 1
- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: extension-v${{ needs.check-version.outputs.current-version }}
release_name: Extension v${{ needs.check-version.outputs.current-version }}
body: |
VS Code Extension Release v${{ needs.check-version.outputs.current-version }}
**Changes in this release:**
- Published to VS Code Marketplace
- Published to Open VSX Registry
- Extension package: `${{ steps.vsix-info.outputs.vsix-filename }}`
**Installation:**
- Install from VS Code Marketplace: [Task Master Kanban](https://marketplace.visualstudio.com/items?itemName=[TBD])
- Install from Open VSX Registry: [Task Master Kanban](https://open-vsx.org/extension/[TBD])
- Or download the VSIX file below and install manually
draft: false
prerelease: false
- name: Upload VSIX to Release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: apps/extension/vsix-build/${{ steps.vsix-info.outputs.vsix-filename }}
asset_name: ${{ steps.vsix-info.outputs.vsix-filename }}
asset_content_type: application/zip
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: extension-release-v${{ needs.check-version.outputs.current-version }}
path: |
apps/extension/vsix-build/*.vsix
apps/extension/dist/
retention-days: 90
notify-success:
needs: [check-version, build-and-publish]
if: success() && needs.check-version.outputs.should-publish == 'true'
runs-on: ubuntu-latest
steps:
- name: Success Notification
run: |
echo "🎉 Extension v${{ needs.check-version.outputs.current-version }} successfully published!"
echo "📦 Available on VS Code Marketplace"
echo "🌍 Available on Open VSX Registry"
echo "🏷️ GitHub release created: extension-v${{ needs.check-version.outputs.current-version }}"
notify-skipped:
needs: check-version
if: needs.check-version.outputs.should-publish == 'false'
runs-on: ubuntu-latest
steps:
- name: Skip Notification
run: |
echo " Extension publish skipped - no version changes detected"
echo "Current version: ${{ needs.check-version.outputs.current-version }}"
echo "To force publish, use workflow_dispatch with force_publish=true"