Skip to content

5.3 OpenSpec + Claude Code 工作流

概述

Claude Code 是 Anthropic 官方提供的 AI 编程助手,与 OpenSpec 有着原生的深度集成。本章将详细介绍如何在 Claude Code 中使用 OpenSpec 进行规格驱动开发。

Claude Code 与 OpenSpec 的集成方式

集成架构

┌──────────────────────────────────────────────────────────┐
│                      Claude Code                          │
├──────────────────────────────────────────────────────────┤
│  ┌─────────────────┐    ┌─────────────────────────────┐  │
│  │  斜杠命令        │    │  AGENTS.md 工作流指令       │  │
│  │  /openspec:*    │    │  openspec/AGENTS.md         │  │
│  └────────┬────────┘    └──────────────┬──────────────┘  │
│           │                            │                  │
│           └────────────┬───────────────┘                  │
│                        ▼                                  │
│  ┌─────────────────────────────────────────────────────┐ │
│  │               OpenSpec 工作流执行                     │ │
│  │                                                      │ │
│  │   读取 project.md → 分析需求 → 创建变更 → 实现任务    │ │
│  └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘

斜杠命令

初始化 OpenSpec 并选择 Claude Code 后,会创建以下斜杠命令:

命令功能示例用法
/openspec:proposal创建变更提案/openspec:proposal Add user authentication
/openspec:apply实现变更/openspec:apply add-user-auth
/openspec:archive归档变更/openspec:archive add-user-auth

配置文件位置

.claude/
└── commands/
    └── openspec/
        ├── proposal.md    # 提案命令模板
        ├── apply.md       # 实现命令模板
        └── archive.md     # 归档命令模板

完整工作流演示

场景:为电商应用添加购物车功能

假设你正在开发一个电商应用,需要添加购物车功能。

Step 1: 创建变更提案

使用斜杠命令

/openspec:proposal Add shopping cart functionality

或使用自然语言

请帮我创建一个 OpenSpec 提案,添加购物车功能。
用户需要能够:
- 添加商品到购物车
- 修改商品数量
- 删除商品
- 查看购物车总价

Claude Code 响应

我将为购物车功能创建 OpenSpec 变更提案。

首先,让我查看现有规格...
[运行 openspec list --specs]

好的,我看到有 product 和 order 规格。
购物车将与这两者交互。

创建变更目录结构...
[创建 openspec/changes/add-shopping-cart/]

正在生成 proposal.md...

生成的 proposal.md

markdown
## Why
电商应用需要购物车功能,让用户能够:
- 在购买前收集多个商品
- 方便地管理购买意向
- 一次性完成多商品结账

## What Changes
- 添加购物车数据模型和 API
- 实现购物车 CRUD 操作
- 添加购物车 UI 组件
- 集成到现有的 product 和 order 流程

## Impact
- **Affected specs**: product (minor), order (integration)
- **New spec**: shopping-cart
- **Affected code**:
  - `src/models/` - 新增购物车模型
  - `src/routes/` - 新增购物车 API
  - `src/components/` - 新增购物车组件
- **Breaking changes**: 无

生成的规格增量

markdown
# Shopping Cart Specification

## Purpose
Enable users to collect and manage products before checkout.

## Requirements

### Requirement: Add to Cart
The system SHALL allow users to add products to their shopping cart.

#### Scenario: Add new item
- **GIVEN** user is viewing a product
- **WHEN** user clicks "Add to Cart"
- **AND** product is in stock
- **THEN** product is added to cart with quantity 1
- **AND** cart icon shows updated count

#### Scenario: Add existing item
- **GIVEN** product is already in cart
- **WHEN** user adds same product again
- **THEN** quantity increases by 1
- **AND** duplicate entries are not created

### Requirement: Update Quantity
The system SHALL allow users to change item quantities in cart.

