This is page 1 of 15. Use http://codebase.md/pimzino/spec-workflow-mcp?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .dockerignore
├── .gitattributes
├── .github
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── dashboard_issue.yml
│ │ ├── documentation.yml
│ │ ├── feature_request.yml
│ │ └── vscode_extension.yml
│ └── workflows
│ ├── claude-code-review.yml
│ └── claude.yml
├── .gitignore
├── CHANGELOG.md
├── containers
│ ├── .env.example
│ ├── DOCKER_USAGE.md
│ ├── docker-compose.yml
│ ├── Dockerfile
│ ├── example.mcp.json
│ └── README.md
├── docs
│ ├── CONFIGURATION.md
│ ├── DEVELOPMENT.md
│ ├── INTERFACES.md
│ ├── PROMPTING-GUIDE.md
│ ├── technical-documentation
│ │ ├── api-reference.md
│ │ ├── architecture.md
│ │ ├── context-management.md
│ │ ├── contributing.md
│ │ ├── dashboard.md
│ │ ├── developer-guide.md
│ │ ├── file-structure.md
│ │ ├── i18n-guide.md
│ │ ├── i18n-structure.md
│ │ ├── README.md
│ │ └── troubleshooting.md
│ ├── TOOLS-REFERENCE.md
│ ├── TROUBLESHOOTING.md
│ ├── USER-GUIDE.md
│ └── WORKFLOW.md
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── scripts
│ ├── copy-static.cjs
│ └── validate-i18n.js
├── src
│ ├── config.ts
│ ├── core
│ │ ├── archive-service.ts
│ │ ├── dashboard-session.ts
│ │ ├── implementation-log-migrator.ts
│ │ ├── parser.ts
│ │ ├── path-utils.ts
│ │ ├── project-registry.ts
│ │ ├── task-parser.ts
│ │ └── workspace-initializer.ts
│ ├── dashboard
│ │ ├── approval-storage.ts
│ │ ├── execution-history-manager.ts
│ │ ├── implementation-log-manager.ts
│ │ ├── job-scheduler.ts
│ │ ├── multi-server.ts
│ │ ├── parser.ts
│ │ ├── project-manager.ts
│ │ ├── public
│ │ │ ├── claude-icon-dark.svg
│ │ │ └── claude-icon.svg
│ │ ├── settings-manager.ts
│ │ ├── utils.ts
│ │ └── watcher.ts
│ ├── dashboard_frontend
│ │ ├── index.html
│ │ ├── src
│ │ │ ├── components
│ │ │ │ ├── I18nErrorBoundary.tsx
│ │ │ │ └── LanguageSelector.tsx
│ │ │ ├── i18n-dynamic.ts
│ │ │ ├── i18n.ts
│ │ │ ├── lib
│ │ │ │ └── utils.ts
│ │ │ ├── locales
│ │ │ │ ├── ar.json
│ │ │ │ ├── de.json
│ │ │ │ ├── en.json
│ │ │ │ ├── es.json
│ │ │ │ ├── fr.json
│ │ │ │ ├── it.json
│ │ │ │ ├── ja.json
│ │ │ │ ├── ko.json
│ │ │ │ ├── pt.json
│ │ │ │ ├── ru.json
│ │ │ │ └── zh.json
│ │ │ ├── main.tsx
│ │ │ ├── modules
│ │ │ │ ├── api
│ │ │ │ │ └── api.tsx
│ │ │ │ ├── app
│ │ │ │ │ └── App.tsx
│ │ │ │ ├── approvals
│ │ │ │ │ ├── ApprovalsAnnotator.tsx
│ │ │ │ │ └── colors.ts
│ │ │ │ ├── components
│ │ │ │ │ ├── KanbanBoard.tsx
│ │ │ │ │ ├── KanbanTaskCard.tsx
│ │ │ │ │ ├── PageNavigationSidebar.tsx
│ │ │ │ │ ├── ProjectDropdown.tsx
│ │ │ │ │ ├── SortDropdown.tsx
│ │ │ │ │ └── StatusFilterPills.tsx
│ │ │ │ ├── diff
│ │ │ │ │ ├── DiffStats.tsx
│ │ │ │ │ ├── DiffViewer.tsx
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── editor
│ │ │ │ │ └── MarkdownEditor.tsx
│ │ │ │ ├── markdown
│ │ │ │ │ └── Markdown.tsx
│ │ │ │ ├── modals
│ │ │ │ │ ├── AlertModal.tsx
│ │ │ │ │ ├── ChangelogModal.tsx
│ │ │ │ │ ├── ConfirmationModal.tsx
│ │ │ │ │ └── TextInputModal.tsx
│ │ │ │ ├── notifications
│ │ │ │ │ ├── NotificationProvider.tsx
│ │ │ │ │ ├── VolumeControl.module.css
│ │ │ │ │ └── VolumeControl.tsx
│ │ │ │ ├── pages
│ │ │ │ │ ├── ApprovalsPage.tsx
│ │ │ │ │ ├── DashboardStatistics.tsx
│ │ │ │ │ ├── JobExecutionHistory.tsx
│ │ │ │ │ ├── JobFormModal.tsx
│ │ │ │ │ ├── JobTemplates.ts
│ │ │ │ │ ├── LogsPage.tsx
│ │ │ │ │ ├── SettingsPage.tsx
│ │ │ │ │ ├── SpecsPage.tsx
│ │ │ │ │ ├── SpecViewerPage.tsx
│ │ │ │ │ ├── SteeringPage.tsx
│ │ │ │ │ └── TasksPage.tsx
│ │ │ │ ├── projects
│ │ │ │ │ └── ProjectProvider.tsx
│ │ │ │ ├── theme
│ │ │ │ │ ├── HighlightStyles.tsx
│ │ │ │ │ ├── tailwind.css
│ │ │ │ │ ├── theme.css
│ │ │ │ │ └── ThemeProvider.tsx
│ │ │ │ └── ws
│ │ │ │ └── WebSocketProvider.tsx
│ │ │ └── types.ts
│ │ └── vite.config.ts
│ ├── index.ts
│ ├── markdown
│ │ └── templates
│ │ ├── design-template.md
│ │ ├── product-template.md
│ │ ├── requirements-template.md
│ │ ├── structure-template.md
│ │ ├── tasks-template.md
│ │ └── tech-template.md
│ ├── prompts
│ │ ├── create-spec.ts
│ │ ├── create-steering-doc.ts
│ │ ├── implement-task.ts
│ │ ├── index.ts
│ │ ├── inject-spec-workflow-guide.ts
│ │ ├── inject-steering-guide.ts
│ │ ├── refresh-tasks.ts
│ │ ├── spec-status.ts
│ │ └── types.ts
│ ├── server.ts
│ ├── tools
│ │ ├── __tests__
│ │ │ └── projectPath.test.ts
│ │ ├── approvals.ts
│ │ ├── index.ts
│ │ ├── log-implementation.ts
│ │ ├── spec-status.ts
│ │ ├── spec-workflow-guide.ts
│ │ └── steering-guide.ts
│ └── types.ts
├── tsconfig.json
├── vitest.config.ts
└── vscode-extension
├── .gitignore
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .vscode-test.mjs
├── .vscodeignore
├── CHANGELOG.md
├── components.json
├── esbuild.js
├── eslint.config.mjs
├── icon.png
├── icons
│ ├── activity-bar-icon.svg
│ └── spec-workflow.svg
├── LICENSE
├── package-lock.json
├── package.json
├── package.nls.ja.json
├── package.nls.json
├── package.nls.zh.json
├── README.md
├── src
│ ├── extension
│ │ ├── providers
│ │ │ └── SidebarProvider.ts
│ │ ├── services
│ │ │ ├── ApprovalCommandService.ts
│ │ │ ├── ApprovalEditorService.ts
│ │ │ ├── ArchiveService.ts
│ │ │ ├── CommentModalService.ts
│ │ │ ├── FileWatcher.ts
│ │ │ ├── ImplementationLogService.ts
│ │ │ └── SpecWorkflowService.ts
│ │ ├── types.ts
│ │ └── utils
│ │ ├── colorUtils.ts
│ │ ├── logger.ts
│ │ └── taskParser.ts
│ ├── extension.ts
│ ├── test
│ │ ├── extension.test.ts
│ │ └── pathResolution.test.ts
│ └── webview
│ ├── App.tsx
│ ├── comment-modal.html
│ ├── comment-modal.tsx
│ ├── components
│ │ ├── ArtifactSection.tsx
│ │ ├── CommentModal.tsx
│ │ ├── LogEntryCard.tsx
│ │ ├── LogStatsPanel.tsx
│ │ └── ui
│ │ ├── accordion.tsx
│ │ ├── badge.tsx
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── input.tsx
│ │ ├── progress.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ └── tabs.tsx
│ ├── globals.css
│ ├── hooks
│ │ ├── useSoundNotifications.ts
│ │ └── useVSCodeTheme.ts
│ ├── i18n.ts
│ ├── index.html
│ ├── lib
│ │ ├── utils.ts
│ │ └── vscode-api.ts
│ ├── locales
│ │ ├── ar.json
│ │ ├── de.json
│ │ ├── en.json
│ │ ├── es.json
│ │ ├── fr.json
│ │ ├── it.json
│ │ ├── ja.json
│ │ ├── ko.json
│ │ ├── pt.json
│ │ ├── ru.json
│ │ └── zh.json
│ ├── main.tsx
│ ├── pages
│ │ └── LogsPage.tsx
│ └── vite-env.d.ts
├── tailwind.config.js
├── tsconfig.app.json
├── tsconfig.extension.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
├── webview-assets
│ └── sounds
│ ├── approval-pending.wav
│ └── task-completed.wav
└── webview-dist
├── comment-modal.html
├── comment-modal.js
├── globals.css
├── i18n.js
├── index.html
├── locales
│ ├── ar.json
│ ├── de.json
│ ├── en.json
│ ├── es.json
│ ├── fr.json
│ ├── it.json
│ ├── ja.json
│ ├── ko.json
│ ├── pt.json
│ ├── ru.json
│ └── zh.json
├── main.js
└── sounds
├── approval-pending.wav
└── task-completed.wav
```
# Files
--------------------------------------------------------------------------------
/vscode-extension/.gitignore:
--------------------------------------------------------------------------------
```
1 | out
2 | dist
3 | node_modules
4 | .vscode-test/
5 | *.vsix
6 |
```
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
```
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
```
--------------------------------------------------------------------------------
/vscode-extension/.vscode-test.mjs:
--------------------------------------------------------------------------------
```
1 | import { defineConfig } from '@vscode/test-cli';
2 |
3 | export default defineConfig({
4 | files: 'out/test/**/*.test.js',
5 | });
6 |
```
--------------------------------------------------------------------------------
/vscode-extension/.vscodeignore:
--------------------------------------------------------------------------------
```
1 | .vscode/**
2 | .vscode-test/**
3 | out/**
4 | node_modules/**
5 | src/**
6 | .gitignore
7 | .yarnrc
8 | esbuild.js
9 | vsc-extension-quickstart.md
10 | **/tsconfig.json
11 | **/eslint.config.mjs
12 | **/*.map
13 | **/*.ts
14 | **/.vscode-test.*
15 | !webview-dist/**
16 | !package.nls.*.json
17 |
```
--------------------------------------------------------------------------------
/containers/.env.example:
--------------------------------------------------------------------------------
```
1 | # Dashboard Configuration
2 | # Default port for the dashboard (change if 5000 is in use)
3 | DASHBOARD_PORT=5000
4 |
5 | # Path to your project directory
6 | # This should be the directory containing (or where you want to create) .spec-workflow
7 | SPEC_WORKFLOW_PATH=./workspace
8 |
```
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
```
1 | # Dependencies
2 | node_modules
3 | npm-debug.log
4 |
5 | # Build artifacts
6 | dist
7 | .next
8 | out
9 |
10 | # IDE and editor files
11 | .vscode
12 | .idea
13 | *.swp
14 | *.swo
15 | *~
16 |
17 | # OS files
18 | .DS_Store
19 | Thumbs.db
20 |
21 | # Git
22 | .git
23 | .gitignore
24 | .gitattributes
25 |
26 | # Testing
27 | coverage
28 | .nyc_output
29 |
30 | # Documentation (not needed in container)
31 | docs
32 | *.md
33 | !containers/README.md
34 |
35 | # CI/CD
36 | .github
37 |
38 | # Environment files
39 | .env
40 | .env.*
41 |
42 | # VSCode extension
43 | vscode-extension
44 |
45 | # Temporary files
46 | tmp
47 | temp
48 | *.tmp
49 | .spec-workflow
50 |
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 | .pnpm-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Snowpack dependency directory (https://snowpack.dev/)
46 | web_modules/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Optional stylelint cache
58 | .stylelintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variable files
76 | .env
77 | .env.development.local
78 | .env.test.local
79 | .env.production.local
80 | .env.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 | out
89 |
90 | # Nuxt.js build / generate output
91 | .nuxt
92 | dist
93 |
94 | # Gatsby files
95 | .cache/
96 | # Comment in the public line in if your project uses Gatsby and not Next.js
97 | # https://nextjs.org/blog/next-9-1#public-directory-support
98 | # public
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # vuepress v2.x temp and cache directory
104 | .temp
105 | .cache
106 |
107 | # vitepress build output
108 | **/.vitepress/dist
109 |
110 | # vitepress cache directory
111 | **/.vitepress/cache
112 |
113 | # Docusaurus cache and generated files
114 | .docusaurus
115 |
116 | # Serverless directories
117 | .serverless/
118 |
119 | # FuseBox cache
120 | .fusebox/
121 |
122 | # DynamoDB Local files
123 | .dynamodb/
124 |
125 | # TernJS port file
126 | .tern-port
127 |
128 | # Stores VSCode versions used for testing VSCode extensions
129 | .vscode-test
130 |
131 | # yarn v2
132 | .yarn/cache
133 | .yarn/unplugged
134 | .yarn/build-state.yml
135 | .yarn/install-state.gz
136 | .pnp.*
137 |
138 | # AI
139 | CLAUDE.md
140 | .claude
141 | .serena
142 | AGENTS.md
143 | opencodetmp
144 |
145 | # Spec Workflow MCP
146 | .specworkflow
```
--------------------------------------------------------------------------------
/vscode-extension/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Spec Workflow MCP Extension
2 |
3 | A VSCode extension that provides an integrated dashboard for managing Spec-Workflow MCP projects directly in your workspace.
4 |
5 | ## Features
6 |
7 | - **Integrated Sidebar Dashboard**: Access all your spec workflow data without leaving VSCode
8 | - **Real-time Updates**: File system watchers automatically update the dashboard when .spec-workflow files change
9 | - **Project Overview**: Comprehensive statistics showing active vs archived specs, tasks, and approvals
10 | - **Spec Management**: Browse active and archived specifications with easy archiving/unarchiving
11 | - **Task Management**: View and update task statuses directly from the sidebar
12 | - **Approval Workflow**: Complete approval process with approve, reject, and revision requests
13 | - **Steering Documents**: Manage product, tech, and structure steering documents
14 | - **Sound Notifications**: Configurable audio alerts for approvals and task completions
15 | - **Editor Integration**: Context menu actions for approvals and comments directly in code
16 | - **React + Tailwind UI**: Modern, responsive interface built with React 19 and Tailwind CSS v4
17 |
18 | ## Requirements
19 |
20 | - VSCode 1.99.0 or higher
21 | - A workspace containing a `.spec-workflow` directory structure
22 |
23 | ## Usage
24 |
25 | 1. Open a workspace that contains a `.spec-workflow` directory
26 | 2. The Spec Workflow MCP icon will appear in the Activity Bar
27 | 3. Click the icon to open the dashboard sidebar
28 | 4. Use the tabbed interface to navigate between:
29 | - **Overview**: Project statistics showing active/archived specs breakdown and recent activity
30 | - **Steering**: Manage steering documents (product, tech, structure)
31 | - **Specs**: Browse active and archived specifications with archive management
32 | - **Tasks**: View and manage task progress for selected specifications
33 | - **Approvals**: Handle pending approval requests with full workflow support
34 |
35 | ## Archive Management
36 |
37 | Specifications can be archived to keep dropdown menus clean and organized:
38 | - Switch between **Active** and **Archived** views in the Specs tab
39 | - Archive completed specifications to remove them from active dropdowns
40 | - Unarchive specifications when needed
41 | - Archive operations are blocked if pending approvals exist for the specification
42 |
43 | ## Commands
44 |
45 | - `Spec Workflow: Open Dashboard` - Opens the sidebar dashboard
46 | - `Spec Workflow: Refresh Data` - Manually refresh all data
47 | - `Spec Workflow: Open Spec` - Quick pick to open specific specifications
48 | - `Spec Workflow: Approve` - Approve current document (editor context)
49 | - `Spec Workflow: Reject` - Reject current document (editor context)
50 | - `Spec Workflow: Request Revision` - Request revision for current document
51 | - `Spec Workflow: Add Comment` - Add comment to selected text
52 | - `Spec Workflow: Approval Actions` - Show approval action menu
53 |
54 | ## Extension Settings
55 |
56 | - `specWorkflow.notifications.sounds.enabled` - Enable sound notifications (default: true)
57 | - `specWorkflow.notifications.sounds.volume` - Sound volume level 0.0-1.0 (default: 0.3)
58 | - `specWorkflow.notifications.sounds.approvalSound` - Play sound for approval requests (default: true)
59 | - `specWorkflow.notifications.sounds.taskCompletionSound` - Play sound for task completions (default: true)
60 |
61 | ## Development
62 |
63 | This extension is built with:
64 | - React 19 with TypeScript
65 | - Vite for webview bundling
66 | - Tailwind CSS v4 for styling
67 | - ShadCN UI components
68 | - VSCode Extension API
69 |
70 | ## Release Notes
71 |
72 | ### 0.0.1
73 |
74 | Initial release of Spec Workflow MCP Extension:
75 | - **Dashboard Integration**: Complete sidebar dashboard with real-time updates
76 | - **Specification Management**: Active/archived spec organization with archive workflow
77 | - **Task Tracking**: Interactive task management with status updates
78 | - **Approval System**: Full approval workflow with approve/reject/revision capabilities
79 | - **Steering Documents**: Product, tech, and structure document management
80 | - **Sound Notifications**: Configurable audio alerts for key events
81 | - **Editor Integration**: Context menu actions and comment system
82 | - **Modern UI**: React 19 + Tailwind CSS v4 with responsive design
83 |
84 | ## Support
85 |
86 | If you find this extension helpful, consider supporting the development:
87 |
88 | [☕ Buy Me a Coffee](https://buymeacoffee.com/pimzino)
89 |
90 | ## License
91 |
92 | This project is licensed under the GPL-3.0 License.
```
--------------------------------------------------------------------------------
/containers/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Spec-Workflow MCP Docker Setup
2 |
3 | This directory contains Docker configuration files to run the Spec-Workflow MCP dashboard in a containerized environment. This setup provides isolation and easy deployment for the dashboard service.
4 |
5 | ## 📋 Table of Contents
6 |
7 | - [Prerequisites](#prerequisites)
8 | - [Quick Start](#quick-start)
9 | - [Building the Image](#building-the-image)
10 | - [Running the Dashboard](#running-the-dashboard)
11 | - [Using Docker Compose](#using-docker-compose)
12 | - [Configuration Options](#configuration-options)
13 | - [Troubleshooting](#troubleshooting)
14 |
15 | ## Prerequisites
16 |
17 | - Docker (version 20.10 or later)
18 | - Docker Compose (optional, for simplified management)
19 | - A project directory where you want to use spec-workflow
20 |
21 | ## Quick Start
22 |
23 | ### Option 1: Using Docker Compose (Recommended)
24 |
25 | The easiest way to get started is with Docker Compose:
26 |
27 | ```bash
28 | # From the repository root
29 | cd containers
30 | docker-compose up --build
31 | ```
32 |
33 | The dashboard will be available at: http://localhost:5000
34 |
35 | ### Option 2: Using Docker CLI
36 |
37 | Build and run manually:
38 |
39 | ```bash
40 | # From the repository root
41 | docker build -f containers/Dockerfile -t spec-workflow-mcp .
42 | docker run -p 5000:5000 -v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw" spec-workflow-mcp
43 | ```
44 |
45 | ## Building the Image
46 |
47 | ### Build from Repository Root
48 |
49 | **Important:** The Dockerfile must be built from the repository root directory, not from the `containers` directory, because it needs access to the source code.
50 |
51 | ```bash
52 | # From the repository root
53 | docker build -f containers/Dockerfile -t spec-workflow-mcp .
54 | ```
55 |
56 | ### Build Arguments
57 |
58 | The image is built in two stages:
59 | 1. **Builder stage**: Installs dependencies and builds the TypeScript application
60 | 2. **Runtime stage**: Creates a minimal production image with only necessary files
61 |
62 | ## Running the Dashboard
63 |
64 | ### Basic Usage
65 |
66 | Run the dashboard on the default port (5000):
67 |
68 | ```bash
69 | docker run -p 5000:5000 \
70 | -v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw" \
71 | spec-workflow-mcp
72 | ```
73 |
74 | ### Custom Port
75 |
76 | Run the dashboard on a custom port (e.g., 8080):
77 |
78 | ```bash
79 | docker run -p 8080:8080 \
80 | -e DASHBOARD_PORT=8080 \
81 | -v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw" \
82 | spec-workflow-mcp
83 | ```
84 |
85 | ### Using a Specific Project Path
86 |
87 | Mount your project's `.spec-workflow` directory:
88 |
89 | ```bash
90 | docker run -p 5000:5000 \
91 | -v "/path/to/your/project/.spec-workflow:/workspace/.spec-workflow:rw" \
92 | spec-workflow-mcp
93 | ```
94 |
95 | ## Using Docker Compose
96 |
97 | Docker Compose simplifies the management of the dashboard container.
98 |
99 | ### Default Configuration
100 |
101 | Create a `.env` file (optional):
102 |
103 | ```bash
104 | # .env file
105 | DASHBOARD_PORT=5000
106 | SPEC_WORKFLOW_PATH=./workspace
107 | ```
108 |
109 | Then start the dashboard:
110 |
111 | ```bash
112 | cd containers
113 | docker-compose up -d
114 | ```
115 |
116 | ### Custom Configuration
117 |
118 | Override environment variables when starting:
119 |
120 | ```bash
121 | DASHBOARD_PORT=8080 SPEC_WORKFLOW_PATH=/path/to/project docker-compose up -d
122 | ```
123 |
124 | ### Managing the Service
125 |
126 | ```bash
127 | # Start the dashboard
128 | docker-compose up -d
129 |
130 | # View logs
131 | docker-compose logs -f
132 |
133 | # Stop the dashboard
134 | docker-compose down
135 |
136 | # Rebuild and restart
137 | docker-compose up --build
138 | ```
139 |
140 | ## Configuration Options
141 |
142 | ### Environment Variables
143 |
144 | | Variable | Default | Description |
145 | |----------|---------|-------------|
146 | | `DASHBOARD_PORT` | `5000` | Port on which the dashboard runs |
147 | | `SPEC_WORKFLOW_PATH` | `/workspace` | Path to the project directory (inside container) |
148 |
149 | ### Volume Mounts
150 |
151 | The dashboard requires access to the `.spec-workflow` directory to function properly.
152 |
153 | **Example:**
154 | ```bash
155 | -v "/path/to/project/.spec-workflow:/workspace/.spec-workflow:rw"
156 | ```
157 |
158 | **Important Notes:**
159 | - The volume mount must be read-write (`:rw`) for the dashboard to function
160 | - Only the `.spec-workflow` directory needs to be mounted
161 | - The directory will be created automatically if it doesn't exist
162 |
163 | ### Port Mapping
164 |
165 | Map the container port to a host port:
166 |
167 | ```bash
168 | -p <host-port>:<container-port>
169 | ```
170 |
171 | **Examples:**
172 | - Default: `-p 5000:5000`
173 | - Custom: `-p 8080:8080` (remember to set `DASHBOARD_PORT=8080`)
174 |
175 | ## MCP Server Configuration
176 |
177 | The dashboard runs independently of MCP servers. To connect MCP servers to the dashboard:
178 |
179 | ### For Claude Desktop
180 |
181 | Add to your `claude_desktop_config.json`:
182 |
183 | ```json
184 | {
185 | "mcpServers": {
186 | "spec-workflow": {
187 | "command": "npx",
188 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
189 | }
190 | }
191 | }
192 | ```
193 |
194 | **Note:** The MCP server runs on your host machine and connects to the Docker dashboard automatically via port 5000.
195 |
196 | ### For Other MCP Clients
197 |
198 | Use similar configuration with the appropriate MCP client settings. The MCP servers run independently and connect to the dashboard's WebSocket endpoint.
199 |
200 | ## Troubleshooting
201 |
202 | ### Common Issues
203 |
204 | #### 1. Port Already in Use
205 |
206 | **Error:** `Bind for 0.0.0.0:5000 failed: port is already allocated`
207 |
208 | **Solution:** Use a different port:
209 | ```bash
210 | docker run -p 8080:8080 -e DASHBOARD_PORT=8080 ...
211 | # or with docker-compose
212 | DASHBOARD_PORT=8080 docker-compose up
213 | ```
214 |
215 | #### 2. Permission Denied
216 |
217 | **Error:** Permission issues with `.spec-workflow` directory
218 |
219 | **Solutions:**
220 | - Ensure the directory has proper permissions: `chmod -R 755 .spec-workflow`
221 | - On SELinux systems, add `:z` to the volume mount: `-v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw,z"`
222 |
223 | #### 3. Dashboard Not Accessible
224 |
225 | **Check:**
226 | - Container is running: `docker ps`
227 | - Port is properly mapped: `docker port <container-id>`
228 | - Firewall allows connections on the port
229 | - Access via: `http://localhost:5000` (or your custom port)
230 |
231 | #### 4. Build Fails
232 |
233 | **Error:** Build fails with COPY or dependency errors
234 |
235 | **Solutions:**
236 | - Ensure you're building from the repository root: `docker build -f containers/Dockerfile -t spec-workflow-mcp .`
237 | - Check that all source files are present
238 | - Verify `package.json` and `package-lock.json` exist
239 |
240 | ### Viewing Logs
241 |
242 | #### Docker CLI
243 | ```bash
244 | docker logs <container-id>
245 | docker logs -f <container-id> # Follow logs
246 | ```
247 |
248 | #### Docker Compose
249 | ```bash
250 | docker-compose logs
251 | docker-compose logs -f # Follow logs
252 | ```
253 |
254 | ### Inspecting the Container
255 |
256 | ```bash
257 | # View container details
258 | docker inspect <container-id>
259 |
260 | # Access container shell
261 | docker exec -it <container-id> /bin/sh
262 | ```
263 |
264 | ## Advanced Configuration
265 |
266 | ### Running in Detached Mode
267 |
268 | ```bash
269 | docker run -d \
270 | --name spec-workflow-dashboard \
271 | -p 5000:5000 \
272 | -v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw" \
273 | spec-workflow-mcp
274 | ```
275 |
276 | ### Auto-Restart on Failure
277 |
278 | ```bash
279 | docker run -d \
280 | --name spec-workflow-dashboard \
281 | --restart unless-stopped \
282 | -p 5000:5000 \
283 | -v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw" \
284 | spec-workflow-mcp
285 | ```
286 |
287 | ### Health Checks
288 |
289 | The dashboard doesn't currently include health checks, but you can test connectivity:
290 |
291 | ```bash
292 | curl http://localhost:5000
293 | ```
294 |
295 | ## Security Considerations
296 |
297 | - The container runs as a non-root user (`node`) for security
298 | - Only expose necessary ports
299 | - Use read-only volume mounts where possible (though `:rw` is required for `.spec-workflow`)
300 | - Keep the base image updated: `docker pull node:24-alpine`
301 |
302 | ## Performance Tips
303 |
304 | - The container is optimized for production with:
305 | - Multi-stage builds to minimize image size
306 | - Only production dependencies in final image
307 | - Alpine Linux for small footprint
308 |
309 | - Monitor resource usage:
310 | ```bash
311 | docker stats <container-id>
312 | ```
313 |
314 | ## Additional Resources
315 |
316 | - [Main Documentation](../README.md)
317 | - [User Guide](../docs/USER-GUIDE.md)
318 | - [Troubleshooting Guide](../docs/TROUBLESHOOTING.md)
319 | - [GitHub Repository](https://github.com/Pimzino/spec-workflow-mcp)
320 |
321 | ## Support
322 |
323 | If you encounter issues:
324 | 1. Check the [Troubleshooting](#troubleshooting) section
325 | 2. Review logs: `docker logs <container-id>`
326 | 3. Open an issue on [GitHub](https://github.com/Pimzino/spec-workflow-mcp/issues)
327 | 4. Include:
328 | - Docker version: `docker --version`
329 | - Operating system
330 | - Error messages
331 | - Steps to reproduce
332 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Spec Workflow MCP
2 |
3 | [](https://www.npmjs.com/package/@pimzino/spec-workflow-mcp)
4 | [](https://marketplace.visualstudio.com/items?itemName=Pimzino.spec-workflow-mcp)
5 |
6 | A Model Context Protocol (MCP) server for structured spec-driven development with real-time dashboard and VSCode extension.
7 |
8 | ## ☕ Support This Project
9 |
10 | <a href="https://buymeacoffee.com/Pimzino" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
11 |
12 | ## 📺 Showcase
13 |
14 | ### 🔄 Approval System in Action
15 | <a href="https://www.youtube.com/watch?v=C-uEa3mfxd0" target="_blank">
16 | <img src="https://img.youtube.com/vi/C-uEa3mfxd0/maxresdefault.jpg" alt="Approval System Demo" width="600">
17 | </a>
18 |
19 | *See how the approval system works: create documents, request approval through the dashboard, provide feedback, and track revisions.*
20 |
21 | ### 📊 Dashboard & Spec Management
22 | <a href="https://www.youtube.com/watch?v=g9qfvjLUWf8" target="_blank">
23 | <img src="https://img.youtube.com/vi/g9qfvjLUWf8/maxresdefault.jpg" alt="Dashboard Demo" width="600">
24 | </a>
25 |
26 | *Explore the real-time dashboard: view specs, track progress, navigate documents, and monitor your development workflow.*
27 |
28 | ## ✨ Key Features
29 |
30 | - **Structured Development Workflow** - Sequential spec creation (Requirements → Design → Tasks)
31 | - **Real-Time Web Dashboard** - Monitor specs, tasks, and progress with live updates
32 | - **VSCode Extension** - Integrated sidebar dashboard for VSCode users
33 | - **Approval Workflow** - Complete approval process with revisions
34 | - **Task Progress Tracking** - Visual progress bars and detailed status
35 | - **Implementation Logs** - Searchable logs of all task implementations with code statistics
36 | - **Multi-Language Support** - Available in 11 languages
37 |
38 | ## 🌍 Supported Languages
39 |
40 | 🇺🇸 English • 🇯🇵 日本語 • 🇨🇳 中文 • 🇪🇸 Español • 🇧🇷 Português • 🇩🇪 Deutsch • 🇫🇷 Français • 🇷🇺 Русский • 🇮🇹 Italiano • 🇰🇷 한국어 • 🇸🇦 العربية
41 |
42 | ## 🚀 Quick Start
43 |
44 | ### Step 1: Add to your AI tool
45 |
46 | Add to your MCP configuration (see client-specific setup below):
47 |
48 | ```json
49 | {
50 | "mcpServers": {
51 | "spec-workflow": {
52 | "command": "npx",
53 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
54 | }
55 | }
56 | }
57 | ```
58 |
59 | ### Step 2: Choose your interface
60 |
61 | **Option A: Web Dashboard** (Required for CLI users)
62 | Start the dashboard (runs on port 5000 by default):
63 | ```bash
64 | npx -y @pimzino/spec-workflow-mcp@latest --dashboard
65 | ```
66 |
67 | The dashboard will be accessible at: http://localhost:5000
68 |
69 | > **Note:** Only one dashboard instance is needed. All your projects will connect to the same dashboard.
70 |
71 | **Option B: VSCode Extension** (Recommended for VSCode users)
72 |
73 | Install [Spec Workflow MCP Extension](https://marketplace.visualstudio.com/items?itemName=Pimzino.spec-workflow-mcp) from the VSCode marketplace.
74 |
75 | ## 📝 How to Use
76 |
77 | Simply mention spec-workflow in your conversation:
78 |
79 | - **"Create a spec for user authentication"** - Creates complete spec workflow
80 | - **"List my specs"** - Shows all specs and their status
81 | - **"Execute task 1.2 in spec user-auth"** - Runs a specific task
82 |
83 | [See more examples →](docs/PROMPTING-GUIDE.md)
84 |
85 | ## 🔧 MCP Client Setup
86 |
87 | <details>
88 | <summary><strong>Augment Code</strong></summary>
89 |
90 | Configure in your Augment settings:
91 | ```json
92 | {
93 | "mcpServers": {
94 | "spec-workflow": {
95 | "command": "npx",
96 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
97 | }
98 | }
99 | }
100 | ```
101 | </details>
102 |
103 | <details>
104 | <summary><strong>Claude Code CLI</strong></summary>
105 |
106 | Add to your MCP configuration:
107 | ```bash
108 | claude mcp add spec-workflow npx @pimzino/spec-workflow-mcp@latest -- /path/to/your/project
109 | ```
110 |
111 | **Important Notes:**
112 | - The `-y` flag bypasses npm prompts for smoother installation
113 | - The `--` separator ensures the path is passed to the spec-workflow script, not to npx
114 | - Replace `/path/to/your/project` with your actual project directory path
115 |
116 | **Alternative for Windows (if the above doesn't work):**
117 | ```bash
118 | claude mcp add spec-workflow cmd.exe /c "npx @pimzino/spec-workflow-mcp@latest /path/to/your/project"
119 | ```
120 | </details>
121 |
122 | <details>
123 | <summary><strong>Claude Desktop</strong></summary>
124 |
125 | Add to `claude_desktop_config.json`:
126 | ```json
127 | {
128 | "mcpServers": {
129 | "spec-workflow": {
130 | "command": "npx",
131 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
132 | }
133 | }
134 | }
135 | ```
136 |
137 | > **Important:** Run the dashboard separately with `--dashboard` before starting the MCP server.
138 |
139 | </details>
140 |
141 | <details>
142 | <summary><strong>Cline/Claude Dev</strong></summary>
143 |
144 | Add to your MCP server configuration:
145 | ```json
146 | {
147 | "mcpServers": {
148 | "spec-workflow": {
149 | "command": "npx",
150 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
151 | }
152 | }
153 | }
154 | ```
155 | </details>
156 |
157 | <details>
158 | <summary><strong>Continue IDE Extension</strong></summary>
159 |
160 | Add to your Continue configuration:
161 | ```json
162 | {
163 | "mcpServers": {
164 | "spec-workflow": {
165 | "command": "npx",
166 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
167 | }
168 | }
169 | }
170 | ```
171 | </details>
172 |
173 | <details>
174 | <summary><strong>Cursor IDE</strong></summary>
175 |
176 | Add to your Cursor settings (`settings.json`):
177 | ```json
178 | {
179 | "mcpServers": {
180 | "spec-workflow": {
181 | "command": "npx",
182 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
183 | }
184 | }
185 | }
186 | ```
187 | </details>
188 |
189 | <details>
190 | <summary><strong>OpenCode</strong></summary>
191 |
192 | Add to your `opencode.json` configuration file:
193 | ```json
194 | {
195 | "$schema": "https://opencode.ai/config.json",
196 | "mcp": {
197 | "spec-workflow": {
198 | "type": "local",
199 | "command": ["npx", "-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"],
200 | "enabled": true
201 | }
202 | }
203 | }
204 | ```
205 | </details>
206 |
207 | ## 🐳 Docker Deployment
208 |
209 | Run the dashboard in a Docker container for isolated deployment:
210 |
211 | ```bash
212 | # Using Docker Compose (recommended)
213 | cd containers
214 | docker-compose up --build
215 |
216 | # Or using Docker CLI
217 | docker build -f containers/Dockerfile -t spec-workflow-mcp .
218 | docker run -p 5000:5000 -v "./workspace/.spec-workflow:/workspace/.spec-workflow:rw" spec-workflow-mcp
219 | ```
220 |
221 | The dashboard will be available at: http://localhost:5000
222 |
223 | [See Docker setup guide →](containers/README.md)
224 |
225 | ## 📚 Documentation
226 |
227 | - [Configuration Guide](docs/CONFIGURATION.md) - Command-line options, config files
228 | - [User Guide](docs/USER-GUIDE.md) - Comprehensive usage examples
229 | - [Workflow Process](docs/WORKFLOW.md) - Development workflow and best practices
230 | - [Interfaces Guide](docs/INTERFACES.md) - Dashboard and VSCode extension details
231 | - [Prompting Guide](docs/PROMPTING-GUIDE.md) - Advanced prompting examples
232 | - [Tools Reference](docs/TOOLS-REFERENCE.md) - Complete tools documentation
233 | - [Development](docs/DEVELOPMENT.md) - Contributing and development setup
234 | - [Troubleshooting](docs/TROUBLESHOOTING.md) - Common issues and solutions
235 |
236 | ## 📁 Project Structure
237 |
238 | ```
239 | your-project/
240 | .spec-workflow/
241 | approvals/
242 | archive/
243 | specs/
244 | steering/
245 | templates/
246 | user-templates/
247 | config.example.toml
248 | ```
249 |
250 | ## 🛠️ Development
251 |
252 | ```bash
253 | # Install dependencies
254 | npm install
255 |
256 | # Build the project
257 | npm run build
258 |
259 | # Run in development mode
260 | npm run dev
261 | ```
262 |
263 | [See development guide →](docs/DEVELOPMENT.md)
264 |
265 | ## 📄 License
266 |
267 | GPL-3.0
268 |
269 | ## ⭐ Star History
270 |
271 | <a href="https://www.star-history.com/#Pimzino/spec-workflow-mcp&Date">
272 | <picture>
273 | <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=Pimzino/spec-workflow-mcp&type=Date&theme=dark" />
274 | <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=Pimzino/spec-workflow-mcp&type=Date" />
275 | <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=Pimzino/spec-workflow-mcp&type=Date" />
276 | </picture>
277 | </a>
```
--------------------------------------------------------------------------------
/docs/technical-documentation/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Technical Documentation
2 |
3 | > **Quick Reference**: Jump to what you need most → [Tools API](api-reference.md) | [Architecture](architecture.md) | [Developer Guide](developer-guide.md) | [Troubleshooting](troubleshooting.md)
4 |
5 | ## 📋 Table of Contents
6 |
7 | ### Core Documentation
8 | - **[Architecture Overview](architecture.md)** - System design, components, and data flow
9 | - **[MCP Tools API Reference](api-reference.md)** - Complete tool documentation with examples
10 | - **[Developer Workflow Guide](developer-guide.md)** - Step-by-step development workflows
11 | - **[Context Management](context-management.md)** - How context switching and caching works
12 | - **[File Structure](file-structure.md)** - Project organization and directory layout
13 | - **[Dashboard System](dashboard.md)** - Web dashboard and real-time features
14 | - **[Troubleshooting & FAQ](troubleshooting.md)** - Common issues and solutions
15 |
16 | ### Quick Start Guides
17 | - **[Setting Up Development Environment](setup.md)** - Get up and running quickly
18 | - **[Contributing Guidelines](contributing.md)** - How to contribute to the project
19 | - **[Testing Guide](testing.md)** - Running tests and writing new ones
20 |
21 | ## 🚀 Quick Start
22 |
23 | ### For AI Assistant Integration
24 | ```json
25 | {
26 | "mcpServers": {
27 | "spec-workflow": {
28 | "command": "npx",
29 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/project", "--AutoStartDashboard"]
30 | }
31 | }
32 | }
33 | ```
34 |
35 | ### For Local Development
36 | ```bash
37 | # Clone and setup
38 | git clone <repository-url>
39 | cd spec-workflow-mcp
40 | npm install
41 |
42 | # Start development server
43 | npm run dev
44 |
45 | # Build for production
46 | npm run build
47 | ```
48 |
49 | ## 🔍 Comprehensive Capability Analysis
50 |
51 | ### Critical Questions Answered
52 |
53 | Based on comprehensive codebase analysis, here are definitive answers to key technical questions:
54 |
55 | #### **Question 1: Web Scraping & Research Capabilities**
56 | **Answer: No independent web scraping - leverages LLM's built-in web search**
57 |
58 | | Aspect | This MCP | Other AI Agents | Expansion Opportunity |
59 | |--------|----------|----------------|---------------------|
60 | | **Web Scraping** | ❌ No independent capability | ✅ Custom scrapers (Puppeteer, Playwright) | 🔮 Could add structured scraping tools |
61 | | **API Research** | ❌ Relies on LLM's web search | ✅ Direct API integrations | 🔮 Could add GitHub, Stack Overflow APIs |
62 | | **Research Caching** | ❌ No research persistence | ✅ Advanced caching systems | 🔮 Could cache LLM research results |
63 | | **Data Sources** | ✅ LLM's vast training data + real-time web | ❌ Limited to configured sources | ✅ Best of both worlds |
64 |
65 | #### **Question 2: AI Calls & Context Window Management**
66 | **Answer: Pure MCP - uses only connected LLM, no independent AI calls**
67 |
68 | | Aspect | This MCP | Other AI Agents | Expansion Opportunity |
69 | |--------|----------|----------------|---------------------|
70 | | **AI Service Calls** | ❌ No independent AI calls | ✅ Multiple AI model integration | 🔮 Could add specialized AI services |
71 | | **Context Management** | ❌ No LLM context manipulation | ✅ Advanced context strategies | 🔮 Could add context optimization |
72 | | **Memory Management** | ❌ File-based only | ✅ Vector databases, embeddings | 🔮 Could add persistent memory |
73 | | **Multi-Model Usage** | ❌ Single LLM connection | ✅ GPT-4 + Claude + Gemini | 🔮 Could add model routing |
74 |
75 | #### **Question 3: Document Planning Process**
76 | **Answer: Template-guided LLM intelligence - no separate AI planning**
77 |
78 | | Aspect | This MCP | Other AI Agents | Expansion Opportunity |
79 | |--------|----------|----------------|---------------------|
80 | | **Planning Intelligence** | ✅ LLM reasoning with templates | ✅ Dedicated planning AI | 🔮 Could add adaptive workflows |
81 | | **Template System** | ✅ Static but comprehensive | ❌ Often no structured templates | ✅ Structured advantage |
82 | | **Workflow Adaptation** | ❌ Fixed sequence | ✅ Dynamic workflow generation | 🔮 Could add LLM-powered workflows |
83 | | **Project Analysis** | ✅ LLM analyzes project context | ✅ Specialized analysis tools | 🔮 Could add deep code analysis |
84 |
85 | #### **Question 4: Auto Review Process**
86 | **Answer: Human-only approval system - no automated AI review**
87 |
88 | | Aspect | This MCP | Other AI Agents | Expansion Opportunity |
89 | |--------|----------|----------------|---------------------|
90 | | **Review Automation** | ❌ Human approval required | ✅ Multi-stage AI review | 🔮 Could add optional AI gates |
91 | | **Quality Assurance** | ✅ LLM quality + Human oversight | ❌ AI-only (potential errors) | ✅ Best quality control |
92 | | **Approval Workflows** | ✅ Dashboard/VS Code integration | ❌ Often CLI-only | ✅ Superior UX |
93 | | **Review Intelligence** | ✅ LLM can suggest improvements | ✅ Specialized review models | 🔮 Could add review templates |
94 |
95 | #### **Question 5: Best Practice Standards**
96 | **Answer: LLM built-in knowledge - no external standards fetching**
97 |
98 | | Aspect | This MCP | Other AI Agents | Expansion Opportunity |
99 | |--------|----------|----------------|---------------------|
100 | | **Standards Source** | ✅ LLM's vast training knowledge | ✅ External standards APIs | 🔮 Could add standards integration |
101 | | **Currency** | ✅ LLM can web search for latest | ❌ Static configurations | ✅ Always current |
102 | | **Customization** | ❌ No project-specific standards | ✅ Custom rule engines | 🔮 Could add org standards |
103 | | **Best Practices** | ✅ Industry-wide via LLM | ❌ Limited to pre-configured | ✅ Comprehensive coverage |
104 |
105 | ### Competitive Positioning Analysis
106 |
107 | **Strengths vs Other AI Agents:**
108 | ```typescript
109 | interface CompetitiveAdvantages {
110 | humanOversight: "Mandatory approval prevents runaway AI behavior";
111 | llmLeverage: "Uses full power of connected LLM without limitations";
112 | structuredOutput: "Templates ensure consistent, professional documentation";
113 | realTimeUI: "Dashboard and VS Code integration for seamless workflow";
114 | simplicity: "No complex setup or API key management required";
115 | reliability: "Proven workflow sequence with validation and error handling";
116 | }
117 | ```
118 |
119 | **Current Limitations vs Market Leaders:**
120 | ```typescript
121 | interface LimitationsAnalysis {
122 | automationLevel: "Less automated than fully autonomous agents";
123 | integrationEcosystem: "Limited external service integrations";
124 | multiProject: "Single project scope vs enterprise-wide solutions";
125 | aiDiversity: "Single LLM vs multi-model approaches";
126 | workflowFlexibility: "Fixed sequence vs adaptive workflows";
127 | }
128 | ```
129 |
130 | **Expansion Opportunities Identified:**
131 | ```typescript
132 | interface ExpansionRoadmap {
133 | immediateWins: {
134 | githubIntegration: "PR creation, issue sync, code analysis";
135 | qualityGates: "Optional automated quality checks";
136 | templateDynamism: "Project-type aware template selection";
137 | };
138 |
139 | mediumTerm: {
140 | multiProjectSupport: "Enterprise dashboard for multiple projects";
141 | advancedIntegrations: "Jira, Confluence, Slack notifications";
142 | workflowCustomization: "Configurable workflow sequences";
143 | };
144 |
145 | longTerm: {
146 | aiOrchestration: "Multi-agent coordination capabilities";
147 | predictiveAnalytics: "Project success prediction and risk analysis";
148 | enterpriseFeatures: "SSO, compliance, audit trails";
149 | };
150 | }
151 | ```
152 |
153 | ## ⚠️ Technical Limitations & Capabilities
154 |
155 | ### What This MCP Does NOT Do
156 |
157 | **No Independent External Calls**:
158 | - ❌ No separate web scraping or API calls by the MCP server
159 | - ❌ No independent external research by the MCP server
160 | - ❌ No direct calls to AI services from the MCP server
161 | - ✅ Leverages connected LLM's built-in web search and knowledge
162 |
163 | **No Separate AI Service Integration**:
164 | - ❌ No additional calls to OpenAI, Anthropic, or other AI services
165 | - ❌ No independent AI processing outside the connected LLM
166 | - ❌ No separate AI models or services
167 | - ✅ Uses only the LLM provided through MCP connection
168 |
169 | **No Context Window Management**:
170 | - ❌ Does not extend or manage AI client context windows
171 | - ❌ No conversation history or memory management
172 | - ❌ No cross-session AI context preservation
173 | - ✅ Provides structured project data for AI client consumption
174 |
175 | **Human-Only Approval System**:
176 | - ❌ No automated AI-powered document review
177 | - ❌ No AI-based approval recommendations
178 | - ❌ Verbal approval not accepted
179 | - ✅ All approvals require dashboard or VS Code interaction
180 |
181 | ### What This MCP Excels At
182 |
183 | **Leveraging LLM Built-in Capabilities**:
184 | - ✅ Provides structured templates for LLM to fill with intelligent content
185 | - ✅ Supplies project context for LLM analysis and understanding
186 | - ✅ Enables LLM to use its built-in knowledge for best practices
187 | - ✅ Allows LLM to perform web research when generating content
188 |
189 | **Structured Workflow Enforcement**:
190 | - ✅ Enforces spec-driven development sequence
191 | - ✅ Template-based document structure for consistent LLM output
192 | - ✅ Workflow validation and blocking
193 | - ✅ Human oversight integration for LLM-generated content
194 |
195 | **Intelligent Project Data Management**:
196 | - ✅ Efficient context loading for LLM consumption
197 | - ✅ Real-time file watching and updates
198 | - ✅ Cross-platform path handling
199 | - ✅ Structured project organization that LLM can understand
200 |
201 | **Enhanced Developer Experience**:
202 | - ✅ Web dashboard for reviewing LLM-generated content
203 | - ✅ VS Code extension integration
204 | - ✅ Real-time WebSocket updates
205 | - ✅ Comprehensive error handling
206 |
207 | ## 🎯 Key Concepts
208 |
209 | ### MCP Tools
210 | The server provides 12 MCP tools for spec-driven development:
211 | - **Workflow Tools**: `spec-workflow-guide`, `steering-guide`
212 | - **Content Tools**: `create-spec-doc`, `create-steering-doc`, `get-template-context`
213 | - **Search Tools**: `get-spec-context`, `get-steering-context`, `spec-list`
214 | - **Status Tools**: `spec-status`, `manage-tasks`
215 | - **Approval Tools**: `request-approval`, `get-approval-status`, `delete-approval`
216 |
217 | ### File Organization
218 | ```
219 | .spec-workflow/
220 | ├── specs/ # Specification documents
221 | ├── steering/ # Project guidance documents
222 | ├── approvals/ # Approval workflow data
223 | └── archive/ # Archived specifications
224 | ```
225 |
226 | ### Workflow Phases
227 | 1. **Requirements** → 2. **Design** → 3. **Tasks** → 4. **Implementation**
228 |
229 | Each phase requires approval before proceeding to the next.
230 |
231 | ## 🔧 Development Workflow
232 |
233 | ### Adding a New MCP Tool
234 | 1. Create tool file in `src/tools/`
235 | 2. Export tool definition and handler
236 | 3. Register in `src/tools/index.ts`
237 | 4. Update API documentation
238 | 5. Add tests
239 |
240 | ### Dashboard Development
241 | ```bash
242 | # Start dashboard in development mode
243 | npm run dev:dashboard
244 |
245 | # Build dashboard assets
246 | npm run build:dashboard
247 | ```
248 |
249 | ### VSCode Extension Development
250 | ```bash
251 | cd vscode-extension
252 | npm install
253 | npm run compile
254 | # Press F5 in VSCode to launch extension host
255 | ```
256 |
257 | ## 📚 Documentation Standards
258 |
259 | - **Code Examples**: Always include working examples
260 | - **Error Handling**: Document expected error conditions
261 | - **Performance**: Note any performance considerations
262 | - **Security**: Highlight security implications
263 | - **Breaking Changes**: Mark breaking changes clearly
264 |
265 | ## 🤝 Getting Help
266 |
267 | 1. **Check the [Troubleshooting Guide](troubleshooting.md)** first
268 | 2. **Search existing [GitHub Issues](https://github.com/Pimzino/spec-workflow-mcp/issues)**
269 | 3. **Create a new issue** with detailed reproduction steps
270 | 4. **Join the community** for real-time support
271 |
272 | ---
273 |
274 | ## 📊 Technical Architecture Summary
275 |
276 | ### Pure MCP Server Design
277 | This project implements a **pure Model Context Protocol (MCP) server** that:
278 |
279 | | Aspect | Implementation | Details |
280 | |--------|---------------|----------|
281 | | **AI Integration** | Pure MCP server | Leverages connected LLM's built-in capabilities |
282 | | **Web Research** | LLM built-in capability | LLM performs web search using its built-in features |
283 | | **Context Management** | File-based structure | No LLM context window management |
284 | | **Content Generation** | LLM-powered with templates | LLM fills templates using built-in knowledge & search |
285 | | **Planning Process** | LLM reasoning + workflow validation | LLM plans content, MCP enforces structure |
286 | | **Review System** | Human approval only | Dashboard/VS Code integration for LLM output |
287 | | **Best Practices** | LLM built-in knowledge | LLM applies best practices from its training |
288 | | **External Calls** | NPM version check only | All other capabilities through connected LLM |
289 |
290 | ### Key Files & Implementation
291 | - **MCP Tools**: `src/tools/*.ts` - 13 tools for workflow management
292 | - **Templates**: `src/markdown/templates/*.md` - Static document structures
293 | - **Approval System**: `src/dashboard/approval-storage.ts` - Human-only review
294 | - **Context Loading**: `src/core/*.ts` - File-based context structuring
295 | - **Web Dashboard**: `src/dashboard_frontend/` - React-based approval UI
296 |
297 | ### Performance Characteristics
298 | - **Memory Usage**: 50KB templates + 10-100KB per spec context
299 | - **File System**: Local `.spec-workflow/` directory only
300 | - **Network**: Localhost dashboard + NPM version check
301 | - **Scaling**: Linear per project, 50-100 specs recommended
302 | - **Security**: Local-only, no external data transmission
303 |
304 | ## 📊 Market Analysis & Strategic Insights
305 |
306 | ### Competitive Landscape Analysis
307 |
308 | **Category 1: Autonomous AI Agents (e.g., AutoGPT, LangChain Agents)**
309 | ```typescript
310 | interface AutonomousAgents {
311 | capabilities: {
312 | webScraping: "Advanced - Custom scrapers, API integrations";
313 | aiCalls: "Multiple models, specialized AI services";
314 | automation: "Fully autonomous operation";
315 | integrations: "Extensive third-party ecosystem";
316 | };
317 |
318 | limitations: {
319 | humanOversight: "Limited or optional";
320 | reliability: "Can go off-track or produce errors";
321 | complexity: "Complex setup, API management";
322 | cost: "High due to multiple AI calls";
323 | };
324 |
325 | differentiator: "Full automation vs structured human-guided workflow";
326 | }
327 | ```
328 |
329 | **Category 2: Development Workflow Tools (e.g., GitHub Copilot, Cursor)**
330 | ```typescript
331 | interface DevelopmentTools {
332 | capabilities: {
333 | codeGeneration: "Excellent within editors";
334 | contextAwareness: "Good for code context";
335 | realTimeAssistance: "Integrated development support";
336 | aiPowered: "Built-in LLM capabilities";
337 | };
338 |
339 | limitations: {
340 | workflowStructure: "Limited structured spec processes";
341 | documentationFocus: "Code-centric, not spec-driven";
342 | approvalProcess: "No formal review workflows";
343 | projectPlanning: "Limited high-level planning";
344 | };
345 |
346 | differentiator: "Code-first vs spec-driven development approach";
347 | }
348 | ```
349 |
350 | **Category 3: Project Management + AI (e.g., Notion AI, Linear)**
351 | ```typescript
352 | interface ProjectManagementAI {
353 | capabilities: {
354 | projectTracking: "Excellent project organization";
355 | collaboration: "Team coordination features";
356 | aiAssistance: "AI-powered content generation";
357 | integration: "Extensive third-party connections";
358 | };
359 |
360 | limitations: {
361 | technicalDepth: "Limited technical specification focus";
362 | workflowEnforcement: "Flexible but not enforced";
363 | developerWorkflow: "Not developer-workflow optimized";
364 | codeIntegration: "Limited code context understanding";
365 | };
366 |
367 | differentiator: "General project management vs developer-specific workflows";
368 | }
369 | ```
370 |
371 | ### Strategic Market Position
372 |
373 | **Spec-Workflow-MCP's Unique Position:**
374 | ```typescript
375 | interface MarketPosition {
376 | blueOcean: {
377 | category: "LLM-Enhanced Structured Development Workflows";
378 | uniqueValue: "Human-supervised LLM intelligence with enforced spec-driven process";
379 | targetUser: "Development teams needing structured processes with AI assistance";
380 | };
381 |
382 | competitiveAdvantages: {
383 | llmLeverage: "Full LLM power without additional API costs";
384 | humanOversight: "Prevents AI errors through mandatory approval";
385 | structuredProcess: "Enforces proven development methodology";
386 | simplicity: "No complex setup or API key management";
387 | realTimeUI: "Superior user experience with dashboard";
388 | };
389 |
390 | marketOpportunities: {
391 | enterpriseAdoption: "Companies wanting AI benefits with human control";
392 | consultingFirms: "Standardized processes across client projects";
393 | startups: "Structured development without overhead";
394 | education: "Teaching proper development workflows";
395 | };
396 | }
397 | ```
398 |
399 | ### Expansion Strategy Insights
400 |
401 | **Phase 1: Leverage Core Strengths**
402 | ```typescript
403 | interface Phase1Strategy {
404 | buildOnStrengths: {
405 | enhanceHumanOversight: "Advanced approval workflows, review templates";
406 | improveStructure: "Dynamic templates, adaptive workflows";
407 | expandLLMUsage: "Better context utilization, smarter suggestions";
408 | };
409 |
410 | addressGaps: {
411 | basicIntegrations: "GitHub, GitLab, Bitbucket connections";
412 | qualityGates: "Optional automated checks before human review";
413 | teamFeatures: "Multi-developer coordination";
414 | };
415 | }
416 | ```
417 |
418 | **Phase 2: Strategic Differentiation**
419 | ```typescript
420 | interface Phase2Strategy {
421 | uniqueCapabilities: {
422 | hybridIntelligence: "Best of LLM automation + human oversight";
423 | contextMastery: "Superior project context understanding";
424 | processExcellence: "Industry-leading structured workflows";
425 | };
426 |
427 | competitiveFeatures: {
428 | multiModelSupport: "Support multiple LLM providers";
429 | enterpriseFeatures: "SSO, compliance, audit trails";
430 | aiOrchestration: "Multi-agent coordination while maintaining oversight";
431 | };
432 | }
433 | ```
434 |
435 | ### Strategic Recommendations for Creators
436 |
437 | **Immediate Opportunities (0-6 months):**
438 | 1. **GitHub Integration**: Leverage LLM to create PRs, analyze codebases
439 | 2. **Quality Templates**: Add project-type detection for smarter templates
440 | 3. **Team Coordination**: Multi-developer approval workflows
441 | 4. **Performance Analytics**: Track spec-to-delivery success rates
442 |
443 | **Medium-term Differentiators (6-18 months):**
444 | 1. **Hybrid AI Workflows**: Optional automated gates with human oversight
445 | 2. **Enterprise Dashboard**: Multi-project management interface
446 | 3. **Advanced Integrations**: Jira, Slack, Confluence, CI/CD pipelines
447 | 4. **Predictive Analytics**: Project risk analysis using LLM insights
448 |
449 | **Long-term Vision (18+ months):**
450 | 1. **AI Orchestration Platform**: Multi-agent coordination with human oversight
451 | 2. **Industry Templates**: Specialized workflows for different domains
452 | 3. **Compliance Integration**: SOX, GDPR, HIPAA workflow templates
453 | 4. **Educational Platform**: Teaching structured development at scale
454 |
455 | ### Market Validation Insights
456 |
457 | **This analysis reveals that Spec-Workflow-MCP occupies a unique market position:**
458 | - ✅ **Underserved Market**: Structured development workflows with AI enhancement
459 | - ✅ **Clear Differentiation**: Human oversight + LLM power combination
460 | - ✅ **Expansion Potential**: Multiple clear paths for feature enhancement
461 | - ✅ **Strategic Moat**: Proven workflow methodology that competitors would struggle to replicate
462 |
463 | **Last Updated**: December 2024 | **Version**: 0.0.23
```
--------------------------------------------------------------------------------
/docs/technical-documentation/contributing.md:
--------------------------------------------------------------------------------
```markdown
1 | # Contributing Guidelines
2 |
3 | > **Welcome!** This guide will help you contribute effectively to the Spec Workflow MCP project.
4 |
5 | ## 🚀 Quick Start for Contributors
6 |
7 | ### 1. Setup Development Environment
8 | ```bash
9 | # Fork and clone the repository
10 | git clone https://github.com/your-username/spec-workflow-mcp.git
11 | cd spec-workflow-mcp
12 |
13 | # Install dependencies
14 | npm install
15 |
16 | # Install VS Code extension dependencies (optional)
17 | cd vscode-extension
18 | npm install
19 | cd ..
20 |
21 | # Build everything to verify setup
22 | npm run build
23 | ```
24 |
25 | ### 2. Development Workflow
26 | ```bash
27 | # Start MCP server in development mode
28 | npm run dev
29 |
30 | # In another terminal, start dashboard
31 | npm run dev:dashboard
32 |
33 | # Make your changes
34 | # Test thoroughly
35 | # Create pull request
36 | ```
37 |
38 | ## 🎯 How to Contribute
39 |
40 | ### Areas Where We Need Help
41 |
42 | **🔧 Core Features**
43 | - New MCP tools and functionality
44 | - Performance optimizations
45 | - Cross-platform compatibility improvements
46 |
47 | **📱 Dashboard & UI**
48 | - New dashboard features
49 | - UI/UX improvements
50 | - Accessibility enhancements
51 |
52 | **📚 Documentation**
53 | - Code examples and tutorials
54 | - API documentation improvements
55 | - Translation to other languages
56 |
57 | **🧪 Testing**
58 | - Unit test coverage
59 | - Integration test scenarios
60 | - Manual testing on different platforms
61 |
62 | **🐛 Bug Fixes**
63 | - Reported issues in GitHub
64 | - Edge cases and error handling
65 | - Performance bottlenecks
66 |
67 | ## 📋 Contribution Types
68 |
69 | ### 1. Bug Reports
70 | **Before Creating an Issue**:
71 | - Search existing issues first
72 | - Try the [troubleshooting guide](troubleshooting.md)
73 | - Test with the latest version
74 |
75 | **Good Bug Report Template**:
76 | ```markdown
77 | ## Bug Description
78 | Brief description of the issue
79 |
80 | ## Environment
81 | - OS: [Windows 11 / macOS 14 / Ubuntu 22.04]
82 | - Node.js: [version]
83 | - MCP Client: [Claude Desktop / Cursor / etc.]
84 |
85 | ## Steps to Reproduce
86 | 1. Step one
87 | 2. Step two
88 | 3. Step three
89 |
90 | ## Expected Behavior
91 | What should happen
92 |
93 | ## Actual Behavior
94 | What actually happens
95 |
96 | ## Additional Context
97 | - Error messages
98 | - Screenshots
99 | - Logs
100 | ```
101 |
102 | ### 2. Feature Requests
103 | **Good Feature Request Template**:
104 | ```markdown
105 | ## Feature Description
106 | Clear description of the proposed feature
107 |
108 | ## Problem It Solves
109 | What problem does this address?
110 |
111 | ## Proposed Solution
112 | How should it work?
113 |
114 | ## Alternatives Considered
115 | Other approaches you've considered
116 |
117 | ## Implementation Ideas
118 | Any thoughts on how to implement this
119 | ```
120 |
121 | ### 3. Code Contributions
122 |
123 | #### Pull Request Process
124 | 1. **Fork** the repository
125 | 2. **Create** a feature branch: `git checkout -b feature/my-feature`
126 | 3. **Make** your changes following our coding standards
127 | 4. **Test** your changes thoroughly
128 | 5. **Document** new functionality
129 | 6. **Submit** a pull request with clear description
130 |
131 | #### Pull Request Template
132 | ```markdown
133 | ## Description
134 | Brief description of changes
135 |
136 | ## Type of Change
137 | - [ ] Bug fix
138 | - [ ] New feature
139 | - [ ] Breaking change
140 | - [ ] Documentation update
141 |
142 | ## Testing
143 | - [ ] Unit tests pass
144 | - [ ] Manual testing completed
145 | - [ ] Cross-platform tested (if applicable)
146 |
147 | ## Documentation
148 | - [ ] Code is documented
149 | - [ ] README updated (if needed)
150 | - [ ] API docs updated (if needed)
151 |
152 | ## Checklist
153 | - [ ] Code follows style guidelines
154 | - [ ] Self-review completed
155 | - [ ] No merge conflicts
156 | ```
157 |
158 | ## 🎨 Coding Standards
159 |
160 | ### TypeScript Guidelines
161 |
162 | **File Organization**:
163 | ```typescript
164 | // 1. External library imports
165 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
166 | import { readFile } from 'fs/promises';
167 |
168 | // 2. Internal imports
169 | import { ToolContext, ToolResponse } from '../types.js';
170 | import { PathUtils } from '../core/path-utils.js';
171 |
172 | // 3. Type definitions
173 | interface LocalInterface {
174 | // ...
175 | }
176 |
177 | // 4. Constants
178 | const CONSTANTS = {
179 | // ...
180 | };
181 |
182 | // 5. Main implementation
183 | export class MyClass {
184 | // ...
185 | }
186 | ```
187 |
188 | **Function Structure**:
189 | ```typescript
190 | /**
191 | * Brief description of what the function does
192 | * @param param1 Description of parameter
193 | * @param param2 Description of parameter
194 | * @returns Description of return value
195 | */
196 | export async function myFunction(
197 | param1: string,
198 | param2: number
199 | ): Promise<MyReturnType> {
200 | // Input validation
201 | if (!param1) {
202 | throw new Error('param1 is required');
203 | }
204 |
205 | try {
206 | // Main logic
207 | const result = await doSomething(param1, param2);
208 | return result;
209 | } catch (error: any) {
210 | // Error handling
211 | throw new Error(`Operation failed: ${error.message}`);
212 | }
213 | }
214 | ```
215 |
216 | **Error Handling Pattern**:
217 | ```typescript
218 | // MCP Tool error handling
219 | export async function myToolHandler(args: any, context: ToolContext): Promise<ToolResponse> {
220 | try {
221 | // Validation
222 | const { requiredParam } = args;
223 | if (!requiredParam) {
224 | return {
225 | success: false,
226 | message: 'requiredParam is required',
227 | nextSteps: ['Provide the required parameter']
228 | };
229 | }
230 |
231 | // Implementation
232 | const result = await doWork(requiredParam);
233 |
234 | return {
235 | success: true,
236 | message: 'Operation completed successfully',
237 | data: result,
238 | nextSteps: ['Next recommended action']
239 | };
240 | } catch (error: any) {
241 | return {
242 | success: false,
243 | message: `Operation failed: ${error.message}`,
244 | nextSteps: [
245 | 'Check input parameters',
246 | 'Verify file permissions',
247 | 'Try again or contact support'
248 | ]
249 | };
250 | }
251 | }
252 | ```
253 |
254 | ### React Component Guidelines
255 |
256 | **Component Structure**:
257 | ```typescript
258 | // src/dashboard_frontend/src/components/MyComponent.tsx
259 | import React, { useState, useEffect } from 'react';
260 |
261 | interface MyComponentProps {
262 | data: DataType[];
263 | onAction: (item: DataType) => void;
264 | className?: string;
265 | }
266 |
267 | export default function MyComponent({
268 | data,
269 | onAction,
270 | className = ''
271 | }: MyComponentProps) {
272 | const [localState, setLocalState] = useState<StateType>({});
273 |
274 | useEffect(() => {
275 | // Side effects
276 | }, [data]);
277 |
278 | const handleClick = (item: DataType) => {
279 | // Event handlers
280 | onAction(item);
281 | };
282 |
283 | return (
284 | <div className={`base-styles ${className}`}>
285 | {data.map(item => (
286 | <div key={item.id} onClick={() => handleClick(item)}>
287 | {item.name}
288 | </div>
289 | ))}
290 | </div>
291 | );
292 | }
293 | ```
294 |
295 | **Styling Guidelines**:
296 | ```typescript
297 | // Use Tailwind CSS classes
298 | <div className="p-4 bg-white dark:bg-gray-800 rounded-lg shadow-md">
299 | <h2 className="text-xl font-semibold text-gray-900 dark:text-white">
300 | Title
301 | </h2>
302 | </div>
303 |
304 | // Custom CSS only when Tailwind is insufficient
305 | // Add to src/modules/theme/theme.css
306 | ```
307 |
308 | ### File and Directory Naming
309 |
310 | ```
311 | // Files
312 | kebab-case.ts ✅ Good
313 | PascalCase.ts ❌ Avoid
314 | snake_case.ts ❌ Avoid
315 |
316 | // Directories
317 | kebab-case/ ✅ Good
318 | PascalCase/ ❌ Avoid (except React components)
319 | snake_case/ ❌ Avoid
320 |
321 | // React Components
322 | MyComponent.tsx ✅ Good (PascalCase for components)
323 | my-component.tsx ❌ Avoid
324 |
325 | // MCP Tools
326 | my-tool.ts ✅ Good
327 | myTool.ts ❌ Avoid
328 | ```
329 |
330 | ## 🧪 Testing Guidelines
331 |
332 | ### Manual Testing Checklist
333 |
334 | **Before Submitting PR**:
335 | - [ ] MCP server starts without errors
336 | - [ ] Dashboard loads and displays data
337 | - [ ] WebSocket connections work
338 | - [ ] File changes trigger updates
339 | - [ ] Approval workflow functions
340 | - [ ] Cross-platform compatibility (if applicable)
341 |
342 | **Test Scenarios**:
343 | ```bash
344 | # 1. Basic MCP server functionality
345 | npm run dev
346 | # Connect AI client and test tools
347 |
348 | # 2. Dashboard functionality
349 | npm run dev:dashboard
350 | # Test all pages and features
351 |
352 | # 3. VS Code extension (if modified)
353 | cd vscode-extension
354 | # Press F5 in VS Code to test
355 |
356 | # 4. Build process
357 | npm run clean
358 | npm run build
359 | # Verify dist/ contents
360 |
361 | # 5. CLI interface
362 | node dist/index.js --help
363 | node dist/index.js --dashboard
364 | ```
365 |
366 | ### Future Testing Framework
367 |
368 | **Unit Tests** (planned):
369 | ```typescript
370 | // Example test structure
371 | describe('PathUtils', () => {
372 | describe('getSpecPath', () => {
373 | it('should create correct spec path', () => {
374 | const result = PathUtils.getSpecPath('/project', 'my-spec');
375 | expect(result).toBe('/project/.spec-workflow/specs/my-spec');
376 | });
377 |
378 | it('should handle special characters', () => {
379 | const result = PathUtils.getSpecPath('/project', 'user-auth');
380 | expect(result).toContain('user-auth');
381 | });
382 | });
383 | });
384 | ```
385 |
386 | ## 📖 Documentation Standards
387 |
388 | ### Code Documentation
389 |
390 | **JSDoc Comments**:
391 | ```typescript
392 | /**
393 | * Creates a new specification document following the workflow sequence
394 | *
395 | * @param projectPath - Absolute path to the project root
396 | * @param specName - Feature name in kebab-case (e.g., 'user-authentication')
397 | * @param document - Which document to create: 'requirements' | 'design' | 'tasks'
398 | * @param content - Complete markdown content for the document
399 | * @returns Promise resolving to tool response with file path and next steps
400 | *
401 | * @example
402 | * ```typescript
403 | * const response = await createSpecDoc({
404 | * projectPath: '/my/project',
405 | * specName: 'user-auth',
406 | * document: 'requirements',
407 | * content: '# Requirements\n\n...'
408 | * });
409 | * ```
410 | *
411 | * @throws {Error} When workflow order is violated (e.g., creating design before requirements)
412 | */
413 | export async function createSpecDoc(...): Promise<ToolResponse> {
414 | // Implementation
415 | }
416 | ```
417 |
418 | **README Updates**:
419 | - Update main README.md for user-facing changes
420 | - Update technical documentation for developer changes
421 | - Include code examples for new features
422 |
423 | ### API Documentation
424 |
425 | **MCP Tool Documentation**:
426 | ```typescript
427 | export const myNewToolTool: Tool = {
428 | name: 'my-new-tool',
429 | description: `Brief description of what this tool does.
430 |
431 | # Instructions
432 | When to use this tool and how it fits in the workflow.
433 |
434 | # Parameters
435 | - param1: Description and format
436 | - param2: Description and constraints
437 |
438 | # Example Usage
439 | Concrete example of how to use this tool.`,
440 | inputSchema: {
441 | // JSON Schema
442 | }
443 | };
444 | ```
445 |
446 | ## 🔄 Development Workflow
447 |
448 | ### Branch Strategy
449 |
450 | ```bash
451 | # Main branches
452 | main # Stable release code
453 | develop # Integration branch for features
454 |
455 | # Feature branches
456 | feature/add-new-tool # New features
457 | bugfix/fix-approval # Bug fixes
458 | docs/update-api # Documentation updates
459 | chore/update-deps # Maintenance tasks
460 | ```
461 |
462 | ### Commit Message Format
463 |
464 | ```bash
465 | # Format: type(scope): description
466 |
467 | feat(tools): add new spec validation tool
468 | fix(dashboard): resolve WebSocket connection issues
469 | docs(api): update MCP tool documentation
470 | chore(deps): update TypeScript to 5.3.0
471 | refactor(parser): simplify task parsing logic
472 |
473 | # Types: feat, fix, docs, style, refactor, test, chore
474 | # Scope: tools, dashboard, core, docs, extension
475 | ```
476 |
477 | ### Release Process
478 |
479 | **Version Bumping**:
480 | ```bash
481 | # Patch release (bug fixes)
482 | npm version patch
483 |
484 | # Minor release (new features)
485 | npm version minor
486 |
487 | # Major release (breaking changes)
488 | npm version major
489 | ```
490 |
491 | **Pre-release Checklist**:
492 | - [ ] All tests pass
493 | - [ ] Documentation updated
494 | - [ ] CHANGELOG.md updated
495 | - [ ] Version bumped
496 | - [ ] Build successful
497 | - [ ] Manual testing completed
498 |
499 | ## 🤝 Community Guidelines
500 |
501 | ### Code of Conduct
502 |
503 | **Our Standards**:
504 | - **Be Respectful** - Treat everyone with respect and kindness
505 | - **Be Inclusive** - Welcome contributors from all backgrounds
506 | - **Be Constructive** - Provide helpful feedback and suggestions
507 | - **Be Patient** - Remember that everyone is learning
508 |
509 | **Unacceptable Behavior**:
510 | - Harassment or discrimination
511 | - Trolling or inflammatory comments
512 | - Personal attacks
513 | - Publishing private information
514 |
515 | ### Getting Help
516 |
517 | **For Contributors**:
518 | 1. **Read this guide** and linked documentation
519 | 2. **Search existing issues** and discussions
520 | 3. **Ask in GitHub Discussions** for general questions
521 | 4. **Create an issue** for specific problems
522 | 5. **Join community channels** (if available)
523 |
524 | **For Maintainers**:
525 | - Respond to issues and PRs promptly
526 | - Provide constructive feedback
527 | - Help newcomers get started
528 | - Maintain welcoming environment
529 |
530 | ## 🏆 Recognition
531 |
532 | ### Contributors
533 |
534 | Contributors are recognized in:
535 | - GitHub contributors list
536 | - CHANGELOG.md for significant contributions
537 | - README.md acknowledgments section
538 |
539 | ### Types of Contributions
540 |
541 | **All contributions are valued**:
542 | - 💻 **Code** - Features, bug fixes, improvements
543 | - 📖 **Documentation** - Guides, examples, translations
544 | - 🐛 **Testing** - Bug reports, test cases, QA
545 | - 💡 **Ideas** - Feature requests, design feedback
546 | - 🎨 **Design** - UI/UX improvements, icons, graphics
547 | - 📢 **Community** - Helping other users, spreading the word
548 |
549 | ---
550 |
551 | **Thank you for contributing to Spec Workflow MCP!** 🎉
552 |
553 | Every contribution, no matter how small, helps make this project better for everyone.
554 |
555 | ---
556 |
557 | **Next**: [Testing Guide →](testing.md)
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/vite-env.d.ts:
--------------------------------------------------------------------------------
```typescript
1 | /// <reference types="vite/client" />
2 |
3 | declare module "*.css" {
4 | const content: any;
5 | export default content;
6 | }
```
--------------------------------------------------------------------------------
/vscode-extension/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" },
6 | { "path": "./tsconfig.extension.json" }
7 | ]
8 | }
9 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/lib/utils.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { clsx, type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
```
--------------------------------------------------------------------------------
/containers/example.mcp.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "mcpServers": {
3 | "spec-workflow": {
4 | "command": "npx",
5 | "args": [
6 | "-y",
7 | "@pimzino/spec-workflow-mcp@latest",
8 | "/path/to/your/project"
9 | ]
10 | }
11 | }
12 | }
13 |
14 |
```
--------------------------------------------------------------------------------
/vscode-extension/.vscode/extensions.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers", "ms-vscode.extension-test-runner"]
5 | }
6 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/index.html:
--------------------------------------------------------------------------------
```html
1 | <!doctype html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="UTF-8" />
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 | <title>Spec Dashboard</title>
7 | <link rel="icon" href="/favicon.ico" />
8 | </head>
9 | <body>
10 | <div id="root"></div>
11 | <script type="module" src="/src/main.tsx"></script>
12 | </body>
13 | </html>
14 |
15 |
16 |
```
--------------------------------------------------------------------------------
/containers/docker-compose.yml:
--------------------------------------------------------------------------------
```yaml
1 | services:
2 | spec-workflow-mcp:
3 | build:
4 | context: ..
5 | dockerfile: containers/Dockerfile
6 | ports:
7 | - "${DASHBOARD_PORT:-5000}:${DASHBOARD_PORT:-5000}"
8 | volumes:
9 | - "${SPEC_WORKFLOW_PATH:-./workspace}/.spec-workflow:/workspace/.spec-workflow:rw"
10 | environment:
11 | - DASHBOARD_PORT=${DASHBOARD_PORT:-5000}
12 | restart: unless-stopped
13 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/modules/approvals/colors.ts:
--------------------------------------------------------------------------------
```typescript
1 | export function hexToColorObject(hex: string) {
2 | const r = parseInt(hex.slice(1, 3), 16);
3 | const g = parseInt(hex.slice(3, 5), 16);
4 | const b = parseInt(hex.slice(5, 7), 16);
5 | const bg = `rgba(${r}, ${g}, ${b}, 0.3)`;
6 | const border = hex;
7 | const name = hex.toLowerCase();
8 | return { bg, border, name };
9 | }
10 |
11 | export function isValidHex(hex: string) {
12 | return /^#[0-9A-Fa-f]{6}$/.test(hex);
13 | }
14 |
15 |
16 |
```
--------------------------------------------------------------------------------
/src/prompts/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Prompt, PromptMessage, PromptArgument } from '@modelcontextprotocol/sdk/types.js';
2 | import { ToolContext } from '../types.js';
3 |
4 | export interface PromptHandler {
5 | (args: Record<string, any>, context: ToolContext): Promise<PromptMessage[]>;
6 | }
7 |
8 | export interface PromptDefinition {
9 | prompt: Prompt;
10 | handler: PromptHandler;
11 | }
12 |
13 | export interface PromptResponse {
14 | messages: PromptMessage[];
15 | }
```
--------------------------------------------------------------------------------
/vscode-extension/components.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "src/webview/globals.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | },
20 | "iconLibrary": "lucide"
21 | }
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/index.html:
--------------------------------------------------------------------------------
```html
1 | <!doctype html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="UTF-8" />
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 | <title>Spec Workflow Dashboard</title>
7 | <style>
8 | /* Prevent FOUC */
9 | body {
10 | visibility: hidden;
11 | }
12 | body.loaded {
13 | visibility: visible;
14 | }
15 | </style>
16 | </head>
17 | <body>
18 | <div id="root"></div>
19 | <script type="module" src="/main.tsx"></script>
20 | </body>
21 | </html>
```
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from 'vitest/config';
2 |
3 | export default defineConfig({
4 | test: {
5 | environment: 'node',
6 | globals: true,
7 | include: ['src/**/*.{test,spec}.{js,ts}'],
8 | exclude: ['src/dashboard_frontend/**/*', 'node_modules/**/*'],
9 | coverage: {
10 | reporter: ['text', 'json', 'html'],
11 | exclude: [
12 | 'src/dashboard_frontend/**',
13 | 'dist/**',
14 | '**/*.d.ts',
15 | '**/*.config.*',
16 | '**/test/**',
17 | '**/__tests__/**',
18 | ]
19 | }
20 | }
21 | });
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/main.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, { Suspense } from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import App from './App';
4 | import './globals.css';
5 | import './i18n';
6 |
7 | // Create root and render app
8 | const container = document.getElementById('root');
9 | if (container) {
10 | const root = ReactDOM.createRoot(container);
11 | root.render(
12 | <React.StrictMode>
13 | <Suspense fallback="Loading...">
14 | <App />
15 | </Suspense>
16 | </React.StrictMode>
17 | );
18 |
19 | // Mark body as loaded to prevent FOUC
20 | document.body.classList.add('loaded');
21 | }
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "node16",
5 | "moduleResolution": "node16",
6 | "lib": ["ES2022"],
7 | "outDir": "./dist",
8 | "rootDir": "./src",
9 | "strict": true,
10 | "esModuleInterop": true,
11 | "skipLibCheck": true,
12 | "forceConsistentCasingInFileNames": true,
13 | "resolveJsonModule": true,
14 | "declaration": true,
15 | "declarationMap": true,
16 | "sourceMap": true,
17 | "allowSyntheticDefaultImports": true
18 | },
19 | "include": ["src/**/*"],
20 | "exclude": ["node_modules", "dist", "src/dashboard_frontend/**"]
21 | }
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/main.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, { Suspense } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { HashRouter } from 'react-router-dom';
4 | import App from './modules/app/App';
5 | import './modules/theme/tailwind.css';
6 | import './modules/theme/theme.css';
7 | import './i18n';
8 |
9 | const container = document.getElementById('root');
10 | if (container) {
11 | const root = createRoot(container);
12 | root.render(
13 | <React.StrictMode>
14 | <Suspense fallback="loading">
15 | <HashRouter>
16 | <App />
17 | </HashRouter>
18 | </Suspense>
19 | </React.StrictMode>
20 | );
21 | }
22 |
23 |
24 |
```
--------------------------------------------------------------------------------
/vscode-extension/tsconfig.extension.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "module": "Node16",
4 | "target": "ES2022",
5 | "lib": ["ES2022"],
6 | "allowJs": true,
7 | "skipLibCheck": true,
8 | "esModuleInterop": true,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "moduleResolution": "Node16",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noEmit": true,
16 | "sourceMap": true,
17 | "baseUrl": "."
18 | },
19 | "include": [
20 | "src/extension",
21 | "src/extension.ts",
22 | "esbuild.js"
23 | ],
24 | "exclude": [
25 | "node_modules"
26 | ]
27 | }
```
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
```yaml
1 | # yaml-language-server: $schema=https://json.schemastore.org/github-issue-config.json
2 |
3 | blank_issues_enabled: false
4 | contact_links:
5 | - name: 💬 Discussion
6 | url: https://github.com/anthropics/claude-code/issues
7 | about: Ask questions, share ideas, or discuss Claude Code and MCP projects
8 | - name: 📖 MCP Documentation
9 | url: https://modelcontextprotocol.io
10 | about: Read about the Model Context Protocol specification and implementation guides
11 | - name: ⚡ Claude Code
12 | url: https://claude.ai/code
13 | about: Official Claude Code documentation and resources
```
--------------------------------------------------------------------------------
/vscode-extension/.vscode/launch.json:
--------------------------------------------------------------------------------
```json
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Run Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "args": [
13 | "--extensionDevelopmentPath=${workspaceFolder}"
14 | ],
15 | "outFiles": [
16 | "${workspaceFolder}/dist/**/*.js"
17 | ],
18 | "preLaunchTask": "${defaultBuildTask}"
19 | }
20 | ]
21 | }
22 |
```
--------------------------------------------------------------------------------
/vscode-extension/webview-dist/index.html:
--------------------------------------------------------------------------------
```html
1 | <!doctype html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="UTF-8" />
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 | <title>Spec Workflow Dashboard</title>
7 | <style>
8 | /* Prevent FOUC */
9 | body {
10 | visibility: hidden;
11 | }
12 | body.loaded {
13 | visibility: visible;
14 | }
15 | </style>
16 | <script type="module" crossorigin src="/main.js"></script>
17 | <link rel="modulepreload" crossorigin href="/i18n.js">
18 | <link rel="stylesheet" crossorigin href="/globals.css">
19 | </head>
20 | <body>
21 | <div id="root"></div>
22 | </body>
23 | </html>
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/vite.config.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { defineConfig } from 'vite';
2 | import { fileURLToPath } from 'url';
3 | import { dirname } from 'path';
4 | import react from '@vitejs/plugin-react';
5 |
6 | // Dynamically import Tailwind CSS v4 plugin
7 | async function createConfig() {
8 | const { default: tailwindcss } = await import('@tailwindcss/vite');
9 |
10 | return {
11 | plugins: [react(), tailwindcss()],
12 | // Ensure Vite resolves index.html relative to this config file
13 | root: dirname(fileURLToPath(new URL(import.meta.url))),
14 | base: '/',
15 | build: {
16 | outDir: 'dist',
17 | emptyOutDir: true,
18 | },
19 | };
20 | }
21 |
22 | export default defineConfig(createConfig());
23 |
24 |
25 |
```
--------------------------------------------------------------------------------
/vscode-extension/.vscode/settings.json:
--------------------------------------------------------------------------------
```json
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false, // set this to true to hide the "out" folder with the compiled JS files
5 | "dist": false // set this to true to hide the "dist" folder with the compiled JS files
6 | },
7 | "search.exclude": {
8 | "out": true, // set this to false to include "out" folder in search results
9 | "dist": true // set this to false to include "dist" folder in search results
10 | },
11 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
12 | "typescript.tsc.autoDetect": "off"
13 | }
```
--------------------------------------------------------------------------------
/vscode-extension/tsconfig.node.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4 | "target": "ES2022",
5 | "lib": ["ES2022"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "verbatimModuleSyntax": true,
13 | "moduleDetection": "force",
14 | "noEmit": true,
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "erasableSyntaxOnly": true,
21 | "noFallthroughCasesInSwitch": true,
22 | "noUncheckedSideEffectImports": true
23 | },
24 | "include": ["vite.config.ts"]
25 | }
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/separator.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import * as SeparatorPrimitive from "@radix-ui/react-separator";
3 |
4 | import { cn } from "@/lib/utils";
5 |
6 | function Separator({
7 | className,
8 | orientation = "horizontal",
9 | decorative = true,
10 | ...props
11 | }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
12 | return (
13 | <SeparatorPrimitive.Root
14 | data-slot="separator"
15 | decorative={decorative}
16 | orientation={orientation}
17 | className={cn(
18 | "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
19 | className
20 | )}
21 | {...props}
22 | />
23 | );
24 | }
25 |
26 | export { Separator };
27 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/input.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes<HTMLInputElement> {}
7 |
8 | const Input = React.forwardRef<HTMLInputElement, InputProps>(
9 | ({ className, type, ...props }, ref) => (
10 | <input
11 | type={type}
12 | className={cn(
13 | "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
14 | className
15 | )}
16 | ref={ref}
17 | {...props}
18 | />
19 | )
20 | );
21 | Input.displayName = "Input";
22 |
23 | export { Input };
24 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/comment-modal.html:
--------------------------------------------------------------------------------
```html
1 | <!DOCTYPE html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="UTF-8">
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 | <title>Add Comment</title>
7 | <link rel="stylesheet" href="./globals.css">
8 | <style>
9 | body {
10 | margin: 0;
11 | padding: 0;
12 | font-family: var(--vscode-font-family), -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
13 | font-size: var(--vscode-font-size, 13px);
14 | line-height: 1.4;
15 | color: var(--vscode-foreground);
16 | background: var(--vscode-editor-background);
17 | }
18 | #root {
19 | width: 100%;
20 | height: 100vh;
21 | }
22 | </style>
23 | </head>
24 | <body>
25 | <div id="root"></div>
26 | <script type="module" src="./comment-modal.tsx"></script>
27 | </body>
28 | </html>
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/progress.tsx:
--------------------------------------------------------------------------------
```typescript
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as ProgressPrimitive from "@radix-ui/react-progress";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | function Progress({
9 | className,
10 | value,
11 | ...props
12 | }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
13 | return (
14 | <ProgressPrimitive.Root
15 | data-slot="progress"
16 | className={cn(
17 | "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
18 | className
19 | )}
20 | {...props}
21 | >
22 | <ProgressPrimitive.Indicator
23 | data-slot="progress-indicator"
24 | className="bg-primary h-full w-full flex-1 transition-all"
25 | style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
26 | />
27 | </ProgressPrimitive.Root>
28 | );
29 | }
30 |
31 | export { Progress };
32 |
```
--------------------------------------------------------------------------------
/vscode-extension/eslint.config.mjs:
--------------------------------------------------------------------------------
```
1 | import typescriptEslint from "@typescript-eslint/eslint-plugin";
2 | import tsParser from "@typescript-eslint/parser";
3 |
4 | export default [{
5 | files: ["**/*.ts", "**/*.tsx"],
6 | ignores: ["node_modules/**", "webview-dist/**", "dist/**", "out/**", "**/*.d.ts", "**/webview-dist/**"],
7 | }, {
8 | plugins: {
9 | "@typescript-eslint": typescriptEslint,
10 | },
11 |
12 | languageOptions: {
13 | parser: tsParser,
14 | ecmaVersion: 2022,
15 | sourceType: "module",
16 | },
17 |
18 | rules: {
19 | "@typescript-eslint/naming-convention": ["warn", {
20 | selector: "import",
21 | format: ["camelCase", "PascalCase"],
22 | }],
23 |
24 | curly: "warn",
25 | eqeqeq: "warn",
26 | "no-throw-literal": "warn",
27 | semi: "warn",
28 | },
29 | }];
```
--------------------------------------------------------------------------------
/vscode-extension/tsconfig.app.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 | "target": "ES2022",
5 | "useDefineForClassFields": true,
6 | "lib": ["ES2022", "DOM", "DOM.Iterable"],
7 | "module": "ESNext",
8 | "skipLibCheck": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "bundler",
12 | "allowImportingTsExtensions": true,
13 | "verbatimModuleSyntax": true,
14 | "moduleDetection": "force",
15 | "noEmit": true,
16 | "jsx": "react-jsx",
17 |
18 | /* Path mapping */
19 | "baseUrl": ".",
20 | "paths": {
21 | "@/*": ["./src/webview/*"]
22 | },
23 |
24 | /* Linting */
25 | "strict": true,
26 | "noUnusedLocals": true,
27 | "noUnusedParameters": true,
28 | "erasableSyntaxOnly": true,
29 | "noFallthroughCasesInSwitch": true,
30 | "noUncheckedSideEffectImports": true
31 | },
32 | "include": ["src/webview"]
33 | }
```
--------------------------------------------------------------------------------
/vscode-extension/webview-dist/comment-modal.html:
--------------------------------------------------------------------------------
```html
1 | <!DOCTYPE html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="UTF-8">
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 | <title>Add Comment</title>
7 | <style>
8 | body {
9 | margin: 0;
10 | padding: 0;
11 | font-family: var(--vscode-font-family), -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
12 | font-size: var(--vscode-font-size, 13px);
13 | line-height: 1.4;
14 | color: var(--vscode-foreground);
15 | background: var(--vscode-editor-background);
16 | }
17 | #root {
18 | width: 100%;
19 | height: 100vh;
20 | }
21 | </style>
22 | <script type="module" crossorigin src="/comment-modal.js"></script>
23 | <link rel="modulepreload" crossorigin href="/i18n.js">
24 | <link rel="stylesheet" crossorigin href="/globals.css">
25 | </head>
26 | <body>
27 | <div id="root"></div>
28 | </body>
29 | </html>
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/lib/utils.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { clsx, type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
8 | export function formatDate(dateStr?: string) {
9 | if (!dateStr) {return 'Never';}
10 | return new Date(dateStr).toLocaleDateString(undefined, {
11 | month: 'short',
12 | day: 'numeric',
13 | hour: '2-digit',
14 | minute: '2-digit'
15 | });
16 | }
17 |
18 | export function formatDistanceToNow(dateStr: string) {
19 | const date = new Date(dateStr);
20 | const now = new Date();
21 | const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
22 |
23 | if (diffInSeconds < 60) {return 'Just now';}
24 | if (diffInSeconds < 3600) {return `${Math.floor(diffInSeconds / 60)}m ago`;}
25 | if (diffInSeconds < 86400) {return `${Math.floor(diffInSeconds / 3600)}h ago`;}
26 | return `${Math.floor(diffInSeconds / 86400)}d ago`;
27 | }
28 |
```
--------------------------------------------------------------------------------
/containers/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
1 | # Build stage
2 | FROM node:24-alpine AS builder
3 | WORKDIR /app
4 |
5 | # Copy package files
6 | COPY package*.json ./
7 |
8 | # Install all dependencies (including devDependencies for build)
9 | RUN npm ci
10 |
11 | # Copy source files
12 | COPY src ./src
13 | COPY scripts ./scripts
14 | COPY tsconfig.json ./tsconfig.json
15 | COPY vitest.config.ts ./vitest.config.ts
16 |
17 | # Build the application
18 | RUN npm run build
19 |
20 | # Runtime stage
21 | FROM node:24-alpine
22 | WORKDIR /app
23 |
24 | # Copy only production files
25 | COPY --from=builder /app/package*.json ./
26 | RUN npm ci --only=production
27 |
28 | # Copy built application
29 | COPY --from=builder /app/dist ./dist
30 |
31 | RUN mkdir -p /workspace
32 |
33 | # Change ownership of the app directory to the node user (uid=1000)
34 | RUN chown -R node:node /app /workspace
35 |
36 | # Switch to the node user to match host user permissions
37 | USER node
38 |
39 | WORKDIR /workspace
40 |
41 | EXPOSE 5000
42 |
43 | CMD node /app/dist/index.js ${SPEC_WORKFLOW_PATH:-/workspace} --dashboard --port ${DASHBOARD_PORT:-5000}
44 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/modules/theme/HighlightStyles.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, { useEffect } from 'react';
2 | import { useTheme } from './ThemeProvider';
3 |
4 | const LIGHT_ID = 'hljs-light-theme';
5 | const DARK_ID = 'hljs-dark-theme';
6 | const LIGHT_HREF = 'https://cdn.jsdelivr.net/npm/[email protected]/styles/github.min.css';
7 | const DARK_HREF = 'https://cdn.jsdelivr.net/npm/[email protected]/styles/github-dark.min.css';
8 |
9 | function ensureLink(id: string, href: string) {
10 | let link = document.getElementById(id) as HTMLLinkElement | null;
11 | if (!link) {
12 | link = document.createElement('link');
13 | link.id = id;
14 | link.rel = 'stylesheet';
15 | link.href = href;
16 | document.head.appendChild(link);
17 | }
18 | return link;
19 | }
20 |
21 | export function HighlightStyles() {
22 | const { theme } = useTheme();
23 |
24 | useEffect(() => {
25 | const light = ensureLink(LIGHT_ID, LIGHT_HREF);
26 | const dark = ensureLink(DARK_ID, DARK_HREF);
27 | if (theme === 'dark') {
28 | light.disabled = true;
29 | dark.disabled = false;
30 | } else {
31 | light.disabled = false;
32 | dark.disabled = true;
33 | }
34 | }, [theme]);
35 |
36 | return null;
37 | }
38 |
39 |
40 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/modules/theme/ThemeProvider.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
2 | import './tailwind.css';
3 |
4 | type Theme = 'light' | 'dark';
5 |
6 | type ThemeContextType = {
7 | theme: Theme;
8 | toggleTheme: () => void;
9 | };
10 |
11 | const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
12 |
13 | export function ThemeProvider({ children }: { children: React.ReactNode }) {
14 | const [theme, setTheme] = useState<Theme>(() => {
15 | const saved = localStorage.getItem('theme');
16 | return (saved as Theme) || 'dark';
17 | });
18 |
19 | useEffect(() => {
20 | document.documentElement.classList.toggle('dark', theme === 'dark');
21 | localStorage.setItem('theme', theme);
22 | }, [theme]);
23 |
24 | const value = useMemo(
25 | () => ({ theme, toggleTheme: () => setTheme((t) => (t === 'dark' ? 'light' : 'dark')) }),
26 | [theme]
27 | );
28 |
29 | return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
30 | }
31 |
32 | export function useTheme(): ThemeContextType {
33 | const ctx = useContext(ThemeContext);
34 | if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
35 | return ctx;
36 | }
37 |
38 |
39 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/modules/theme/tailwind.css:
--------------------------------------------------------------------------------
```css
1 | @import "tailwindcss";
2 | @plugin "@tailwindcss/typography";
3 |
4 | @variant dark (.dark &);
5 |
6 | :root {
7 | color-scheme: light dark;
8 | }
9 |
10 | .card {
11 | @apply bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-sm;
12 | }
13 |
14 | .card-hover {
15 | @apply transition-transform duration-200 hover:-translate-y-0.5 hover:shadow-md;
16 | }
17 |
18 | .btn {
19 | @apply inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-transparent bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-700 transition;
20 | }
21 |
22 | .btn-secondary {
23 | @apply inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-700 dark:text-gray-300 text-sm hover:bg-gray-100 dark:hover:bg-gray-700 transition;
24 | }
25 |
26 | .muted { @apply text-gray-500 dark:text-gray-400; }
27 |
28 | /* Drag and Drop utilities */
29 | .draggable {
30 | @apply touch-none select-none;
31 | }
32 |
33 | .dragging {
34 | @apply cursor-grabbing opacity-75 scale-105 rotate-1 z-50;
35 | }
36 |
37 | .drag-overlay {
38 | @apply pointer-events-none;
39 | }
40 |
41 | .drop-zone {
42 | @apply transition-colors duration-200;
43 | }
44 |
45 | .drop-zone-active {
46 | @apply ring-2 ring-blue-400 bg-blue-50 dark:bg-blue-900/10;
47 | }
```
--------------------------------------------------------------------------------
/vscode-extension/esbuild.js:
--------------------------------------------------------------------------------
```javascript
1 | const esbuild = require("esbuild");
2 |
3 | const production = process.argv.includes('--production');
4 | const watch = process.argv.includes('--watch');
5 |
6 | /**
7 | * @type {import('esbuild').Plugin}
8 | */
9 | const esbuildProblemMatcherPlugin = {
10 | name: 'esbuild-problem-matcher',
11 |
12 | setup(build) {
13 | build.onStart(() => {
14 | console.log('[watch] build started');
15 | });
16 | build.onEnd((result) => {
17 | result.errors.forEach(({ text, location }) => {
18 | console.error(`✘ [ERROR] ${text}`);
19 | console.error(` ${location.file}:${location.line}:${location.column}:`);
20 | });
21 | console.log('[watch] build finished');
22 | });
23 | },
24 | };
25 |
26 | async function main() {
27 | const ctx = await esbuild.context({
28 | entryPoints: [
29 | 'src/extension.ts'
30 | ],
31 | bundle: true,
32 | format: 'cjs',
33 | minify: production,
34 | sourcemap: !production,
35 | sourcesContent: false,
36 | platform: 'node',
37 | outfile: 'dist/extension.js',
38 | external: ['vscode'],
39 | logLevel: 'silent',
40 | plugins: [
41 | /* add to the end of plugins array */
42 | esbuildProblemMatcherPlugin,
43 | ],
44 | });
45 | if (watch) {
46 | await ctx.watch();
47 | } else {
48 | await ctx.rebuild();
49 | await ctx.dispose();
50 | }
51 | }
52 |
53 | main().catch(e => {
54 | console.error(e);
55 | process.exit(1);
56 | });
57 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/modules/notifications/VolumeControl.module.css:
--------------------------------------------------------------------------------
```css
1 | /* Slider styles for VolumeControl component */
2 | .slider {
3 | -webkit-appearance: none;
4 | appearance: none;
5 | width: 80px;
6 | height: 4px;
7 | border-radius: 2px;
8 | background: #e5e7eb;
9 | outline: none;
10 | cursor: pointer;
11 | transition: background 0.3s;
12 | }
13 |
14 | .dark .slider {
15 | background: #4b5563;
16 | }
17 |
18 | /* Webkit browsers (Chrome, Safari, Edge) */
19 | .slider::-webkit-slider-thumb {
20 | -webkit-appearance: none;
21 | appearance: none;
22 | height: 16px;
23 | width: 16px;
24 | border-radius: 50%;
25 | background: #2563eb;
26 | cursor: pointer;
27 | border: 2px solid #ffffff;
28 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
29 | transition: background 0.2s;
30 | margin-top: -6px;
31 | }
32 |
33 | .slider::-webkit-slider-thumb:hover {
34 | background: #1d4ed8;
35 | }
36 |
37 | /* Firefox */
38 | .slider::-moz-range-thumb {
39 | height: 16px;
40 | width: 16px;
41 | border-radius: 50%;
42 | background: #2563eb;
43 | cursor: pointer;
44 | border: 2px solid #ffffff;
45 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
46 | transition: background 0.2s;
47 | }
48 |
49 | .slider::-moz-range-thumb:hover {
50 | background: #1d4ed8;
51 | }
52 |
53 | /* Track styles */
54 | .slider::-webkit-slider-runnable-track {
55 | width: 100%;
56 | height: 4px;
57 | cursor: pointer;
58 | border-radius: 2px;
59 | }
60 |
61 | .slider::-moz-range-track {
62 | width: 100%;
63 | height: 4px;
64 | cursor: pointer;
65 | border-radius: 2px;
66 | }
```
--------------------------------------------------------------------------------
/src/markdown/templates/requirements-template.md:
--------------------------------------------------------------------------------
```markdown
1 | # Requirements Document
2 |
3 | ## Introduction
4 |
5 | [Provide a brief overview of the feature, its purpose, and its value to users]
6 |
7 | ## Alignment with Product Vision
8 |
9 | [Explain how this feature supports the goals outlined in product.md]
10 |
11 | ## Requirements
12 |
13 | ### Requirement 1
14 |
15 | **User Story:** As a [role], I want [feature], so that [benefit]
16 |
17 | #### Acceptance Criteria
18 |
19 | 1. WHEN [event] THEN [system] SHALL [response]
20 | 2. IF [precondition] THEN [system] SHALL [response]
21 | 3. WHEN [event] AND [condition] THEN [system] SHALL [response]
22 |
23 | ### Requirement 2
24 |
25 | **User Story:** As a [role], I want [feature], so that [benefit]
26 |
27 | #### Acceptance Criteria
28 |
29 | 1. WHEN [event] THEN [system] SHALL [response]
30 | 2. IF [precondition] THEN [system] SHALL [response]
31 |
32 | ## Non-Functional Requirements
33 |
34 | ### Code Architecture and Modularity
35 | - **Single Responsibility Principle**: Each file should have a single, well-defined purpose
36 | - **Modular Design**: Components, utilities, and services should be isolated and reusable
37 | - **Dependency Management**: Minimize interdependencies between modules
38 | - **Clear Interfaces**: Define clean contracts between components and layers
39 |
40 | ### Performance
41 | - [Performance requirements]
42 |
43 | ### Security
44 | - [Security requirements]
45 |
46 | ### Reliability
47 | - [Reliability requirements]
48 |
49 | ### Usability
50 | - [Usability requirements]
51 |
```
--------------------------------------------------------------------------------
/vscode-extension/package.nls.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "displayName": "Spec Workflow MCP",
3 | "description": "VSCode extension for Spec-Workflow-MCP with integrated dashboard",
4 | "command.openDashboard": "Open Spec Workflow Dashboard",
5 | "command.refreshData": "Refresh Data",
6 | "command.openSpec": "Open Spec",
7 | "command.approve": "Approve",
8 | "command.reject": "Reject",
9 | "command.requestRevision": "Request Revision",
10 | "command.addComment": "Add Comment",
11 | "command.editComment": "Edit Comment",
12 | "command.deleteComment": "Delete Comment",
13 | "command.showApprovalActions": "Approval Actions",
14 | "view.dashboard": "Dashboard",
15 | "view.containerTitle": "Spec Workflow",
16 | "config.title": "Spec Workflow",
17 | "config.sounds.enabled.description": "Enable sound notifications for spec workflow events",
18 | "config.sounds.volume.description": "Volume level for sound notifications (0.0 to 1.0)",
19 | "config.sounds.approvalSound.description": "Play sound when new approval requests are pending",
20 | "config.sounds.taskCompletionSound.description": "Play sound when tasks are completed",
21 | "config.language.description": "Language for the extension interface",
22 | "config.language.auto.description": "Auto-detect based on VS Code settings",
23 | "config.language.en.description": "English",
24 | "config.language.ja.description": "Japanese (日本語)",
25 | "config.language.zh.description": "Chinese (中文)"
26 | }
27 |
```
--------------------------------------------------------------------------------
/src/dashboard_frontend/src/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | export interface AutomationJob {
2 | id: string;
3 | name: string;
4 | type: 'cleanup-approvals' | 'cleanup-specs' | 'cleanup-archived-specs';
5 | enabled: boolean;
6 | config: {
7 | daysOld: number;
8 | };
9 | schedule: string;
10 | lastRun?: string;
11 | nextRun?: string;
12 | createdAt: string;
13 | }
14 |
15 | export interface ImplementationLogEntry {
16 | id: string;
17 | taskId: string;
18 | timestamp: string;
19 | summary: string;
20 | filesModified: string[];
21 | filesCreated: string[];
22 | statistics: {
23 | linesAdded: number;
24 | linesRemoved: number;
25 | filesChanged: number;
26 | };
27 | artifacts: {
28 | apiEndpoints?: Array<{
29 | method: string;
30 | path: string;
31 | purpose: string;
32 | requestFormat?: string;
33 | responseFormat?: string;
34 | location: string;
35 | }>;
36 | components?: Array<{
37 | name: string;
38 | type: string;
39 | purpose: string;
40 | location: string;
41 | props?: string;
42 | exports?: string[];
43 | }>;
44 | functions?: Array<{
45 | name: string;
46 | purpose: string;
47 | location: string;
48 | signature?: string;
49 | isExported: boolean;
50 | }>;
51 | classes?: Array<{
52 | name: string;
53 | purpose: string;
54 | location: string;
55 | methods?: string[];
56 | isExported: boolean;
57 | }>;
58 | integrations?: Array<{
59 | description: string;
60 | frontendComponent: string;
61 | backendEndpoint: string;
62 | dataFlow: string;
63 | }>;
64 | };
65 | }
66 |
```
--------------------------------------------------------------------------------
/vscode-extension/.vscode/tasks.json:
--------------------------------------------------------------------------------
```json
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "watch",
8 | "dependsOn": [
9 | "npm: watch:tsc",
10 | "npm: watch:esbuild"
11 | ],
12 | "presentation": {
13 | "reveal": "never"
14 | },
15 | "group": {
16 | "kind": "build",
17 | "isDefault": true
18 | }
19 | },
20 | {
21 | "type": "npm",
22 | "script": "watch:esbuild",
23 | "group": "build",
24 | "problemMatcher": "$esbuild-watch",
25 | "isBackground": true,
26 | "label": "npm: watch:esbuild",
27 | "presentation": {
28 | "group": "watch",
29 | "reveal": "never"
30 | }
31 | },
32 | {
33 | "type": "npm",
34 | "script": "watch:tsc",
35 | "group": "build",
36 | "problemMatcher": "$tsc-watch",
37 | "isBackground": true,
38 | "label": "npm: watch:tsc",
39 | "presentation": {
40 | "group": "watch",
41 | "reveal": "never"
42 | }
43 | },
44 | {
45 | "type": "npm",
46 | "script": "watch-tests",
47 | "problemMatcher": "$tsc-watch",
48 | "isBackground": true,
49 | "presentation": {
50 | "reveal": "never",
51 | "group": "watchers"
52 | },
53 | "group": "build"
54 | },
55 | {
56 | "label": "tasks: watch-tests",
57 | "dependsOn": [
58 | "npm: watch",
59 | "npm: watch-tests"
60 | ],
61 | "problemMatcher": []
62 | }
63 | ]
64 | }
65 |
```
--------------------------------------------------------------------------------
/src/markdown/templates/product-template.md:
--------------------------------------------------------------------------------
```markdown
1 | # Product Overview
2 |
3 | ## Product Purpose
4 | [Describe the core purpose of this product/project. What problem does it solve?]
5 |
6 | ## Target Users
7 | [Who are the primary users of this product? What are their needs and pain points?]
8 |
9 | ## Key Features
10 | [List the main features that deliver value to users]
11 |
12 | 1. **Feature 1**: [Description]
13 | 2. **Feature 2**: [Description]
14 | 3. **Feature 3**: [Description]
15 |
16 | ## Business Objectives
17 | [What are the business goals this product aims to achieve?]
18 |
19 | - [Objective 1]
20 | - [Objective 2]
21 | - [Objective 3]
22 |
23 | ## Success Metrics
24 | [How will we measure the success of this product?]
25 |
26 | - [Metric 1]: [Target]
27 | - [Metric 2]: [Target]
28 | - [Metric 3]: [Target]
29 |
30 | ## Product Principles
31 | [Core principles that guide product decisions]
32 |
33 | 1. **[Principle 1]**: [Explanation]
34 | 2. **[Principle 2]**: [Explanation]
35 | 3. **[Principle 3]**: [Explanation]
36 |
37 | ## Monitoring & Visibility (if applicable)
38 | [How do users track progress and monitor the system?]
39 |
40 | - **Dashboard Type**: [e.g., Web-based, CLI, Desktop app]
41 | - **Real-time Updates**: [e.g., WebSocket, polling, push notifications]
42 | - **Key Metrics Displayed**: [What information is most important to surface]
43 | - **Sharing Capabilities**: [e.g., read-only links, exports, reports]
44 |
45 | ## Future Vision
46 | [Where do we see this product evolving in the future?]
47 |
48 | ### Potential Enhancements
49 | - **Remote Access**: [e.g., Tunnel features for sharing dashboards with stakeholders]
50 | - **Analytics**: [e.g., Historical trends, performance metrics]
51 | - **Collaboration**: [e.g., Multi-user support, commenting]
52 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/LogStatsPanel.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import { useTranslation } from 'react-i18next';
2 | import { Card, CardContent } from './ui/card';
3 |
4 | interface LogStatsPanelProps {
5 | stats: {
6 | totalEntries: number;
7 | totalLinesAdded: number;
8 | totalLinesRemoved: number;
9 | totalFilesChanged: number;
10 | } | null;
11 | }
12 |
13 | export function LogStatsPanel({ stats }: LogStatsPanelProps) {
14 | const { t } = useTranslation();
15 |
16 | if (!stats) {
17 | return null;
18 | }
19 |
20 | return (
21 | <Card className="mb-6">
22 | <CardContent className="p-4">
23 | <div className="grid grid-cols-4 gap-4">
24 | <div className="text-center">
25 | <div className="text-2xl font-bold">{stats.totalEntries}</div>
26 | <div className="text-xs text-muted-foreground">{t('logs.stats.totalEntries')}</div>
27 | </div>
28 | <div className="text-center">
29 | <div className="text-2xl font-bold text-green-600">{stats.totalLinesAdded}</div>
30 | <div className="text-xs text-muted-foreground">{t('logs.stats.linesAdded')}</div>
31 | </div>
32 | <div className="text-center">
33 | <div className="text-2xl font-bold text-red-600">{stats.totalLinesRemoved}</div>
34 | <div className="text-xs text-muted-foreground">{t('logs.stats.linesRemoved')}</div>
35 | </div>
36 | <div className="text-center">
37 | <div className="text-2xl font-bold text-purple-600">{stats.totalFilesChanged}</div>
38 | <div className="text-xs text-muted-foreground">{t('logs.stats.filesChanged')}</div>
39 | </div>
40 | </div>
41 | </CardContent>
42 | </Card>
43 | );
44 | }
45 |
```
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: 📚 Documentation
2 | description: Report issues with documentation or suggest improvements
3 | title: "[Docs]: "
4 | labels: ["documentation", "needs-triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Help us improve the documentation!
10 |
11 | - type: dropdown
12 | id: issue-type
13 | attributes:
14 | label: Issue Type
15 | description: What kind of documentation issue is this?
16 | options:
17 | - "Error or typo"
18 | - "Unclear explanation"
19 | - "Missing information"
20 | - "Outdated information"
21 | - "New documentation needed"
22 | - "Better examples needed"
23 | - "Other"
24 | validations:
25 | required: true
26 |
27 | - type: textarea
28 | id: location
29 | attributes:
30 | label: Where is the issue?
31 | description: Which documentation has the issue?
32 | placeholder: |
33 | - File: README.md, etc.
34 | - Section: Installation, Usage, etc.
35 | - URL: If online documentation
36 | validations:
37 | required: true
38 |
39 | - type: textarea
40 | id: issue-description
41 | attributes:
42 | label: What's the problem?
43 | description: Describe the documentation issue
44 | placeholder: What's wrong or missing?
45 | validations:
46 | required: true
47 |
48 | - type: textarea
49 | id: suggested-improvement
50 | attributes:
51 | label: How should it be improved?
52 | description: What would make it better?
53 | placeholder: Your suggested improvement...
54 | validations:
55 | required: true
56 |
57 | - type: textarea
58 | id: additional-context
59 | attributes:
60 | label: Additional Context
61 | description: Any other details that would help?
62 | placeholder: Add any other context here...
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/badge.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import { Slot } from "@radix-ui/react-slot";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const badgeVariants = cva(
8 | "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
14 | secondary:
15 | "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
16 | destructive:
17 | "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
18 | outline:
19 | "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20 | },
21 | },
22 | defaultVariants: {
23 | variant: "default",
24 | },
25 | }
26 | );
27 |
28 | function Badge({
29 | className,
30 | variant,
31 | asChild = false,
32 | ...props
33 | }: React.ComponentProps<"span"> &
34 | VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35 | const Comp = asChild ? Slot : "span";
36 |
37 | return (
38 | <Comp
39 | data-slot="badge"
40 | className={cn(badgeVariants({ variant }), className)}
41 | {...props}
42 | />
43 | );
44 | }
45 |
46 | export { Badge, badgeVariants };
47 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/extension/utils/logger.ts:
--------------------------------------------------------------------------------
```typescript
1 | import * as vscode from 'vscode';
2 |
3 | export class Logger {
4 | private outputChannel: vscode.OutputChannel;
5 |
6 | constructor(outputChannel: vscode.OutputChannel) {
7 | this.outputChannel = outputChannel;
8 | }
9 |
10 | private formatMessage(level: string, message: string, data?: any): string {
11 | const timestamp = new Date().toISOString();
12 | let formatted = `[${timestamp}] ${level}: ${message}`;
13 |
14 | if (data !== undefined) {
15 | if (typeof data === 'object') {
16 | formatted += `\n${JSON.stringify(data, null, 2)}`;
17 | } else {
18 | formatted += ` ${data}`;
19 | }
20 | }
21 |
22 | return formatted;
23 | }
24 |
25 | log(message: string, data?: any) {
26 | const formatted = this.formatMessage('INFO', message, data);
27 | this.outputChannel.appendLine(formatted);
28 | }
29 |
30 | error(message: string, data?: any) {
31 | const formatted = this.formatMessage('ERROR', message, data);
32 | this.outputChannel.appendLine(formatted);
33 | }
34 |
35 | warn(message: string, data?: any) {
36 | const formatted = this.formatMessage('WARN', message, data);
37 | this.outputChannel.appendLine(formatted);
38 | }
39 |
40 | debug(message: string, data?: any) {
41 | const formatted = this.formatMessage('DEBUG', message, data);
42 | this.outputChannel.appendLine(formatted);
43 | }
44 |
45 | separator(title?: string) {
46 | const line = '='.repeat(60);
47 | if (title) {
48 | const padding = Math.max(0, 60 - title.length - 4);
49 | const leftPad = Math.floor(padding / 2);
50 | const rightPad = padding - leftPad;
51 | this.outputChannel.appendLine(`${'='.repeat(leftPad)} ${title} ${'='.repeat(rightPad)}`);
52 | } else {
53 | this.outputChannel.appendLine(line);
54 | }
55 | }
56 |
57 | show() {
58 | this.outputChannel.show();
59 | }
60 | }
```
--------------------------------------------------------------------------------
/src/dashboard/public/claude-icon-dark.svg:
--------------------------------------------------------------------------------
```
1 | <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" fill="#F4A971" fill-rule="nonzero"></path></svg>
```
--------------------------------------------------------------------------------
/src/dashboard/public/claude-icon.svg:
--------------------------------------------------------------------------------
```
1 | <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" fill="#D97757" fill-rule="nonzero"></path></svg>
```
--------------------------------------------------------------------------------
/containers/DOCKER_USAGE.md:
--------------------------------------------------------------------------------
```markdown
1 | # Example MCP Configuration with Docker Dashboard
2 |
3 | This directory contains an example MCP server configuration (`example.mcp.json`)
4 | for use with the Docker-hosted dashboard.
5 |
6 | ## Architecture
7 |
8 | The recommended setup is:
9 | - **Dashboard**: Runs in Docker (using docker-compose.yml)
10 | - **MCP Servers**: Run on host machine via npx (using example.mcp.json)
11 |
12 | ## Quick Start
13 |
14 | 1. **Start the Dashboard in Docker:**
15 | ```bash
16 | cd containers
17 | docker-compose up -d
18 | ```
19 | Dashboard will be at: http://localhost:5000
20 |
21 | 2. **Configure MCP Servers:**
22 | Use the configuration from `example.mcp.json` in your MCP client config:
23 | ```json
24 | {
25 | "mcpServers": {
26 | "spec-workflow": {
27 | "command": "npx",
28 | "args": ["-y", "@pimzino/spec-workflow-mcp@latest", "/path/to/your/project"]
29 | }
30 | }
31 | }
32 | ```
33 |
34 | 3. **Start Your MCP Client:**
35 | The MCP servers will automatically connect to the dashboard at port 5000.
36 |
37 | ## Why This Architecture?
38 |
39 | - **Dashboard in Docker**: Provides isolation and easy deployment
40 | - **MCP Servers on Host**: Allows direct file system access to your projects
41 | - **Automatic Connection**: MCP servers auto-detect and connect to dashboard
42 |
43 | ## Alternative: Everything in Docker
44 |
45 | If you need to run MCP servers in Docker (not recommended for most users):
46 | - You'll need to create a custom setup with network bridges
47 | - File system access becomes more complex
48 | - The current setup (dashboard in Docker, MCP on host) is simpler and more flexible
49 |
50 | ## See Also
51 |
52 | - [Docker Setup Guide](README.md) - Complete Docker documentation
53 | - [Main README](../README.md) - General setup and usage
54 | - [Configuration Guide](../docs/CONFIGURATION.md) - Advanced configuration options
55 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/hooks/useVSCodeTheme.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { useState, useEffect } from 'react';
2 |
3 | type VSCodeTheme = 'light' | 'dark' | 'high-contrast';
4 |
5 | /**
6 | * Custom hook to detect and track VS Code theme changes
7 | * VS Code automatically adds theme classes to the body element:
8 | * - 'vscode-light' for light themes
9 | * - 'vscode-dark' for dark themes
10 | * - 'vscode-high-contrast' for high contrast themes
11 | */
12 | export function useVSCodeTheme(): VSCodeTheme {
13 | const [theme, setTheme] = useState<VSCodeTheme>(() => {
14 | // Initial theme detection
15 | const body = document.body;
16 | if (body.classList.contains('vscode-high-contrast')) {
17 | return 'high-contrast';
18 | }
19 | if (body.classList.contains('vscode-dark')) {
20 | return 'dark';
21 | }
22 | return 'light';
23 | });
24 |
25 | useEffect(() => {
26 | const detectTheme = (): VSCodeTheme => {
27 | const body = document.body;
28 | if (body.classList.contains('vscode-high-contrast')) {
29 | return 'high-contrast';
30 | }
31 | if (body.classList.contains('vscode-dark')) {
32 | return 'dark';
33 | }
34 | return 'light';
35 | };
36 |
37 | // Update theme on initial mount
38 | setTheme(detectTheme());
39 |
40 | // Create observer to watch for theme changes
41 | const observer = new MutationObserver((mutations) => {
42 | mutations.forEach((mutation) => {
43 | if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
44 | const newTheme = detectTheme();
45 | setTheme(newTheme);
46 | }
47 | });
48 | });
49 |
50 | // Start observing body class changes
51 | observer.observe(document.body, {
52 | attributes: true,
53 | attributeFilter: ['class']
54 | });
55 |
56 | // Cleanup observer on unmount
57 | return () => {
58 | observer.disconnect();
59 | };
60 | }, []);
61 |
62 | return theme;
63 | }
```
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: ✨ Feature Request
2 | description: Suggest a new feature or enhancement for the Spec-Driven Workflow MCP Server
3 | title: "[Feature]: "
4 | labels: ["enhancement", "needs-triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thanks for suggesting a feature! Help us understand what you'd like to see.
10 |
11 | - type: textarea
12 | id: feature-description
13 | attributes:
14 | label: Feature Description
15 | description: What feature would you like to see?
16 | placeholder: Describe the feature you'd like...
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | id: problem-statement
22 | attributes:
23 | label: Problem or Use Case
24 | description: What problem would this solve or what would you use it for?
25 | placeholder: |
26 | Describe the problem or use case:
27 | - What are you trying to accomplish?
28 | - What's currently difficult or missing?
29 | validations:
30 | required: true
31 |
32 | - type: textarea
33 | id: proposed-solution
34 | attributes:
35 | label: How should it work?
36 | description: Describe how you envision this feature working
37 | placeholder: How would you like this feature to work?
38 |
39 | - type: dropdown
40 | id: feature-area
41 | attributes:
42 | label: Feature Area
43 | description: Which area would this affect?
44 | options:
45 | - MCP Tools
46 | - Web Dashboard
47 | - VSCode Extension
48 | - Spec Workflow
49 | - Bug Workflow
50 | - Templates
51 | - Documentation
52 | - Other
53 |
54 | - type: textarea
55 | id: additional-context
56 | attributes:
57 | label: Additional Context
58 | description: Anything else that would help us understand this request?
59 | placeholder: Add any other details, examples, or context here...
```
--------------------------------------------------------------------------------
/vscode-extension/icons/activity-bar-icon.svg:
--------------------------------------------------------------------------------
```
1 | <svg xmlns="http://www.w3.org/2000/svg"
2 | width="96" height="96" viewBox="0 0 96 96"
3 | preserveAspectRatio="xMidYMid meet"
4 | fill="none" stroke="currentColor" stroke-width="0.75"
5 | stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
6 | <title>Flow diagram on a page</title>
7 |
8 | <style>*{vector-effect:non-scaling-stroke}</style>
9 | <g transform="scale(4)">
10 |
11 |
12 | <!-- Page with folded corner -->
13 | <path d="M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z"/>
14 | <path d="M14 2v6h6"/>
15 |
16 | <!-- Nodes (precisely aligned) -->
17 | <!-- Start: circle center (9,7.5), r=1.6 -> bottom tangent at y=9.1 -->
18 | <circle cx="9" cy="7.5" r="1.6"/>
19 |
20 | <!-- Process: rect from (6,11.5) size 6x3.5; center y=13.25; right mid at (12,13.25) -->
21 | <rect x="6" y="11.5" width="6" height="3.5" rx="0.6"/>
22 |
23 | <!-- Decision: diamond centered at (16.25,13.25), touching (16.25,11.5) top,
24 | (18,13.25) right, (16.25,15) bottom, (14.5,13.25) left -->
25 | <polygon points="16.25,11.5 18,13.25 16.25,15 14.5,13.25"/>
26 |
27 | <!-- Connectors (end exactly at tangents/edges) -->
28 | <!-- From circle bottom (9,9.1) to process top center (9,11.5) -->
29 | <line x1="9" y1="9.1" x2="9" y2="11.5"/>
30 | <!-- Arrowhead into the process box -->
31 | <polyline points="8.55,11.0 9,11.5 9.45,11.0"/>
32 |
33 | <!-- From process right mid (12,13.25) to diamond left point (14.5,13.25) -->
34 | <line x1="12" y1="13.25" x2="14.5" y2="13.25"/>
35 | <!-- Arrowhead into the diamond -->
36 | <polyline points="14.0,12.8 14.5,13.25 14.0,13.7"/>
37 |
38 | <!-- Optional: from diamond bottom point (16.25,15) down a bit to imply continuation -->
39 | <line x1="16.25" y1="15" x2="16.25" y2="16.75"/>
40 | <polyline points="15.8,16.25 16.25,16.75 16.7,16.25"/>
41 |
42 | </g>
43 | </svg>
44 |
```
--------------------------------------------------------------------------------
/src/prompts/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Prompt, PromptMessage, ListPromptsResult, GetPromptResult } from '@modelcontextprotocol/sdk/types.js';
2 | import { ToolContext } from '../types.js';
3 | import { PromptDefinition, PromptHandler } from './types.js';
4 |
5 | // Import individual prompt definitions
6 | import { createSpecPrompt } from './create-spec.js';
7 | import { createSteeringDocPrompt } from './create-steering-doc.js';
8 | import { implementTaskPrompt } from './implement-task.js';
9 | import { specStatusPrompt } from './spec-status.js';
10 | import { injectSpecWorkflowGuidePrompt } from './inject-spec-workflow-guide.js';
11 | import { injectSteeringGuidePrompt } from './inject-steering-guide.js';
12 | import { refreshTasksPrompt } from './refresh-tasks.js';
13 |
14 | // Registry of all prompts
15 | const promptDefinitions: PromptDefinition[] = [
16 | createSpecPrompt,
17 | createSteeringDocPrompt,
18 | implementTaskPrompt,
19 | specStatusPrompt,
20 | injectSpecWorkflowGuidePrompt,
21 | injectSteeringGuidePrompt,
22 | refreshTasksPrompt
23 | ];
24 |
25 | /**
26 | * Get all registered prompts
27 | */
28 | export function registerPrompts(): Prompt[] {
29 | return promptDefinitions.map(def => def.prompt);
30 | }
31 |
32 | /**
33 | * Handle prompts/list request
34 | */
35 | export async function handlePromptList(): Promise<ListPromptsResult> {
36 | return {
37 | prompts: registerPrompts()
38 | };
39 | }
40 |
41 | /**
42 | * Handle prompts/get request
43 | */
44 | export async function handlePromptGet(
45 | name: string,
46 | args: Record<string, any> = {},
47 | context: ToolContext
48 | ): Promise<GetPromptResult> {
49 | const promptDef = promptDefinitions.find(def => def.prompt.name === name);
50 |
51 | if (!promptDef) {
52 | throw new Error(`Prompt not found: ${name}`);
53 | }
54 |
55 | try {
56 | const messages = await promptDef.handler(args, context);
57 | return { messages };
58 | } catch (error: any) {
59 | throw new Error(`Failed to generate prompt messages: ${error.message}`);
60 | }
61 | }
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/i18n.ts:
--------------------------------------------------------------------------------
```typescript
1 | import i18n from 'i18next';
2 | import { initReactI18next } from 'react-i18next';
3 | import LanguageDetector from 'i18next-browser-languagedetector';
4 | import enTranslation from './locales/en.json';
5 | import jaTranslation from './locales/ja.json';
6 | import zhTranslation from './locales/zh.json';
7 | import esTranslation from './locales/es.json';
8 | import ptTranslation from './locales/pt.json';
9 | import deTranslation from './locales/de.json';
10 | import frTranslation from './locales/fr.json';
11 | import ruTranslation from './locales/ru.json';
12 | import itTranslation from './locales/it.json';
13 | import koTranslation from './locales/ko.json';
14 | import arTranslation from './locales/ar.json';
15 |
16 | i18n
17 | .use(LanguageDetector)
18 | .use(initReactI18next)
19 | .init({
20 | resources: {
21 | en: {
22 | translation: enTranslation,
23 | },
24 | ja: {
25 | translation: jaTranslation,
26 | },
27 | zh: {
28 | translation: zhTranslation,
29 | },
30 | es: {
31 | translation: esTranslation,
32 | },
33 | pt: {
34 | translation: ptTranslation,
35 | },
36 | de: {
37 | translation: deTranslation,
38 | },
39 | fr: {
40 | translation: frTranslation,
41 | },
42 | ru: {
43 | translation: ruTranslation,
44 | },
45 | it: {
46 | translation: itTranslation,
47 | },
48 | ko: {
49 | translation: koTranslation,
50 | },
51 | ar: {
52 | translation: arTranslation,
53 | },
54 | },
55 | fallbackLng: 'en',
56 | interpolation: {
57 | escapeValue: false, // react already safes from xss
58 | },
59 | debug: true, // Enable debug mode for webview
60 | detection: {
61 | // Configure language detector to check for manual preference first
62 | order: ['localStorage', 'navigator', 'htmlTag'],
63 | lookupLocalStorage: 'spec-workflow-language',
64 | caches: ['localStorage'],
65 | },
66 | });
67 |
68 | export default i18n;
69 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/comment-modal.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import ReactDOM from 'react-dom/client';
2 | import { CommentModal } from '@/components/CommentModal';
3 | import { I18nextProvider } from 'react-i18next';
4 | import i18n from './i18n';
5 | import '@/globals.css';
6 |
7 | interface SaveCommentMessage {
8 | command: 'save';
9 | comment: string;
10 | color: string;
11 | }
12 |
13 | interface CancelMessage {
14 | command: 'cancel';
15 | }
16 |
17 | // Type for webview communication
18 | // type WebviewMessage = SaveCommentMessage | CancelMessage;
19 |
20 | // Extend the existing VSCode API interface
21 | declare global {
22 | interface Window {
23 | initialState?: {
24 | selectedText: string;
25 | existingComment?: {
26 | id: string;
27 | text: string;
28 | highlightColor?: {
29 | bg: string;
30 | border: string;
31 | name: string;
32 | };
33 | timestamp: string;
34 | } | null;
35 | };
36 | }
37 | }
38 |
39 | const vscode = window.acquireVsCodeApi?.();
40 |
41 | function CommentModalApp() {
42 | // Get initial data from webview
43 | const selectedText = window.initialState?.selectedText || i18n.t('commentModal.noTextSelected');
44 | const existingComment = window.initialState?.existingComment || null;
45 |
46 | const handleSave = (comment: string, color: string) => {
47 | const message: SaveCommentMessage = {
48 | command: 'save',
49 | comment,
50 | color
51 | };
52 | vscode?.postMessage(message);
53 | };
54 |
55 | const handleCancel = () => {
56 | const message: CancelMessage = {
57 | command: 'cancel'
58 | };
59 | vscode?.postMessage(message);
60 | };
61 |
62 | return (
63 | <I18nextProvider i18n={i18n}>
64 | <CommentModal
65 | selectedText={selectedText}
66 | existingComment={existingComment}
67 | onSave={handleSave}
68 | onCancel={handleCancel}
69 | />
70 | </I18nextProvider>
71 | );
72 | }
73 |
74 | // Mount the React app
75 | const container = document.getElementById('root');
76 | if (container) {
77 | const root = ReactDOM.createRoot(container);
78 | root.render(<CommentModalApp />);
79 | }
```
--------------------------------------------------------------------------------
/src/tools/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
2 | import { specWorkflowGuideTool, specWorkflowGuideHandler } from './spec-workflow-guide.js';
3 | import { specStatusTool, specStatusHandler } from './spec-status.js';
4 | import { steeringGuideTool, steeringGuideHandler } from './steering-guide.js';
5 | import { approvalsTool, approvalsHandler } from './approvals.js';
6 | import { logImplementationTool, logImplementationHandler } from './log-implementation.js';
7 | import { ToolContext, ToolResponse, MCPToolResponse, toMCPResponse } from '../types.js';
8 |
9 | export function registerTools(): Tool[] {
10 | return [
11 | specWorkflowGuideTool,
12 | steeringGuideTool,
13 | specStatusTool,
14 | approvalsTool,
15 | logImplementationTool
16 | ];
17 | }
18 |
19 | export async function handleToolCall(name: string, args: any, context: ToolContext): Promise<MCPToolResponse> {
20 | let response: ToolResponse;
21 | let isError = false;
22 |
23 | try {
24 | switch (name) {
25 | case 'spec-workflow-guide':
26 | response = await specWorkflowGuideHandler(args, context);
27 | break;
28 | case 'steering-guide':
29 | response = await steeringGuideHandler(args, context);
30 | break;
31 | case 'spec-status':
32 | response = await specStatusHandler(args, context);
33 | break;
34 | case 'approvals':
35 | response = await approvalsHandler(args, context);
36 | break;
37 | case 'log-implementation':
38 | response = await logImplementationHandler(args, context);
39 | break;
40 | default:
41 | throw new Error(`Unknown tool: ${name}`);
42 | }
43 |
44 | // Check if the response indicates an error
45 | isError = !response.success;
46 |
47 | } catch (error) {
48 | const errorMessage = error instanceof Error ? error.message : String(error);
49 | response = {
50 | success: false,
51 | message: `Tool execution failed: ${errorMessage}`
52 | };
53 | isError = true;
54 | }
55 |
56 | return toMCPResponse(response, isError);
57 | }
```
--------------------------------------------------------------------------------
/.github/workflows/claude-code-review.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Claude Code Review
2 |
3 | on:
4 | pull_request:
5 | types: [opened, synchronize]
6 | # Optional: Only run on specific file changes
7 | # paths:
8 | # - "src/**/*.ts"
9 | # - "src/**/*.tsx"
10 | # - "src/**/*.js"
11 | # - "src/**/*.jsx"
12 |
13 | jobs:
14 | claude-review:
15 | # Optional: Filter by PR author
16 | # if: |
17 | # github.event.pull_request.user.login == 'external-contributor' ||
18 | # github.event.pull_request.user.login == 'new-developer' ||
19 | # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
20 |
21 | runs-on: ubuntu-latest
22 | permissions:
23 | contents: read
24 | pull-requests: read
25 | issues: read
26 | id-token: write
27 |
28 | steps:
29 | - name: Checkout repository
30 | uses: actions/checkout@v4
31 | with:
32 | fetch-depth: 1
33 |
34 | - name: Run Claude Code Review
35 | id: claude-review
36 | uses: anthropics/claude-code-action@v1
37 | with:
38 | claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
39 | prompt: |
40 | Please review this pull request and provide feedback on:
41 | - Code quality and best practices
42 | - Potential bugs or issues
43 | - Performance considerations
44 | - Security concerns
45 | - Test coverage
46 |
47 | Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.
48 |
49 | Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
50 |
51 | # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
52 | # or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
53 | claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
54 |
55 |
```
--------------------------------------------------------------------------------
/.github/workflows/claude.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Claude Code
2 |
3 | on:
4 | issue_comment:
5 | types: [created]
6 | pull_request_review_comment:
7 | types: [created]
8 | issues:
9 | types: [opened, assigned]
10 | pull_request_review:
11 | types: [submitted]
12 |
13 | jobs:
14 | claude:
15 | if: |
16 | (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17 | (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18 | (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19 | (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20 | runs-on: ubuntu-latest
21 | permissions:
22 | contents: read
23 | pull-requests: read
24 | issues: read
25 | id-token: write
26 | actions: read # Required for Claude to read CI results on PRs
27 | steps:
28 | - name: Checkout repository
29 | uses: actions/checkout@v4
30 | with:
31 | fetch-depth: 1
32 |
33 | - name: Run Claude Code
34 | id: claude
35 | uses: anthropics/claude-code-action@v1
36 | with:
37 | claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38 |
39 | # This is an optional setting that allows Claude to read CI results on PRs
40 | additional_permissions: |
41 | actions: read
42 |
43 | # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
44 | # prompt: 'Update the pull request description to include a summary of changes.'
45 |
46 | # Optional: Add claude_args to customize behavior and configuration
47 | # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
48 | # or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
49 | # claude_args: '--model claude-opus-4-1-20250805 --allowed-tools Bash(gh pr:*)'
50 |
51 |
```
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/dashboard_issue.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: 📊 Dashboard/Extension Issue
2 | description: Report an issue with the web dashboard or VSCode extension dashboard
3 | title: "[Dashboard]: "
4 | labels: ["dashboard", "needs-triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Report issues with the web dashboard or VSCode extension dashboard.
10 |
11 | - type: dropdown
12 | id: dashboard-type
13 | attributes:
14 | label: Dashboard Type
15 | description: Which dashboard are you using?
16 | options:
17 | - "Web Dashboard"
18 | - "VSCode Extension Dashboard"
19 | validations:
20 | required: true
21 |
22 | - type: dropdown
23 | id: issue-type
24 | attributes:
25 | label: Issue Type
26 | description: What type of dashboard issue is this?
27 | options:
28 | - "Bug - Dashboard not loading"
29 | - "Bug - Display/UI issues"
30 | - "Bug - Updates not showing"
31 | - "Feature request"
32 | - "Performance issue"
33 | - "Other"
34 | validations:
35 | required: true
36 |
37 | - type: textarea
38 | id: issue-description
39 | attributes:
40 | label: What's happening?
41 | description: Describe the issue or feature request
42 | placeholder: Tell us what's wrong or what you'd like to see...
43 | validations:
44 | required: true
45 |
46 | - type: textarea
47 | id: steps-to-reproduce
48 | attributes:
49 | label: Steps to Reproduce
50 | description: How can we reproduce this issue?
51 | placeholder: |
52 | 1. Start dashboard with...
53 | 2. Do this...
54 | 3. See issue
55 | validations:
56 | required: true
57 |
58 | - type: textarea
59 | id: command-used
60 | attributes:
61 | label: Command or Setup Used
62 | description: How did you start the MCP server/dashboard or what VSCode version are you using?
63 | render: shell
64 | placeholder: npx @pimzino/spec-workflow-mcp@latest --dashboard
65 |
66 | - type: textarea
67 | id: additional-context
68 | attributes:
69 | label: Additional Context
70 | description: Any other details, error messages, or screenshots?
71 | placeholder: Add any other context here...
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/card.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | function Card({ className, ...props }: React.ComponentProps<"div">) {
6 | return (
7 | <div
8 | data-slot="card"
9 | className={cn(
10 | "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
11 | className
12 | )}
13 | {...props}
14 | />
15 | );
16 | }
17 |
18 | function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19 | return (
20 | <div
21 | data-slot="card-header"
22 | className={cn(
23 | "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
24 | className
25 | )}
26 | {...props}
27 | />
28 | );
29 | }
30 |
31 | function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32 | return (
33 | <div
34 | data-slot="card-title"
35 | className={cn("leading-none font-semibold", className)}
36 | {...props}
37 | />
38 | );
39 | }
40 |
41 | function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42 | return (
43 | <div
44 | data-slot="card-description"
45 | className={cn("text-muted-foreground text-sm", className)}
46 | {...props}
47 | />
48 | );
49 | }
50 |
51 | function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52 | return (
53 | <div
54 | data-slot="card-action"
55 | className={cn(
56 | "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
57 | className
58 | )}
59 | {...props}
60 | />
61 | );
62 | }
63 |
64 | function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65 | return (
66 | <div
67 | data-slot="card-content"
68 | className={cn("px-6", className)}
69 | {...props}
70 | />
71 | );
72 | }
73 |
74 | function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75 | return (
76 | <div
77 | data-slot="card-footer"
78 | className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
79 | {...props}
80 | />
81 | );
82 | }
83 |
84 | export {
85 | Card,
86 | CardHeader,
87 | CardFooter,
88 | CardTitle,
89 | CardAction,
90 | CardDescription,
91 | CardContent,
92 | };
93 |
```
--------------------------------------------------------------------------------
/vscode-extension/icons/spec-workflow.svg:
--------------------------------------------------------------------------------
```
1 | <svg xmlns="http://www.w3.org/2000/svg"
2 | width="96" height="96" viewBox="0 0 96 96"
3 | preserveAspectRatio="xMidYMid meet"
4 | fill="none" stroke="currentColor" stroke-width="0.75"
5 | stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
6 | <title>Spec Workflow Icon</title>
7 |
8 | <style>*{vector-effect:non-scaling-stroke}</style>
9 |
10 | <!-- Background circle -->
11 | <circle cx="48" cy="48" r="48" fill="#ffffff"/>
12 |
13 | <!-- Icon copied from activity-bar-icon.svg -->
14 | <!-- Centered 24x24 icon with padding: translate to center, scale, translate back -->
15 | <g transform="translate(48,48) scale(3.5) translate(-12,-12)">
16 | <!-- Page with folded corner -->
17 | <path d="M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z"/>
18 | <path d="M14 2v6h6"/>
19 |
20 | <!-- Nodes (precisely aligned) -->
21 | <!-- Start: circle center (9,7.5), r=1.6 -> bottom tangent at y=9.1 -->
22 | <circle cx="9" cy="7.5" r="1.6"/>
23 |
24 | <!-- Process: rect from (6,11.5) size 6x3.5; center y=13.25; right mid at (12,13.25) -->
25 | <rect x="6" y="11.5" width="6" height="3.5" rx="0.6"/>
26 |
27 | <!-- Decision: diamond centered at (16.25,13.25), touching (16.25,11.5) top,
28 | (18,13.25) right, (16.25,15) bottom, (14.5,13.25) left -->
29 | <polygon points="16.25,11.5 18,13.25 16.25,15 14.5,13.25"/>
30 |
31 | <!-- Connectors (end exactly at tangents/edges) -->
32 | <!-- From circle bottom (9,9.1) to process top center (9,11.5) -->
33 | <line x1="9" y1="9.1" x2="9" y2="11.5"/>
34 | <!-- Arrowhead into the process box -->
35 | <polyline points="8.55,11.0 9,11.5 9.45,11.0"/>
36 |
37 | <!-- From process right mid (12,13.25) to diamond left point (14.5,13.25) -->
38 | <line x1="12" y1="13.25" x2="14.5" y2="13.25"/>
39 | <!-- Arrowhead into the diamond -->
40 | <polyline points="14.0,12.8 14.5,13.25 14.0,13.7"/>
41 |
42 | <!-- Optional: from diamond bottom point (16.25,15) down a bit to imply continuation -->
43 | <line x1="16.25" y1="15" x2="16.25" y2="16.75"/>
44 | <polyline points="15.8,16.25 16.25,16.75 16.7,16.25"/>
45 | </g>
46 | </svg>
47 |
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/accordion.tsx:
--------------------------------------------------------------------------------
```typescript
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as AccordionPrimitive from "@radix-ui/react-accordion";
5 | import { ChevronDownIcon } from "lucide-react";
6 |
7 | import { cn } from "@/lib/utils";
8 |
9 | function Accordion({
10 | ...props
11 | }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
12 | return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
13 | }
14 |
15 | function AccordionItem({
16 | className,
17 | ...props
18 | }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
19 | return (
20 | <AccordionPrimitive.Item
21 | data-slot="accordion-item"
22 | className={cn("border-b last:border-b-0", className)}
23 | {...props}
24 | />
25 | );
26 | }
27 |
28 | function AccordionTrigger({
29 | className,
30 | children,
31 | ...props
32 | }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
33 | return (
34 | <AccordionPrimitive.Header className="flex">
35 | <AccordionPrimitive.Trigger
36 | data-slot="accordion-trigger"
37 | className={cn(
38 | "focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
39 | className
40 | )}
41 | {...props}
42 | >
43 | {children}
44 | <ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
45 | </AccordionPrimitive.Trigger>
46 | </AccordionPrimitive.Header>
47 | );
48 | }
49 |
50 | function AccordionContent({
51 | className,
52 | children,
53 | ...props
54 | }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
55 | return (
56 | <AccordionPrimitive.Content
57 | data-slot="accordion-content"
58 | className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
59 | {...props}
60 | >
61 | <div className={cn("pt-0 pb-4", className)}>{children}</div>
62 | </AccordionPrimitive.Content>
63 | );
64 | }
65 |
66 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
67 |
```
--------------------------------------------------------------------------------
/vscode-extension/tailwind.config.js:
--------------------------------------------------------------------------------
```javascript
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | darkMode: ["class"],
4 | content: [
5 | './src/webview/**/*.{ts,tsx,js,jsx}',
6 | './src/webview/index.html',
7 | ],
8 | prefix: "",
9 | theme: {
10 | container: {
11 | center: true,
12 | padding: "2rem",
13 | screens: {
14 | "2xl": "1400px",
15 | },
16 | },
17 | extend: {
18 | colors: {
19 | border: "hsl(var(--border))",
20 | input: "hsl(var(--input))",
21 | ring: "hsl(var(--ring))",
22 | background: "hsl(var(--background))",
23 | foreground: "hsl(var(--foreground))",
24 | primary: {
25 | DEFAULT: "hsl(var(--primary))",
26 | foreground: "hsl(var(--primary-foreground))",
27 | },
28 | secondary: {
29 | DEFAULT: "hsl(var(--secondary))",
30 | foreground: "hsl(var(--secondary-foreground))",
31 | },
32 | destructive: {
33 | DEFAULT: "hsl(var(--destructive))",
34 | foreground: "hsl(var(--destructive-foreground))",
35 | },
36 | muted: {
37 | DEFAULT: "hsl(var(--muted))",
38 | foreground: "hsl(var(--muted-foreground))",
39 | },
40 | accent: {
41 | DEFAULT: "hsl(var(--accent))",
42 | foreground: "hsl(var(--accent-foreground))",
43 | },
44 | popover: {
45 | DEFAULT: "hsl(var(--popover))",
46 | foreground: "hsl(var(--popover-foreground))",
47 | },
48 | card: {
49 | DEFAULT: "hsl(var(--card))",
50 | foreground: "hsl(var(--card-foreground))",
51 | },
52 | },
53 | borderRadius: {
54 | lg: "var(--radius)",
55 | md: "calc(var(--radius) - 2px)",
56 | sm: "calc(var(--radius) - 4px)",
57 | },
58 | keyframes: {
59 | "accordion-down": {
60 | from: { height: "0" },
61 | to: { height: "var(--radix-accordion-content-height)" },
62 | },
63 | "accordion-up": {
64 | from: { height: "var(--radix-accordion-content-height)" },
65 | to: { height: "0" },
66 | },
67 | },
68 | animation: {
69 | "accordion-down": "accordion-down 0.2s ease-out",
70 | "accordion-up": "accordion-up 0.2s ease-out",
71 | },
72 | },
73 | },
74 | plugins: [],
75 | }
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/tabs.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import * as TabsPrimitive from "@radix-ui/react-tabs";
3 |
4 | import { cn } from "@/lib/utils";
5 |
6 | function Tabs({
7 | className,
8 | ...props
9 | }: React.ComponentProps<typeof TabsPrimitive.Root>) {
10 | return (
11 | <TabsPrimitive.Root
12 | data-slot="tabs"
13 | className={cn("flex flex-col gap-2", className)}
14 | {...props}
15 | />
16 | );
17 | }
18 |
19 | function TabsList({
20 | className,
21 | ...props
22 | }: React.ComponentProps<typeof TabsPrimitive.List>) {
23 | return (
24 | <TabsPrimitive.List
25 | data-slot="tabs-list"
26 | className={cn(
27 | "bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
28 | "[body.vscode-light_&]:border [body.vscode-light_&]:border-border/20 [body.vscode-light_&]:shadow-sm",
29 | className
30 | )}
31 | {...props}
32 | />
33 | );
34 | }
35 |
36 | function TabsTrigger({
37 | className,
38 | ...props
39 | }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
40 | return (
41 | <TabsPrimitive.Trigger
42 | data-slot="tabs-trigger"
43 | className={cn(
44 | "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
45 | className
46 | )}
47 | {...props}
48 | />
49 | );
50 | }
51 |
52 | function TabsContent({
53 | className,
54 | ...props
55 | }: React.ComponentProps<typeof TabsPrimitive.Content>) {
56 | return (
57 | <TabsPrimitive.Content
58 | data-slot="tabs-content"
59 | className={cn("flex-1 outline-none", className)}
60 | {...props}
61 | />
62 | );
63 | }
64 |
65 | export { Tabs, TabsList, TabsTrigger, TabsContent };
66 |
```
--------------------------------------------------------------------------------
/scripts/copy-static.cjs:
--------------------------------------------------------------------------------
```
1 | #!/usr/bin/env node
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 |
6 | function copyDir(src, dest) {
7 | if (!fs.existsSync(dest)) {
8 | fs.mkdirSync(dest, { recursive: true });
9 | }
10 |
11 | const entries = fs.readdirSync(src, { withFileTypes: true });
12 |
13 | for (const entry of entries) {
14 | const srcPath = path.join(src, entry.name);
15 | const destPath = path.join(dest, entry.name);
16 |
17 | if (entry.isDirectory()) {
18 | copyDir(srcPath, destPath);
19 | } else {
20 | fs.copyFileSync(srcPath, destPath);
21 | }
22 | }
23 | }
24 |
25 | // Copy markdown directory
26 | const markdownSrc = path.join(__dirname, '..', 'src', 'markdown');
27 | const markdownDest = path.join(__dirname, '..', 'dist', 'markdown');
28 |
29 | if (fs.existsSync(markdownSrc)) {
30 | copyDir(markdownSrc, markdownDest);
31 | console.log('✓ Copied markdown files');
32 | }
33 |
34 | // Copy locales directory
35 | const localesSrc = path.join(__dirname, '..', 'src', 'locales');
36 | const localesDest = path.join(__dirname, '..', 'dist', 'locales');
37 |
38 | if (fs.existsSync(localesSrc)) {
39 | copyDir(localesSrc, localesDest);
40 | console.log('✓ Copied locale files');
41 | }
42 |
43 | // Copy icons from old dashboard (we still need these)
44 | const iconsSrc = path.join(__dirname, '..', 'src', 'dashboard', 'public');
45 | const publicDest = path.join(__dirname, '..', 'dist', 'dashboard', 'public');
46 |
47 | // Ensure public directory exists
48 | if (!fs.existsSync(publicDest)) {
49 | fs.mkdirSync(publicDest, { recursive: true });
50 | }
51 |
52 | // Copy only the icon files from old dashboard
53 | const iconFiles = ['claude-icon.svg', 'claude-icon-dark.svg'];
54 | if (fs.existsSync(iconsSrc)) {
55 | for (const iconFile of iconFiles) {
56 | const srcPath = path.join(iconsSrc, iconFile);
57 | const destPath = path.join(publicDest, iconFile);
58 | if (fs.existsSync(srcPath)) {
59 | fs.copyFileSync(srcPath, destPath);
60 | }
61 | }
62 | console.log('✓ Copied dashboard icon files');
63 | }
64 |
65 | // Copy dashboard build as the main dashboard
66 | const newDashSrc = path.join(__dirname, '..', 'src', 'dashboard_frontend', 'dist');
67 |
68 | if (fs.existsSync(newDashSrc)) {
69 | // Copy all files from new dashboard to public root
70 | copyDir(newDashSrc, publicDest);
71 | console.log('✓ Copied dashboard as main dashboard');
72 | }
```
--------------------------------------------------------------------------------
/vscode-extension/src/webview/components/ui/button.tsx:
--------------------------------------------------------------------------------
```typescript
1 | import * as React from "react";
2 | import { Slot } from "@radix-ui/react-slot";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16 | outline:
17 | "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20 | ghost:
21 | "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22 | link: "text-primary underline-offset-4 hover:underline",
23 | },
24 | size: {
25 | default: "h-9 px-4 py-2 has-[>svg]:px-3",
26 | sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27 | lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28 | icon: "size-9",
29 | },
30 | },
31 | defaultVariants: {
32 | variant: "default",
33 | size: "default",
34 | },
35 | }
36 | );
37 |
38 | function Button({
39 | className,
40 | variant,
41 | size,
42 | asChild = false,
43 | ...props
44 | }: React.ComponentProps<"button"> &
45 | VariantProps<typeof buttonVariants> & {
46 | asChild?: boolean
47 | }) {
48 | const Comp = asChild ? Slot : "button";
49 |
50 | return (
51 | <Comp
52 | data-slot="button"
53 | className={cn(buttonVariants({ variant, size, className }))}
54 | {...props}
55 | />
56 | );
57 | }
58 |
59 | export { Button, buttonVariants };
60 |
```
--------------------------------------------------------------------------------
/src/prompts/inject-spec-workflow-guide.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Prompt, PromptMessage } from '@modelcontextprotocol/sdk/types.js';
2 | import { PromptDefinition } from './types.js';
3 | import { ToolContext } from '../types.js';
4 | import { specWorkflowGuideHandler } from '../tools/spec-workflow-guide.js';
5 |
6 | const prompt: Prompt = {
7 | name: 'inject-spec-workflow-guide',
8 | title: 'Inject Spec Workflow Guide into Context',
9 | description: 'Injects the complete spec-driven development workflow guide into the conversation context. This provides immediate access to all workflow phases, tools, and best practices without requiring separate tool calls.'
10 | };
11 |
12 | async function handler(args: Record<string, any>, context: ToolContext): Promise<PromptMessage[]> {
13 | // Call the spec-workflow-guide tool to get the full guide
14 | const toolResponse = await specWorkflowGuideHandler({}, context);
15 |
16 | // Extract the guide content from the tool response
17 | const guide = toolResponse.data?.guide || '';
18 | const dashboardUrl = toolResponse.data?.dashboardUrl;
19 | const nextSteps = toolResponse.nextSteps || [];
20 |
21 | const messages: PromptMessage[] = [
22 | {
23 | role: 'user',
24 | content: {
25 | type: 'text',
26 | text: `Please review and follow this comprehensive spec-driven development workflow guide:
27 |
28 | ${guide}
29 |
30 | **Current Context:**
31 | - Project: ${context.projectPath}
32 | ${dashboardUrl ? `- Dashboard: ${dashboardUrl}` : '- Dashboard: Please start the dashboard or use VS Code extension "Spec Workflow MCP"'}
33 |
34 | **Next Steps:**
35 | ${nextSteps.map(step => `- ${step}`).join('\n')}
36 |
37 | **Important Instructions:**
38 | 1. This guide has been injected into your context for immediate reference
39 | 2. Follow the workflow sequence exactly: Requirements → Design → Tasks → Implementation
40 | 3. Use the MCP tools mentioned in the guide to execute each phase
41 | 4. Always request approval between phases using the approvals tool
42 | 5. Never proceed to the next phase without successful approval cleanup
43 |
44 | Please acknowledge that you've reviewed this workflow guide and are ready to help with spec-driven development.`
45 | }
46 | }
47 | ];
48 |
49 | return messages;
50 | }
51 |
52 | export const injectSpecWorkflowGuidePrompt: PromptDefinition = {
53 | prompt,
54 | handler
55 | };
```
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: 🐛 Bug Report
2 | description: Report a bug or issue with the Spec-Driven Workflow MCP Server
3 | title: "[Bug]: "
4 | labels: ["bug", "needs-triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thanks for reporting a bug! Please provide the essential details below to help us fix the issue quickly.
10 |
11 | - type: textarea
12 | id: what-happened
13 | attributes:
14 | label: What happened?
15 | description: Describe the bug clearly and concisely
16 | placeholder: Tell us what went wrong...
17 | validations:
18 | required: true
19 |
20 | - type: dropdown
21 | id: component
22 | attributes:
23 | label: Component
24 | description: Which component is affected?
25 | options:
26 | - MCP Server
27 | - Web Dashboard
28 | - VSCode Extension
29 | validations:
30 | required: true
31 |
32 | - type: textarea
33 | id: steps-to-reproduce
34 | attributes:
35 | label: Steps to Reproduce
36 | description: How can we reproduce this issue?
37 | placeholder: |
38 | 1. Run MCP server with '...'
39 | 2. Use tool '...'
40 | 3. See error
41 | validations:
42 | required: true
43 |
44 | - type: textarea
45 | id: expected-behavior
46 | attributes:
47 | label: Expected Behavior
48 | description: What should have happened instead?
49 | placeholder: Describe what you expected to happen...
50 | validations:
51 | required: true
52 |
53 | - type: textarea
54 | id: error-output
55 | attributes:
56 | label: Error Output (if any)
57 | description: Paste any error messages or logs
58 | render: shell
59 | placeholder: Paste error messages here...
60 |
61 | - type: input
62 | id: version
63 | attributes:
64 | label: Version
65 | description: What version are you using? (MCP server, dashboard, or extension version)
66 | placeholder: "0.0.19"
67 | validations:
68 | required: true
69 |
70 | - type: dropdown
71 | id: os
72 | attributes:
73 | label: Operating System
74 | options:
75 | - Windows
76 | - macOS
77 | - Linux
78 | - Other
79 |
80 | - type: textarea
81 | id: additional-context
82 | attributes:
83 | label: Additional Context
84 | description: Anything else that might help us understand the issue?
85 | placeholder: Add any other details, screenshots, or context here...
```