#### Scenario: Increase quantity
- **GIVEN** item is in cart
- **WHEN** user increases quantity
- **AND** requested quantity is available
- **THEN** quantity is updated
- **AND** cart total is recalculated

#### Scenario: Quantity exceeds stock
- **GIVEN** item is in cart
- **WHEN** user sets quantity higher than stock
- **THEN** quantity is set to max available
- **AND** user is notified

### Requirement: Remove from Cart
The system SHALL allow users to remove items from cart.

#### Scenario: Remove item
- **WHEN** user removes item from cart
- **THEN** item is removed
- **AND** cart total is recalculated
- **AND** user can undo within 5 seconds

### Requirement: Cart Persistence
The system SHALL persist cart data for logged-in users.

#### Scenario: Cart survives session
- **GIVEN** user has items in cart
- **WHEN** user logs out and logs back in
- **THEN** cart contents are preserved

#### Scenario: Guest cart merge
- **GIVEN** guest user has items in cart
- **WHEN** guest user logs in
- **THEN** guest cart merges with existing cart
- **AND** duplicates are combined

Step 2: 审核和完善规格

继续对话

Human: 我看了提案,有几个问题:
1. 购物车有数量上限吗?
2. 商品下架后购物车里的商品怎么处理?
3. 需要支持优惠券吗?

Claude: 好问题!让我补充这些场景到规格中...

[编辑 spec.md 添加新场景]

补充的场景

markdown
### Requirement: Cart Limits
The system MUST enforce reasonable cart limits.

#### Scenario: Item quantity limit
- **WHEN** user tries to add more than 99 of same item
- **THEN** quantity is capped at 99
- **AND** user is notified

#### Scenario: Cart item limit
- **WHEN** user has 50 unique items in cart
- **AND** tries to add another item
- **THEN** system prompts to checkout or remove items

### Requirement: Unavailable Product Handling
The system SHALL handle products becoming unavailable.

#### Scenario: Product out of stock
- **GIVEN** product in cart goes out of stock
- **WHEN** user views cart
- **THEN** item is marked as unavailable
- **AND** item is excluded from checkout
- **AND** user is notified

#### Scenario: Product delisted
- **GIVEN** product in cart is removed from catalog
- **WHEN** user views cart
- **THEN** item shows "No longer available"
- **AND** item can only be removed

Step 3: 验证规格

Human: 请验证变更规格

Claude: [运行 openspec validate add-shopping-cart --strict]

验证通过!规格格式正确,所有需求都有场景覆盖。

Step 4: 批准并实现

Human: 规格看起来不错,请开始实现

Claude: /openspec:apply add-shopping-cart

好的,我将按照任务清单实现购物车功能。

首先读取 proposal.md 和 tasks.md...

开始任务 1.1: 创建购物车数据模型...
[创建 src/models/Cart.js]

任务 1.1 完成 ✓

开始任务 1.2: 创建购物车项目模型...
[创建 src/models/CartItem.js]

...

Step 5: 归档变更

当所有任务完成并部署后:

Human: 购物车功能已上线,请归档变更

Claude: /openspec:archive add-shopping-cart

归档变更 add-shopping-cart...
- 将规格增量合并到 openspec/specs/shopping-cart/spec.md
- 移动变更目录到 archive/2024-12-05-add-shopping-cart/

✓ 归档完成!

高级用法

1. 多规格变更

当一个功能涉及多个规格时:

Human: 创建提案:用户评价功能,需要修改 product 和 order 规格

Claude: 我将创建一个跨规格的变更提案...

[创建目录结构]
openspec/changes/add-reviews/
├── proposal.md
├── tasks.md
└── specs/
    ├── product/
    │   └── spec.md    # 产品评分展示
    ├── order/
    │   └── spec.md    # 只有已购买才能评价
    └── reviews/
        └── spec.md    # 新的评价规格

2. 查看变更状态

Human: 显示当前所有变更的状态

Claude: [运行 openspec list]

活跃变更:
┌─────────────────────────┬──────────────┬────────────┐
│ Change ID               │ Specs        │ Status     │
├─────────────────────────┼──────────────┼────────────┤
│ add-shopping-cart       │ shopping-cart│ In Progress│
│ update-checkout-flow    │ order        │ Review     │
└─────────────────────────┴──────────────┴────────────┘

3. 调试规格解析

当验证失败时:

Human: 验证失败了,能帮我看看哪里有问题吗?

Claude: [运行 openspec show add-shopping-cart --json --deltas-only]

我发现问题了:Scenario 标题格式不正确。

错误位置: specs/shopping-cart/spec.md 第 45 行
问题: 使用了 "### Scenario:" 而不是 "#### Scenario:"

正在修复...

4. 项目上下文利用

Claude Code 会读取 openspec/project.md 来理解项目约定:

Human: 创建提案时请遵循我们的代码规范

Claude: 当然!我已经读取了 project.md,了解到:
- 使用 TypeScript
- 遵循 REST API 设计规范
- 使用 Prisma ORM
- 测试覆盖率要求 80%

我会在生成代码和任务时遵循这些约定。

5. 与 Git 工作流集成

Human: 每个变更提案对应一个 Git 分支,帮我设置工作流

Claude: 好的,我建议以下工作流:

1. 创建提案时创建分支:
   git checkout -b feature/add-shopping-cart

2. 提案审核通过后:
   git add openspec/changes/add-shopping-cart/
   git commit -m "spec: add shopping cart proposal"

3. 实现过程中定期提交:
   git commit -m "feat(cart): implement add to cart API"

4. 归档时:
   git add openspec/
   git commit -m "spec: archive add-shopping-cart"
   git merge main

常见问题与解决方案

问题 1: 斜杠命令不显示

原因:Claude Code 在启动时加载命令,需要重启。

解决

bash
# 退出并重新启动 Claude Code
# 或运行 openspec update 后重启
openspec update

问题 2: AI 不遵循规格格式

原因:AGENTS.md 可能未正确配置。

解决

bash
# 重新生成 AI 指令
openspec update

# 在对话中明确要求
请严格按照 openspec/AGENTS.md 中的格式要求创建规格

问题 3: 变更冲突

原因:多个变更修改同一个规格。

解决

Human: add-reviews 和 update-product-page 都修改了 product 规格,怎么处理?

Claude: 让我检查两个变更的冲突...

[分析两个变更的 delta]

建议:
1. 先归档 update-product-page(范围小)
2. 然后更新 add-reviews 的 delta 基于新的 product 规格

问题 4: 实现与规格不一致

原因:实现过程中发现规格有误或不完整。

解决

Human: 实现时发现规格没考虑到并发修改购物车的情况

Claude: 好的,我们需要更新规格再继续实现。

1. 暂停实现
2. 更新 delta 添加并发场景:

#### Scenario: Concurrent cart modification
- **GIVEN** user has cart open on two devices
- **WHEN** both devices modify the cart
- **THEN** last-write-wins with timestamp
- **AND** other device is notified of changes

3. 重新验证
4. 继续实现

Claude Code 特定技巧

1. 利用 CLAUDE.md 增强工作流

在项目根目录创建 CLAUDE.md

markdown
# Project Instructions for Claude Code

## OpenSpec Workflow
- Always check `openspec list` before creating new changes
- Validate specs with `--strict` flag
- Follow existing spec naming conventions

## Code Generation Preferences
- Use TypeScript strict mode
- Add JSDoc comments for public APIs
- Include error handling in all async functions

## Testing Requirements
- Write unit tests for all new functions
- Integration tests for API endpoints
- E2E tests for critical user flows

2. 自定义命令模板

编辑 .claude/commands/openspec/proposal.md

markdown
# OpenSpec Proposal Command

You are creating an OpenSpec change proposal.

## Instructions
1. First, run `openspec list --specs` to see existing capabilities
2. Analyze the user's request: {{input}}
3. Determine affected specs
4. Create a comprehensive proposal with:
   - Clear "Why" section
   - Detailed "What Changes" list
   - Complete impact analysis

## Output Requirements
- Use Chinese for user-facing documentation
- Use English for code comments
- Include at least 3 scenarios per requirement

3. 批量操作

Human: 我有 5 个小的 bug 修复,不需要创建提案,直接实现

Claude: 理解。根据 OpenSpec 指南,以下情况可以跳过提案:
- Bug 修复(恢复预期行为)
- 拼写/格式修改
- 配置更新
- 测试添加(针对现有行为)

请告诉我这 5 个 bug,我直接修复:

1. ...
2. ...

本章小结

本章介绍了 OpenSpec 与 Claude Code 的深度集成:

  1. 斜杠命令/openspec:proposal/openspec:apply/openspec:archive
  2. 完整工作流:从提案创建到归档的全流程
  3. 高级用法:多规格变更、调试、Git 集成
  4. 常见问题:命令不显示、格式不一致、变更冲突等

Claude Code 与 OpenSpec 的结合让规格驱动开发变得自然流畅。AI 助手会自动遵循 AGENTS.md 中的工作流指令,确保输出符合规格要求。


完整示例代码

以下是一个完整的 Claude Code + OpenSpec 工作流自动化脚本:

bash
#!/bin/bash
# Claude Code + OpenSpec 工作流演示脚本
# 模拟完整的规格驱动开发流程

set -e

# 颜色定义
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

log() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[✓]${NC} $1"; }
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
step() { echo -e "${CYAN}[STEP]${NC} $1"; }

# 检查 OpenSpec
if ! command -v openspec &> /dev/null; then
    echo "请先安装 OpenSpec: npm install -g @fission-ai/openspec@latest"
    exit 1
fi

# 项目设置
PROJECT_DIR="claude-openspec-demo"
log "创建演示项目: $PROJECT_DIR"
rm -rf "$PROJECT_DIR"
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"

# 初始化 Git
git init -q
echo "node_modules/" > .gitignore

# ============================================
# Step 1: 初始化 OpenSpec(模拟选择 Claude Code)
# ============================================
step "1. 初始化 OpenSpec"

# 非交互式初始化
mkdir -p openspec/{specs,changes/archive}
mkdir -p .claude/commands/openspec

# 创建项目配置
cat > openspec/project.md << 'EOF'
# Project Context

## Overview
E-commerce platform demo for Claude Code + OpenSpec workflow.

## Tech Stack
- Language: TypeScript
- Runtime: Node.js 20
- Framework: Express
- Database: PostgreSQL + Prisma
- Frontend: React 18 + Vite

## Conventions

### API Design
- RESTful endpoints under /api/v1/
- Use consistent error response format:
  ```json
  { "error": { "code": "ERR_CODE", "message": "..." } }
  ```

### Code Style
- Use ESLint + Prettier
- Prefer async/await
- Use descriptive function names

### Testing
- Unit tests with Vitest
- Integration tests for APIs
- Minimum 80% coverage

## Security
- All user input must be validated
- Use parameterized queries
- JWT tokens expire in 24 hours
EOF

# 创建 AGENTS.md
cat > openspec/AGENTS.md << 'EOF'
# OpenSpec Instructions for Claude Code

## Quick Start
1. Run `openspec list` to see active changes
2. Run `openspec list --specs` to see existing specs
3. Use `/openspec:proposal` to create new changes

## Workflow
1. **Create**: Draft proposal with `/openspec:proposal`
2. **Review**: Refine specs until approved
3. **Implement**: Execute tasks with `/openspec:apply`
4. **Archive**: Complete with `/openspec:archive`

## Spec Format
- Use `### Requirement:` headers
- Use `#### Scenario:` for test cases
- Use **WHEN/THEN/AND** keywords
EOF

# 创建根目录 AGENTS.md
cat > AGENTS.md << 'EOF'
&lt;!-- OPENSPEC:START --&gt;
# Project Instructions

This project uses OpenSpec for spec-driven development.

**AI Assistants**: Please read `openspec/AGENTS.md` for workflow instructions.
&lt;!-- OPENSPEC:END --&gt;
EOF

# 创建 Claude Code 命令
cat > .claude/commands/openspec/proposal.md << 'EOF'
# OpenSpec Proposal Command

Create a new OpenSpec change proposal.

## Your Task
Based on the user's request, create a complete change proposal with:

1. **Check existing specs**: Run `openspec list --specs`
2. **Create change directory**: \`openspec/changes/\<change-id\>/\`
3. **Generate files**:
   - `proposal.md` - Why and what changes
   - `tasks.md` - Implementation checklist
   - \`specs/\<capability\>/spec.md\` - Delta specs

## Format Requirements
- Change ID: kebab-case, verb-led (add-, update-, remove-)
- Use `### Requirement:` headers (3 hashtags)
- Use `#### Scenario:` headers (4 hashtags)
- Use **WHEN/THEN/AND** keywords in bold

User Request: {{input}}
EOF

cat > .claude/commands/openspec/apply.md << 'EOF'
# OpenSpec Apply Command

Implement an approved OpenSpec change.

## Your Task
1. Read `openspec/changes/{{input}}/proposal.md`
2. Read `openspec/changes/{{input}}/tasks.md`
3. Execute tasks in order
4. Mark tasks complete as you go: `- [x]`

## Guidelines
- Follow project conventions in `openspec/project.md`
- Test each implementation before marking complete
- Create commits for logical units of work
EOF

cat > .claude/commands/openspec/archive.md << 'EOF'
# OpenSpec Archive Command

Archive a completed OpenSpec change.

## Your Task
1. Verify all tasks in `tasks.md` are marked complete
2. Run: `openspec archive {{input}} --yes`
3. Commit the changes

## Prerequisites
- All tasks must be [x] complete
- Code should be tested and deployed
EOF

success "OpenSpec 已初始化(配置 Claude Code)"

# ============================================
# Step 2: 创建初始规格(模拟现有系统)
# ============================================
step "2. 创建初始规格(模拟现有系统)"

mkdir -p openspec/specs/{product,user}

cat > openspec/specs/product/spec.md << 'EOF'
# Product Specification

## Purpose
Manage product catalog and inventory.

## Requirements

### Requirement: Product Listing
The system SHALL display products with pagination.

#### Scenario: List products
- **WHEN** user requests product list
- **THEN** system returns paginated results
- **AND** includes thumbnail, name, price

### Requirement: Product Details
The system SHALL show detailed product information.

#### Scenario: View product
- **GIVEN** product exists
- **WHEN** user requests product by ID
- **THEN** system returns full details
- **AND** includes stock availability
EOF

cat > openspec/specs/user/spec.md << 'EOF'
# User Specification

## Purpose
Handle user accounts and authentication.

## Requirements

### Requirement: User Registration
The system SHALL allow new user registration.

#### Scenario: Successful registration
- **WHEN** user submits valid email and password
- **THEN** account is created
- **AND** verification email is sent

### Requirement: User Login
The system SHALL authenticate users via email/password.

#### Scenario: Valid login
- **WHEN** user submits valid credentials
- **THEN** JWT token is returned
EOF

success "创建了 product 和 user 规格"

# ============================================
# Step 3: 创建购物车变更提案
# ============================================
step "3. 创建购物车变更提案(模拟 /openspec:proposal)"

CHANGE_ID="add-shopping-cart"
mkdir -p "openspec/changes/$CHANGE_ID/specs/shopping-cart"

cat > "openspec/changes/$CHANGE_ID/proposal.md" << 'EOF'
## Why
电商平台需要购物车功能,让用户能够:
- 在购买前收集多个商品
- 方便地管理购买意向
- 一次性完成多商品结账

## What Changes
- 新增购物车数据模型和 API
- 实现购物车 CRUD 操作
- 添加购物车 UI 组件

## Impact
- **New spec**: shopping-cart
- **Related specs**: product (stock check), user (cart ownership)
- **Affected code**:
  - `src/models/Cart.ts`
  - `src/routes/cart.ts`
  - `src/components/Cart/`
- **Breaking changes**: None
EOF

cat > "openspec/changes/$CHANGE_ID/tasks.md" << 'EOF'
# Tasks: Add Shopping Cart

## 1. Database & Models
- [ ] 1.1 Create Cart model with Prisma
- [ ] 1.2 Create CartItem model
- [ ] 1.3 Run database migration

## 2. API Implementation
- [ ] 2.1 GET /api/v1/cart - Get user's cart
- [ ] 2.2 POST /api/v1/cart/items - Add item
- [ ] 2.3 PUT /api/v1/cart/items/:id - Update quantity
- [ ] 2.4 DELETE /api/v1/cart/items/:id - Remove item
- [ ] 2.5 DELETE /api/v1/cart - Clear cart

## 3. Business Logic
- [ ] 3.1 Stock validation on add/update
- [ ] 3.2 Price calculation service
- [ ] 3.3 Cart persistence for logged-in users

## 4. Testing
- [ ] 4.1 Unit tests for cart service
- [ ] 4.2 Integration tests for cart API
- [ ] 4.3 E2E test for cart flow
EOF

cat > "openspec/changes/$CHANGE_ID/specs/shopping-cart/spec.md" << 'EOF'
# Shopping Cart Specification

## Purpose
Enable users to collect and manage products before checkout.

## Requirements

### Requirement: Add to Cart
The system SHALL allow users to add products to their shopping cart.

#### Scenario: Add new item
- **GIVEN** user is viewing a product
- **WHEN** user clicks "Add to Cart"
- **AND** product is in stock
- **THEN** product is added to cart with quantity 1
- **AND** cart count is updated in header

#### Scenario: Add existing item
- **GIVEN** product is already in cart
- **WHEN** user adds same product again
- **THEN** quantity increases by 1
- **AND** no duplicate entries are created

#### Scenario: Out of stock
- **WHEN** user tries to add out-of-stock product
- **THEN** "Out of Stock" message is shown
- **AND** product is not added

### Requirement: Update Cart Item
The system SHALL allow users to change item quantities.

#### Scenario: Increase quantity
- **GIVEN** item is in cart
- **WHEN** user increases quantity
- **AND** requested quantity is available
- **THEN** quantity is updated
- **AND** subtotal is recalculated

#### Scenario: Decrease quantity
- **GIVEN** item quantity is greater than 1
- **WHEN** user decreases quantity
- **THEN** quantity is reduced by 1
- **AND** subtotal is recalculated

#### Scenario: Set to zero
- **GIVEN** item is in cart
- **WHEN** user sets quantity to 0
- **THEN** item is removed from cart

### Requirement: Remove from Cart
The system SHALL allow users to remove items.

#### Scenario: Remove item
- **WHEN** user clicks remove on cart item
- **THEN** item is removed immediately
- **AND** cart total is updated
- **AND** undo option is available for 5 seconds

### Requirement: Cart Persistence
The system SHALL persist cart for logged-in users.

#### Scenario: Cart survives logout
- **GIVEN** user has items in cart
- **WHEN** user logs out and logs back in
- **THEN** cart contents are preserved

#### Scenario: Guest to user merge
- **GIVEN** guest has items in cart
- **WHEN** guest creates account or logs in
- **THEN** guest cart merges with user cart
- **AND** quantities are summed for duplicates
EOF

success "创建了购物车变更提案"

# ============================================
# Step 4: 验证变更
# ============================================
step "4. 验证变更规格"

echo ""
echo "运行: openspec validate $CHANGE_ID --strict"
openspec validate "$CHANGE_ID" --strict 2>/dev/null || warn "验证完成(可能有警告)"

# ============================================
# Step 5: 显示当前状态
# ============================================
step "5. 显示 OpenSpec 状态"

echo ""
echo "=== 活跃变更 ==="
openspec list 2>/dev/null || echo "(使用 openspec list 查看)"

echo ""
echo "=== 现有规格 ==="
openspec list --specs 2>/dev/null || find openspec/specs -name "spec.md" | sed 's/.*specs\//  /' | sed 's/\/spec.md//'

# ============================================
# Step 6: 模拟实现(标记任务完成)
# ============================================
step "6. 模拟实现完成(/openspec:apply)"

# 模拟代码实现
mkdir -p src/{models,routes,services}

cat > src/models/Cart.ts << 'TYPESCRIPT'
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export interface CartItem {
  id: string;
  productId: string;
  quantity: number;
  price: number;
}

export interface Cart {
  id: string;
  userId: string;
  items: CartItem[];
  total: number;
}

export async function getCart(userId: string): Promise<Cart | null> {
  return prisma.cart.findUnique({
    where: { userId },
    include: { items: true }
  });
}

export async function addToCart(
  userId: string,
  productId: string,
  quantity: number
): Promise<CartItem> {
  // Check stock availability
  const product = await prisma.product.findUnique({
    where: { id: productId }
  });

  if (!product || product.stock < quantity) {
    throw new Error('INSUFFICIENT_STOCK');
  }

  // Upsert cart item
  return prisma.cartItem.upsert({
    where: { cartId_productId: { cartId: userId, productId } },
    update: { quantity: { increment: quantity } },
    create: { cartId: userId, productId, quantity, price: product.price }
  });
}

export async function updateQuantity(
  userId: string,
  itemId: string,
  quantity: number
): Promise<CartItem | null> {
  if (quantity <= 0) {
    await prisma.cartItem.delete({ where: { id: itemId } });
    return null;
  }

  return prisma.cartItem.update({
    where: { id: itemId },
    data: { quantity }
  });
}

export async function removeFromCart(
  userId: string,
  itemId: string
): Promise<void> {
  await prisma.cartItem.delete({
    where: { id: itemId, cart: { userId } }
  });
}

export async function clearCart(userId: string): Promise<void> {
  await prisma.cartItem.deleteMany({
    where: { cart: { userId } }
  });
}
TYPESCRIPT

cat > src/routes/cart.ts << 'TYPESCRIPT'
import { Router } from 'express';
import * as Cart from '../models/Cart';
import { authenticate } from '../middleware/auth';

const router = Router();

// GET /api/v1/cart
router.get('/', authenticate, async (req, res) => {
  try {
    const cart = await Cart.getCart(req.user.id);
    res.json(cart || { items: [], total: 0 });
  } catch (error) {
    res.status(500).json({ error: { code: 'CART_ERROR', message: 'Failed to fetch cart' } });
  }
});

// POST /api/v1/cart/items
router.post('/items', authenticate, async (req, res) => {
  try {
    const { productId, quantity = 1 } = req.body;
    const item = await Cart.addToCart(req.user.id, productId, quantity);
    res.status(201).json(item);
  } catch (error) {
    if (error.message === 'INSUFFICIENT_STOCK') {
      res.status(400).json({ error: { code: 'INSUFFICIENT_STOCK', message: 'Not enough stock' } });
    } else {
      res.status(500).json({ error: { code: 'ADD_FAILED', message: 'Failed to add item' } });
    }
  }
});

// PUT /api/v1/cart/items/:id
router.put('/items/:id', authenticate, async (req, res) => {
  try {
    const { quantity } = req.body;
    const item = await Cart.updateQuantity(req.user.id, req.params.id, quantity);
    res.json(item || { deleted: true });
  } catch (error) {
    res.status(500).json({ error: { code: 'UPDATE_FAILED', message: 'Failed to update item' } });
  }
});

// DELETE /api/v1/cart/items/:id
router.delete('/items/:id', authenticate, async (req, res) => {
  try {
    await Cart.removeFromCart(req.user.id, req.params.id);
    res.status(204).send();
  } catch (error) {
    res.status(500).json({ error: { code: 'DELETE_FAILED', message: 'Failed to remove item' } });
  }
});

// DELETE /api/v1/cart
router.delete('/', authenticate, async (req, res) => {
  try {
    await Cart.clearCart(req.user.id);
    res.status(204).send();
  } catch (error) {
    res.status(500).json({ error: { code: 'CLEAR_FAILED', message: 'Failed to clear cart' } });
  }
});

export default router;
TYPESCRIPT

# 标记任务完成
sed -i.bak 's/\[ \]/[x]/g' "openspec/changes/$CHANGE_ID/tasks.md"
rm "openspec/changes/$CHANGE_ID/tasks.md.bak"

success "实现完成,所有任务已标记"

# ============================================
# Step 7: 归档变更
# ============================================
step "7. 归档变更(/openspec:archive)"

openspec archive "$CHANGE_ID" --yes 2>/dev/null || {
    # 手动归档
    mkdir -p "openspec/changes/archive/$(date +%Y-%m-%d)-$CHANGE_ID"
    mv "openspec/changes/$CHANGE_ID"/* "openspec/changes/archive/$(date +%Y-%m-%d)-$CHANGE_ID/"
    rmdir "openspec/changes/$CHANGE_ID"

    # 复制规格到 specs
    mkdir -p openspec/specs/shopping-cart
    cp "openspec/changes/archive/$(date +%Y-%m-%d)-$CHANGE_ID/specs/shopping-cart/spec.md" \
       openspec/specs/shopping-cart/spec.md

    success "手动归档完成"
}

# ============================================
# Step 8: 提交到 Git
# ============================================
step "8. 提交到 Git"

git add .
git commit -m "feat(cart): add shopping cart functionality

Implemented via OpenSpec workflow:
- Cart model and CRUD operations
- REST API endpoints
- Stock validation

Spec: openspec/specs/shopping-cart/spec.md"

# ============================================
# 最终状态
# ============================================
echo ""
echo "========================================"
echo "  Claude Code + OpenSpec 演示完成!"
echo "========================================"
echo ""
echo "项目结构:"
find . -type f -name "*.md" -o -name "*.ts" | grep -v node_modules | sort

echo ""
echo "规格列表:"
find openspec/specs -name "spec.md" | sed 's/.*specs\//  /' | sed 's/\/spec.md//'

echo ""
echo "工作流总结:"
echo "1. ✓ 初始化 OpenSpec + Claude Code"
echo "2. ✓ 创建变更提案 (proposal.md, tasks.md, spec delta)"
echo "3. ✓ 验证规格格式"
echo "4. ✓ 实现任务并标记完成"
echo "5. ✓ 归档变更到 archive/"
echo "6. ✓ 提交到 Git"
echo ""
echo "在实际使用中,Claude Code 会通过以下命令自动执行:"
echo "  /openspec:proposal Add shopping cart"
echo "  /openspec:apply add-shopping-cart"
echo "  /openspec:archive add-shopping-cart"

将此脚本保存为 claude-openspec-demo.sh,然后执行:

bash
chmod +x claude-openspec-demo.sh
./claude-openspec-demo.sh

这个脚本完整演示了 Claude Code + OpenSpec 的工作流:

  1. 初始化项目和 Claude Code 命令
  2. 创建初始规格(模拟现有系统)
  3. 创建变更提案(模拟 /openspec:proposal
  4. 验证规格格式
  5. 实现代码(模拟 /openspec:apply
  6. 归档变更(模拟 /openspec:archive
  7. 提交到 Git

基于 MIT 许可证发布。内容版权归作者所有。