docs(zh-CN): update

This commit is contained in:
neo
2026-03-13 17:45:44 +08:00
parent f548ca3e19
commit 4c0107a322
88 changed files with 16872 additions and 280 deletions

View File

@@ -0,0 +1,173 @@
---
description: 在不打断或丢失当前任务上下文的情况下,快速回答一个附带问题。回答后自动恢复工作。
---
# 旁述指令
在任务进行中提问,获得即时、聚焦的回答——然后立即从暂停处继续。当前任务、文件和上下文绝不会被修改。
## 何时使用
* 你在 Claude 工作时对某事感到好奇,但又不想打断工作节奏
* 你需要快速解释 Claude 当前正在编辑的代码
* 你想就某个决定征求第二意见或进行澄清,而不会使任务偏离方向
* 在 Claude 继续之前,你需要理解一个错误、概念或模式
* 你想询问与当前任务无关的事情,而无需开启新会话
## 使用方法
```
/aside <your question>
/aside what does this function actually return?
/aside is this pattern thread-safe?
/aside why are we using X instead of Y here?
/aside what's the difference between foo() and bar()?
/aside should we be worried about the N+1 query we just added?
```
## 流程
### 步骤 1冻结当前任务状态
在回答任何问题之前,先在心里记下:
* 当前活动任务是什么?(正在处理哪个文件、功能或问题)
* 在调用 `/aside` 时,进行到哪一步了?
* 接下来原本要发生什么?
在旁述期间,**不要**触碰、编辑、创建或删除任何文件。
### 步骤 2直接回答问题
以最简洁但仍完整有用的形式回答问题。
* 先说答案,再说推理过程
* 保持简短——如果需要完整解释,请在任务结束后再提供
* 如果问题涉及当前正在处理的文件或代码,请精确引用(相关时包括文件路径和行号)
* 如果回答问题需要读取文件,就读它——但只读不写
将响应格式化为:
```
ASIDE: [restate the question briefly]
[Your answer here]
— Back to task: [one-line description of what was being done]
```
### 步骤 3恢复主任务
在给出答案后,立即从暂停的确切点继续执行活动任务。除非旁述回答揭示了阻碍或需要重新考虑当前方法的理由(见边缘情况),否则不要请求恢复许可。
***
## 边缘情况
**未提供问题(`/aside` 后面没有内容):**
回复:
```
ASIDE: no question provided
What would you like to know? (ask your question and I'll answer without losing the current task context)
— Back to task: [one-line description of what was being done]
```
**问题揭示了当前任务的潜在问题:**
在恢复之前清楚地标记出来:
```
ASIDE: [answer]
⚠️ Note: This answer suggests [issue] with the current approach. Want to address this before continuing, or proceed as planned?
```
等待用户的决定后再恢复。
**问题实际上是任务重定向(而非旁述问题):**
如果问题暗示要改变正在构建的内容(例如,`/aside actually, let's use Redis instead`),请澄清:
```
ASIDE: That sounds like a direction change, not just a side question.
Do you want to:
(a) Answer this as information only and keep the current plan
(b) Pause the current task and change approach
```
等待用户的回答——不要自行假设。
**问题涉及当前打开的文件或代码:**
根据实时上下文回答。如果该文件在会话早期已被读取,直接引用它。如果尚未读取,现在读取它(只读)并在回答时附带文件:行号引用。
**无活动任务(调用 `/aside` 时没有进行中的任务):**
仍然使用标准包装器,以保持响应格式一致:
```
ASIDE: [restate the question briefly]
[Your answer here]
— Back to task: no active task to resume
```
**问题需要长篇回答:**
简洁地给出核心答案,然后提供:
```
That's the short version. Want a deeper explanation after we finish [current task]?
```
**连续多个 `/aside` 问题:**
依次回答每个问题。在回答完最后一个问题后,恢复主任务。不要在一连串旁述中丢失任务状态。
**旁述回答暗示需要进行代码更改:**
记下所需的更改,但不要在旁述期间进行更改:
```
ASIDE: [answer]
📝 Worth fixing: [what should be changed]. I'll flag this after the current task unless you want to address it now.
```
**问题含糊不清或过于笼统:**
提出一个澄清性问题——一个能获取回答所需信息的最简短问题。不要提出多个问题。
***
## 示例输出
```
User: /aside what does fetchWithRetry() actually do?
ASIDE: what does fetchWithRetry() do?
fetchWithRetry() (src/api/retry.ts:12) attempts the request up to 3 times with
exponential backoff (250ms → 500ms → 1s). It only retries on 5xx responses and
network errors — 4xx errors are treated as final and not retried.
— Back to task: refactoring the auth middleware in src/middleware/auth.ts
```
```
User: /aside is the approach we're taking thread-safe?
ASIDE: is the current approach thread-safe?
No — the shared cache object in src/cache/store.ts:34 is mutated without locking.
Under concurrent requests this is a race condition. It's low risk in a single-process
Node.js server but would be a real problem with worker threads or clustering.
⚠️ Note: This could affect the feature we're building. Want to address this now or continue and fix it in a follow-up?
```
***
## 注意事项
* 在旁述期间**绝不**修改文件——仅限只读访问
* 旁述是对话暂停,不是新任务——必须始终恢复原始任务
* 保持回答聚焦:目标是快速为用户扫清障碍,而不是进行长篇大论
* 如果旁述引发了更广泛的讨论,请先完成当前任务,除非旁述揭示了阻碍
* 除非明确与任务结果相关,否则旁述内容不会保存到会话文件中

View File

@@ -345,7 +345,10 @@ Quarantine recommendation: Mark as test.fixme() until fixed
## 相关代理
此命令调用位于 `~/.claude/agents/e2e-runner.md` 的 `e2e-runner` 代理。
此命令调用由 ECC 提供的 `e2e-runner` 代理。
对于手动安装,源文件位于:
`agents/e2e-runner.md`
## 快速命令

View File

@@ -0,0 +1,72 @@
---
description: 修复 Android 和 KMP 项目的 Gradle 构建错误
---
# Gradle 构建修复
逐步修复 Android 和 Kotlin 多平台项目的 Gradle 构建和编译错误。
## 步骤 1检测构建配置
识别项目类型并运行相应的构建:
| 指示符 | 构建命令 |
|-----------|---------------|
| `build.gradle.kts` + `composeApp/` (KMP) | `./gradlew composeApp:compileKotlinMetadata 2>&1` |
| `build.gradle.kts` + `app/` (Android) | `./gradlew app:compileDebugKotlin 2>&1` |
| `settings.gradle.kts` 包含模块 | `./gradlew assemble 2>&1` |
| 配置了 Detekt | `./gradlew detekt 2>&1` |
同时检查 `gradle.properties``local.properties` 以获取配置信息。
## 步骤 2解析并分组错误
1. 运行构建命令并捕获输出
2. 将 Kotlin 编译错误与 Gradle 配置错误分开
3. 按模块和文件路径分组
4. 排序:先处理配置错误,然后按依赖顺序处理编译错误
## 步骤 3修复循环
针对每个错误:
1. **读取文件** — 错误行周围的完整上下文
2. **诊断** — 常见类别:
* 缺少导入或无法解析的引用
* 类型不匹配或不兼容的类型
* `build.gradle.kts` 中缺少依赖项
* Expect/actual 不匹配 (KMP)
* Compose 编译器错误
3. **最小化修复** — 解决错误所需的最小改动
4. **重新运行构建** — 验证修复并检查新错误
5. **继续** — 处理下一个错误
## 步骤 4防护措施
如果出现以下情况,请停止并询问用户:
* 修复引入的错误比解决的错误多
* 同一错误在 3 次尝试后仍然存在
* 错误需要添加新的依赖项或更改模块结构
* Gradle 同步本身失败(配置阶段错误)
* 错误出现在生成的代码中Room、SQLDelight、KSP
## 步骤 5总结
报告:
* 已修复的错误(模块、文件、描述)
* 剩余的错误
* 引入的新错误(应为零)
* 建议的后续步骤
## 常见的 Gradle/KMP 修复方案
| 错误 | 修复方法 |
|-------|-----|
| `commonMain` 中无法解析的引用 | 检查依赖项是否在 `commonMain.dependencies {}` 中 |
| Expect 声明没有 actual 实现 | 在每个平台源码集中添加 `actual` 实现 |
| Compose 编译器版本不匹配 | 在 `libs.versions.toml` 中统一 Kotlin 和 Compose 编译器版本 |
| 重复类 | 使用 `./gradlew dependencies` 检查是否存在冲突的依赖项 |
| KSP 错误 | 运行 `./gradlew kspCommonMainKotlinMetadata` 重新生成 |
| 配置缓存问题 | 检查是否存在不可序列化的任务输入 |

View File

@@ -0,0 +1,176 @@
---
description: 逐步修复 Kotlin/Gradle 构建错误、编译器警告和依赖项问题。调用 kotlin-build-resolver 代理进行最小化、精准的修复。
---
# Kotlin 构建与修复
此命令调用 **kotlin-build-resolver** 代理,以最小的改动增量修复 Kotlin 构建错误。
## 此命令的作用
1. **运行诊断**:执行 `./gradlew build``detekt``ktlintCheck`
2. **解析错误**:按文件分组并按严重性排序
3. **增量修复**:每次修复一个错误
4. **验证每次修复**:每次更改后重新运行构建
5. **报告摘要**:显示已修复的内容和剩余问题
## 何时使用
在以下情况使用 `/kotlin-build`
* `./gradlew build` 因错误而失败
* Kotlin 编译器报告错误
* `./gradlew detekt` 报告违规
* Gradle 依赖项解析失败
* 拉取更改后导致构建失败
## 运行的诊断命令
```bash
# Primary build check
./gradlew build 2>&1
# Static analysis
./gradlew detekt 2>&1 || echo "detekt not configured"
./gradlew ktlintCheck 2>&1 || echo "ktlint not configured"
# Dependency issues
./gradlew dependencies --configuration runtimeClasspath 2>&1 | head -100
# Optional deep refresh when caches or dependency metadata are suspect
./gradlew build --refresh-dependencies
```
## 示例会话
````text
User: /kotlin-build
Agent:
# Kotlin Build Resolution
## Initial Diagnostics
```bash
$ ./gradlew build
e: src/main/kotlin/com/example/service/UserService.kt:25:15 Unresolved reference: UserRepository
e: src/main/kotlin/com/example/routes/UserRoutes.kt:42:9 Type mismatch: inferred type is String but Int was expected
e: src/main/kotlin/com/example/routes/UserRoutes.kt:58:5 'when' expression must be exhaustive
```
Errors found: 3
## Fix 1: Unresolved Reference
File: src/main/kotlin/com/example/service/UserService.kt:25
Error: Unresolved reference: UserRepository
Cause: Missing import
```kotlin
// Added import
import com.example.repository.UserRepository
```
```bash
$ ./gradlew build
# 2 errors remaining
```
## Fix 2: Type Mismatch
File: src/main/kotlin/com/example/routes/UserRoutes.kt:42
Error: Type mismatch: inferred type is String but Int was expected
```kotlin
// Changed
val count = call.parameters["count"]
// To
val count = call.parameters["count"]?.toIntOrNull()
?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid count")
```
```bash
$ ./gradlew build
# 1 error remaining
```
## Fix 3: Non-Exhaustive When
File: src/main/kotlin/com/example/routes/UserRoutes.kt:58
Error: 'when' expression must be exhaustive
```kotlin
// Added missing branch
when (user.role) {
Role.ADMIN -> handleAdmin(user)
Role.USER -> handleUser(user)
Role.MODERATOR -> handleModerator(user) // Added
}
```
```bash
$ ./gradlew build
# Build successful!
```
## Final Verification
```bash
$ ./gradlew detekt
# No issues
$ ./gradlew test
# All tests passed
```
## Summary
| Metric | Count |
|--------|-------|
| Build errors fixed | 3 |
| Detekt issues fixed | 0 |
| Files modified | 2 |
| Remaining issues | 0 |
Build Status: ✅ SUCCESS
````
## 常见的已修复错误
| 错误 | 典型修复方法 |
|-------|-------------|
| `Unresolved reference: X` | 添加导入或依赖项 |
| `Type mismatch` | 修复类型转换或赋值 |
| `'when' must be exhaustive` | 添加缺失的密封类分支 |
| `Suspend function can only be called from coroutine` | 添加 `suspend` 修饰符 |
| `Smart cast impossible` | 使用局部 `val` 或 `let` |
| `None of the following candidates is applicable` | 修复参数类型 |
| `Could not resolve dependency` | 修复版本或添加仓库 |
## 修复策略
1. **首先修复构建错误** - 代码必须能够编译
2. **其次修复 Detekt 违规** - 修复代码质量问题
3. **再次修复 ktlint 警告** - 修复格式问题
4. **一次修复一个** - 验证每次更改
5. **最小化改动** - 不进行重构,仅修复问题
## 停止条件
代理将在以下情况下停止并报告:
* 同一错误尝试修复 3 次后仍然存在
* 修复引入了更多错误
* 需要进行架构性更改
* 缺少外部依赖项
## 相关命令
* `/kotlin-test` - 构建成功后运行测试
* `/kotlin-review` - 审查代码质量
* `/verify` - 完整的验证循环
## 相关
* 代理:`agents/kotlin-build-resolver.md`
* 技能:`skills/kotlin-patterns/`

View File

@@ -0,0 +1,144 @@
---
description: 全面的Kotlin代码审查涵盖惯用模式、空安全、协程安全和安全性。调用kotlin-reviewer代理。
---
# Kotlin 代码审查
此命令调用 **kotlin-reviewer** 代理进行全面的 Kotlin 专项代码审查。
## 此命令的功能
1. **识别 Kotlin 变更**:通过 `git diff` 查找修改过的 `.kt``.kts` 文件
2. **运行构建与静态分析**:执行 `./gradlew build``detekt``ktlintCheck`
3. **安全扫描**:检查 SQL 注入、命令注入、硬编码的密钥
4. **空安全审查**:分析 `!!` 的使用、平台类型处理、不安全的转换
5. **协程审查**:检查结构化并发、调度器使用、取消操作
6. **生成报告**:按严重性对问题分类
## 使用时机
在以下情况使用 `/kotlin-review`
* 编写或修改 Kotlin 代码后
* 提交 Kotlin 变更前
* 审查包含 Kotlin 代码的拉取请求时
* 接手新的 Kotlin 代码库时
* 学习 Kotlin 惯用模式时
## 审查类别
### 严重(必须修复)
* SQL/命令注入漏洞
* 无正当理由强制解包 `!!`
* 平台类型空安全违规
* 使用 GlobalScope违反结构化并发
* 硬编码的凭证
* 不安全的反序列化
### 高(应该修复)
* 可变状态,而不可变状态即可满足
* 在协程上下文中进行阻塞调用
* 长循环中缺少取消检查
* 对密封类型使用非穷举的 `when`
* 函数过大(>50 行)
* 嵌套过深(>4 层)
### 中(考虑修复)
* 非 Kotlin 惯用写法Java 风格模式)
* 缺少尾随逗号
* 误用或嵌套作用域函数
* 大型集合链中缺少序列化
* 冗余的显式类型声明
## 运行的自动化检查
```bash
# Build check
./gradlew build
# Static analysis
./gradlew detekt
# Formatting check
./gradlew ktlintCheck
# Tests
./gradlew test
```
## 使用示例
````text
User: /kotlin-review
Agent:
# Kotlin Code Review Report
## Files Reviewed
- src/main/kotlin/com/example/service/UserService.kt (modified)
- src/main/kotlin/com/example/routes/UserRoutes.kt (modified)
## Static Analysis Results
✓ Build: Successful
✓ detekt: No issues
⚠ ktlint: 2 formatting warnings
## Issues Found
[CRITICAL] Force-Unwrap Null Safety
File: src/main/kotlin/com/example/service/UserService.kt:28
Issue: Using !! on nullable repository result
```kotlin
val user = repository.findById(id)!! // NPE risk
```
Fix: Use safe call with error handling
```kotlin
val user = repository.findById(id)
?: throw UserNotFoundException("User $id not found")
```
[HIGH] GlobalScope Usage
File: src/main/kotlin/com/example/routes/UserRoutes.kt:45
Issue: Using GlobalScope breaks structured concurrency
```kotlin
GlobalScope.launch {
notificationService.sendWelcome(user)
}
```
Fix: Use the call's coroutine scope
```kotlin
launch {
notificationService.sendWelcome(user)
}
```
## Summary
- CRITICAL: 1
- HIGH: 1
- MEDIUM: 0
Recommendation: ❌ Block merge until CRITICAL issue is fixed
````
## 批准标准
| 状态 | 条件 |
|--------|-----------|
| ✅ 批准 | 无严重或高优先级问题 |
| ⚠️ 警告 | 仅存在中优先级问题(谨慎合并) |
| ❌ 阻止 | 发现严重或高优先级问题 |
## 与其他命令的集成
* 首先使用 `/kotlin-test` 确保测试通过
* 如果构建出错,使用 `/kotlin-build`
* 提交前使用 `/kotlin-review`
* 对于非 Kotlin 专项问题,使用 `/code-review`
## 相关
* 代理:`agents/kotlin-reviewer.md`
* 技能:`skills/kotlin-patterns/`、`skills/kotlin-testing/`

View File

@@ -0,0 +1,315 @@
---
description: 为Kotlin强制执行TDD工作流程。首先编写Kotest测试然后实施。使用Kover验证80%以上的覆盖率。
---
# Kotlin TDD 命令
此命令使用 Kotest、MockK 和 Kover 为 Kotlin 代码强制执行测试驱动开发方法。
## 此命令的作用
1. **定义类型/接口**:首先搭建函数签名
2. **编写 Kotest 测试**创建全面的测试规范RED
3. **运行测试**:验证测试因正确原因而失败
4. **实现代码**编写最少的代码以通过测试GREEN
5. **重构**:在保持测试通过的同时进行改进
6. **检查覆盖率**:确保使用 Kover 达到 80% 以上的覆盖率
## 何时使用
在以下情况下使用 `/kotlin-test`
* 实现新的 Kotlin 函数或类
* 为现有的 Kotlin 代码添加测试覆盖率
* 修复错误(首先编写失败的测试)
* 构建关键业务逻辑
* 学习 Kotlin 中的 TDD 工作流程
## TDD 循环
```
RED -> Write failing Kotest test
GREEN -> Implement minimal code to pass
REFACTOR -> Improve code, tests stay green
REPEAT -> Next test case
```
## 示例会话
````text
User: /kotlin-test I need a function to validate user registration requests
Agent:
# TDD Session: Registration Validator
## Step 1: Define Interface
```kotlin
// validator/RegistrationValidator.kt
package com.example.validator
data class RegistrationRequest(
val name: String,
val email: String,
val password: String,
)
sealed class ValidationResult {
data object Valid : ValidationResult()
data class Invalid(val errors: List<String>) : ValidationResult()
}
fun validateRegistration(request: RegistrationRequest): ValidationResult {
TODO("not implemented")
}
```
## Step 2: Write Kotest Tests (RED)
```kotlin
// validator/RegistrationValidatorTest.kt
package com.example.validator
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf
class RegistrationValidatorTest : FunSpec({
test("valid registration returns Valid") {
val request = RegistrationRequest(
name = "Alice",
email = "alice@example.com",
password = "SecureP@ss1",
)
val result = validateRegistration(request)
result.shouldBeInstanceOf<ValidationResult.Valid>()
}
test("blank name returns Invalid") {
val request = RegistrationRequest(
name = "",
email = "alice@example.com",
password = "SecureP@ss1",
)
val result = validateRegistration(request)
val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
invalid.errors shouldBe listOf("Name is required")
}
test("invalid email returns Invalid") {
val request = RegistrationRequest(
name = "Alice",
email = "not-an-email",
password = "SecureP@ss1",
)
val result = validateRegistration(request)
val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
invalid.errors shouldBe listOf("Invalid email format")
}
test("short password returns Invalid") {
val request = RegistrationRequest(
name = "Alice",
email = "alice@example.com",
password = "short",
)
val result = validateRegistration(request)
val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
invalid.errors shouldBe listOf("Password must be at least 8 characters")
}
test("multiple errors returns all errors") {
val request = RegistrationRequest(
name = "",
email = "bad",
password = "short",
)
val result = validateRegistration(request)
val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
invalid.errors.size shouldBe 3
}
})
```
## Step 3: Run Tests - Verify FAIL
```bash
$ ./gradlew test
RegistrationValidatorTest > valid registration returns Valid FAILED
kotlin.NotImplementedError: An operation is not implemented
FAILED (5 tests, 0 passed, 5 failed)
```
✓ Tests fail as expected (NotImplementedError).
## Step 4: Implement Minimal Code (GREEN)
```kotlin
// validator/RegistrationValidator.kt
package com.example.validator
private val EMAIL_REGEX = Regex("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")
private const val MIN_PASSWORD_LENGTH = 8
fun validateRegistration(request: RegistrationRequest): ValidationResult {
val errors = buildList {
if (request.name.isBlank()) add("Name is required")
if (!EMAIL_REGEX.matches(request.email)) add("Invalid email format")
if (request.password.length < MIN_PASSWORD_LENGTH) add("Password must be at least $MIN_PASSWORD_LENGTH characters")
}
return if (errors.isEmpty()) ValidationResult.Valid
else ValidationResult.Invalid(errors)
}
```
## Step 5: Run Tests - Verify PASS
```bash
$ ./gradlew test
RegistrationValidatorTest > valid registration returns Valid PASSED
RegistrationValidatorTest > blank name returns Invalid PASSED
RegistrationValidatorTest > invalid email returns Invalid PASSED
RegistrationValidatorTest > short password returns Invalid PASSED
RegistrationValidatorTest > multiple errors returns all errors PASSED
PASSED (5 tests, 5 passed, 0 failed)
```
✓ All tests passing!
## Step 6: Check Coverage
```bash
$ ./gradlew koverHtmlReport
Coverage: 100.0% of statements
```
✓ Coverage: 100%
## TDD Complete!
````
## 测试模式
### StringSpec最简单
```kotlin
class CalculatorTest : StringSpec({
"add two positive numbers" {
Calculator.add(2, 3) shouldBe 5
}
})
```
### BehaviorSpecBDD
```kotlin
class OrderServiceTest : BehaviorSpec({
Given("a valid order") {
When("placed") {
Then("should be confirmed") { /* ... */ }
}
}
})
```
### 数据驱动测试
```kotlin
class ParserTest : FunSpec({
context("valid inputs") {
withData("2026-01-15", "2026-12-31", "2000-01-01") { input ->
parseDate(input).shouldNotBeNull()
}
}
})
```
### 协程测试
```kotlin
class AsyncServiceTest : FunSpec({
test("concurrent fetch completes") {
runTest {
val result = service.fetchAll()
result.shouldNotBeEmpty()
}
}
})
```
## 覆盖率命令
```bash
# Run tests with coverage
./gradlew koverHtmlReport
# Verify coverage thresholds
./gradlew koverVerify
# XML report for CI
./gradlew koverXmlReport
# Open HTML report
open build/reports/kover/html/index.html
# Run specific test class
./gradlew test --tests "com.example.UserServiceTest"
# Run with verbose output
./gradlew test --info
```
## 覆盖率目标
| 代码类型 | 目标 |
|-----------|--------|
| 关键业务逻辑 | 100% |
| 公共 API | 90%+ |
| 通用代码 | 80%+ |
| 生成的代码 | 排除 |
## TDD 最佳实践
**应做:**
* 首先编写测试,在任何实现之前
* 每次更改后运行测试
* 使用 Kotest 匹配器进行表达性断言
* 使用 MockK 的 `coEvery`/`coVerify` 来处理挂起函数
* 测试行为,而非实现细节
* 包含边界情况空值、null、最大值
**不应做:**
* 在测试之前编写实现
* 跳过 RED 阶段
* 直接测试私有函数
* 在协程测试中使用 `Thread.sleep()`
* 忽略不稳定的测试
## 相关命令
* `/kotlin-build` - 修复构建错误
* `/kotlin-review` - 在实现后审查代码
* `/verify` - 运行完整的验证循环
## 相关
* 技能:`skills/kotlin-testing/`
* 技能:`skills/tdd-workflow/`

View File

@@ -1,10 +1,10 @@
---
description: 从会话中提取可重用模式,在保存前自我评估质量,并确定正确的保存位置(全局与项目)。
description: "从会话中提取可重用模式,在保存前自我评估质量,并确定正确的保存位置(全局与项目)。"
---
# /learn-eval - 提取、评估、然后保存
扩展 `/learn`,在写任何技能文件之前加入质量门保存位置决策。
扩展 `/learn`,在写任何技能文件之前加入质量门控、保存位置决策和知识放置意识
## 提取内容
@@ -52,41 +52,66 @@ origin: auto-extracted
[触发条件]
```
5. **在保存前自我评估**,使用此评分标准:
5. **质量门控 — 清单 + 整体裁决**
| 维度 | 1 | 3 | 5 |
|-----------|---|---|---|
| 具体性 | 仅抽象原则,无代码示例 | 有代表性代码示例 | 包含所有使用模式的丰富示例 |
| 可操作性 | 不清楚要做什么 | 主要步骤可理解 | 立即可操作,涵盖边界情况 |
| 范围契合度 | 过于宽泛或过于狭窄 | 基本合适,存在一些边界模糊 | 名称、触发器和内容完美匹配 |
| 非冗余性 | 几乎与另一技能相同 | 存在一些重叠但有独特视角 | 完全独特的价值 |
| 覆盖率 | 仅涵盖目标任务的一小部分 | 涵盖主要情况,缺少常见变体 | 涵盖主要情况、边界情况和陷阱 |
### 5a. 必需清单(通过实际阅读文件进行验证)
* 为每个维度评分 15
* 如果任何维度评分为 12改进草案并重新评分直到所有维度 ≥ 3
* 向用户展示评分表和最终草案
在评估草案**之前**,执行以下所有操作:
6. 请求用户确认:
* 展示:提议的保存路径 + 评分表 + 最终草案
* 在写入前等待明确确认
* \[ ] 使用关键字在 `~/.claude/skills/` 和相关项目的 `.claude/skills/` 文件中进行 grep 搜索,检查内容重叠
* \[ ] 检查 MEMORY.md项目级和全局级以查找重叠内容
* \[ ] 考虑是否追加到现有技能即可满足需求
* \[ ] 确认这是一个可复用的模式,而非一次性修复
7. 保存到确定的位置
### 5b. 整体裁决
## 第 5 步的输出格式(评分表)
综合清单结果和草案质量,然后选择**以下一项**
| 维度 | 评分 | 理由 |
|-----------|-------|-----------|
| 具体性 | N/5 | ... |
| 可操作性 | N/5 | ... |
| 范围契合度 | N/5 | ... |
| 非冗余性 | N/5 | ... |
| 覆盖率 | N/5 | ... |
| **总计** | **N/25** | |
| 裁决 | 含义 | 下一步行动 |
|---------|---------|-------------|
| **保存** | 独特、具体、范围明确 | 进行到步骤 6 |
| **改进后保存** | 有价值但需要改进 | 列出改进项 → 修订 → 重新评估(一次) |
| **吸收到 \[X]** | 应追加到现有技能 | 显示目标技能和添加内容 → 步骤 6 |
| **放弃** | 琐碎、冗余或过于抽象 | 解释原因并停止 |
**指导维度**(用于告知裁决,不进行评分):
* **具体性和可操作性**:包含可立即使用的代码示例或命令
* **范围契合度**:名称、触发条件和内容保持一致,并专注于单一模式
* **独特性**:提供现有技能未涵盖的价值(基于清单结果)
* **可复用性**:在未来的会话中存在现实的触发场景
6. **裁决特定的确认流程**
* **改进后保存**:呈现必需的改进项 + 修订后的草案 + 一次重新评估后的更新清单/裁决;如果修订后的裁决是**保存**,则在用户确认后保存,否则遵循新的裁决
* **保存**:呈现保存路径 + 清单结果 + 1行裁决理由 + 完整草案 → 在用户确认后保存
* **吸收到 \[X]**:呈现目标路径 + 添加内容diff格式 + 清单结果 + 裁决理由 → 在用户确认后追加
* **放弃**:仅显示清单结果 + 推理(无需确认)
7. 保存 / 吸收到确定的位置
## 步骤 5 的输出格式
```
### Checklist
- [x] skills/ grep: no overlap (or: overlap found → details)
- [x] MEMORY.md: no overlap (or: overlap found → details)
- [x] Existing skill append: new file appropriate (or: should append to [X])
- [x] Reusability: confirmed (or: one-off → Drop)
### Verdict: Save / Improve then Save / Absorb into [X] / Drop
**Rationale:** (1-2 sentences explaining the verdict)
```
## 设计原理
此版本用基于清单的整体裁决系统取代了之前的 5 维度数字评分标准(具体性、可操作性、范围契合度、非冗余性、覆盖度,评分 1-5。现代前沿模型Opus 4.6+)具有强大的情境判断能力 —— 将丰富的定性信号强行压缩为数字评分会丢失细微差别,并可能产生误导性的总分。整体方法让模型自然地权衡所有因素,产生更准确的保存/放弃决策,同时明确的清单确保不会跳过任何关键检查。
## 注意事项
* 不要提取琐碎的修复(拼写错误、简单的语法错误)
* 不要提取一次性问题(特定的 API 中断等)
* 专注于在未来会话中节省时间的模式
* 保持技能聚焦 — 每个技能一个模式
* 如果覆盖率评分低,在保存前添加相关变体
* 专注于那些将在未来会话中节省时间的模式
* 保持技能聚焦 — 每个技能一个模式
* 当裁决为“吸收”时,追加到现有技能,而不是创建新文件

View File

@@ -104,6 +104,14 @@ TaskOutput({ task_id: "<task_id>", block: true, timeout: 600000 })
4. 当评分 < 7 或用户不批准时强制停止。
5. 需要时(例如确认/选择/批准)使用 `AskUserQuestion` 工具进行用户交互。
## 何时使用外部编排
当工作必须拆分给需要隔离的 git 状态、独立终端或独立构建/测试执行的并行工作器时,请使用外部 tmux/工作树编排。对于轻量级分析、规划或审查(其中主会话是唯一的写入者),请使用进程内子代理。
```bash
node scripts/orchestrate-worktrees.js .claude/plan/workflow-e2e-test.json --execute
```
***
## 执行工作流程

View File

@@ -158,6 +158,61 @@ RECOMMENDATION
```
对于使用独立 git worktree 的外部 tmux-pane 工作器,请使用 `node scripts/orchestrate-worktrees.js plan.json --execute`。内置的编排模式保持进程内运行;此辅助工具适用于长时间运行或跨测试框架的会话。
当工作器需要查看主检出目录中的脏文件或未跟踪的本地文件时,请在计划文件中添加 `seedPaths`。ECC 仅在 `git worktree add` 之后,将那些选定的路径覆盖到每个工作器的工作树中,这既能保持分支隔离,又能暴露正在处理的本地脚本、计划或文档。
```json
{
"sessionName": "workflow-e2e",
"seedPaths": [
"scripts/orchestrate-worktrees.js",
"scripts/lib/tmux-worktree-orchestrator.js",
".claude/plan/workflow-e2e-test.json"
],
"workers": [
{ "name": "docs", "task": "Update orchestration docs." }
]
}
```
要导出实时 tmux/worktree 会话的控制平面快照,请运行:
```bash
node scripts/orchestration-status.js .claude/plan/workflow-visual-proof.json
```
快照包含会话活动、tmux 窗格元数据、工作器状态、目标、已播种的覆盖层以及最近的交接摘要,均以 JSON 格式保存。
## 操作员指挥中心交接
当工作流跨越多个会话、工作树或 tmux 窗格时,请在最终交接内容中附加一个控制平面块:
```markdown
控制平面
-------------
会话:
- 活动会话 ID 或别名
- 每个活动工作线程的分支 + 工作树路径
- 适用时的 tmux 窗格或分离会话名称
差异:
- git 状态摘要
- 已修改文件的 git diff --stat
- 合并/冲突风险说明
审批:
- 待处理的用户审批
- 等待确认的受阻步骤
遥测:
- 最后活动时间戳或空闲信号
- 预估的令牌或成本漂移
- 由钩子或审查器引发的策略事件
```
这使得规划者、实施者、审查者和循环工作器在操作员界面上保持清晰可辨。
## 参数
$ARGUMENTS:

View File

@@ -112,4 +112,7 @@ Agent (planner):
## 相关代理
此命令调用位于 `~/.claude/agents/planner.md` `planner` 代理。
此命令调用由 ECC 提供`planner` 代理。
对于手动安装,源文件位于:
`agents/planner.md`

View File

@@ -0,0 +1,37 @@
---
description: 分析一个草稿提示输出一个经过优化、富含ECC的版本准备粘贴并运行。不执行任务——仅输出咨询分析。
---
# /prompt-optimize
分析并优化以下提示语以实现最大化的ECC杠杆效应。
## 你的任务
对下方用户的输入应用 **prompt-optimizer** 技能。遵循6阶段分析流程
0. **项目检测** — 读取 CLAUDE.md从项目文件package.json, go.mod, pyproject.toml 等)检测技术栈
1. **意图检测** — 对任务类型进行分类(新功能、错误修复、重构、研究、测试、评审、文档、基础设施、设计)
2. **范围评估** — 评估复杂度(简单 / 低 / 中 / 高 / 史诗级),如果检测到代码库,则使用其大小作为信号
3. **ECC组件匹配** — 映射到特定的技能、命令、代理和模型层级
4. **缺失上下文检测** — 识别信息缺口。如果缺少3个以上关键项请在生成前请用户澄清
5. **工作流与模型** — 确定生命周期阶段,推荐模型层级,如果复杂度为高/史诗级,则将其拆分为多个提示语
## 输出要求
* 呈现诊断结果、推荐的ECC组件以及使用 prompt-optimizer 技能中输出格式的优化后提示语
* 提供 **完整版本**(详细)和 **快速版本**(紧凑,根据意图类型变化)
* 使用与用户输入相同的语言进行回复
* 优化后的提示语必须完整且可复制粘贴到新会话中直接使用
* 以提供调整选项或明确下一步操作(用于启动单独的执行请求)的页脚结束
## 关键
请勿执行用户的任务。仅输出分析结果和优化后的提示语。
如果用户要求直接执行,请说明 `/prompt-optimize` 仅产生咨询性输出,并告诉他们应启动一个常规的任务请求。
注意:`blueprint` 是一个**技能**,而非斜杠命令。请写作“使用蓝图技能”,而不是将其呈现为 `/...` 命令。
## 用户输入
$ARGUMENTS

View File

@@ -315,6 +315,6 @@ result = "".join(str(item) for item in items)
| 海象运算符 (`:=`) | 3.8+ |
| 仅限位置参数 | 3.8+ |
| Match 语句 | 3.10+ |
| 类型联合 (\`x \| None\`) | 3.10+ |
| 类型联合 (\`x | None\`) | 3.10+ |
确保你的项目 `pyproject.toml``setup.py` 指定了正确的最低 Python 版本。

View File

@@ -0,0 +1,155 @@
---
description: 从 ~/.claude/sessions/ 加载最新的会话文件,并从上次会话结束的地方恢复工作,保留完整上下文。
---
# 恢复会话命令
加载最后保存的会话状态,并在开始任何工作前完全熟悉情况。
此命令是 `/save-session` 的对应命令。
## 何时使用
* 开始新会话以继续前一天的工作时
* 因上下文限制而开始全新会话后
* 当从其他来源移交会话文件时(只需提供文件路径)
* 任何拥有会话文件并希望 Claude 在继续前完全吸收其内容的时候
## 用法
```
/resume-session # loads most recent file in ~/.claude/sessions/
/resume-session 2024-01-15 # loads most recent session for that date
/resume-session ~/.claude/sessions/2024-01-15-session.tmp # loads a specific legacy-format file
/resume-session ~/.claude/sessions/2024-01-15-abc123de-session.tmp # loads a current short-id session file
```
## 流程
### 步骤 1查找会话文件
如果未提供参数:
1. 检查 `~/.claude/sessions/`
2. 选择最近修改的 `*-session.tmp` 文件
3. 如果文件夹不存在或没有匹配的文件,告知用户:
```
在 ~/.claude/sessions/ 中未找到会话文件。
请在会话结束时运行 /save-session 来创建一个。
```
然后停止。
如果提供了参数:
* 如果看起来像日期 (`YYYY-MM-DD`),则在 `~/.claude/sessions/` 中搜索匹配
`YYYY-MM-DD-session.tmp`(旧格式)或 `YYYY-MM-DD-<shortid>-session.tmp`(当前格式)的文件,
并加载该日期最近修改的版本
* 如果看起来像文件路径,则直接读取该文件
* 如果未找到,清晰报告并停止
### 步骤 2读取整个会话文件
读取完整的文件。暂时不要总结。
### 步骤 3确认理解
使用以下确切格式回复一份结构化简报:
```
SESSION LOADED: [actual resolved path to the file]
════════════════════════════════════════════════
PROJECT: [project name / topic from file]
WHAT WE'RE BUILDING:
[2-3 sentence summary in your own words]
CURRENT STATE:
✅ Working: [count] items confirmed
🔄 In Progress: [list files that are in progress]
🗒️ Not Started: [list planned but untouched]
WHAT NOT TO RETRY:
[list every failed approach with its reason — this is critical]
OPEN QUESTIONS / BLOCKERS:
[list any blockers or unanswered questions]
NEXT STEP:
[exact next step if defined in the file]
[if not defined: "No next step defined — recommend reviewing 'What Has NOT Been Tried Yet' together before starting"]
════════════════════════════════════════════════
Ready to continue. What would you like to do?
```
### 步骤 4等待用户
请**不要**自动开始工作。请**不要**触碰任何文件。等待用户指示下一步做什么。
如果会话文件中明确定义了下一步,并且用户说"继续"或"是"或类似内容 — 则执行该确切步骤。
如果未定义下一步 — 询问用户从哪里开始,并可选择性地从"尚未尝试的内容"部分提出建议。
***
## 边界情况
**同一日期有多个会话** (`2024-01-15-session.tmp`, `2024-01-15-abc123de-session.tmp`)
加载该日期最近修改的匹配文件无论其使用的是旧的无ID格式还是当前的短ID格式。
**会话文件引用了已不存在的文件:**
在简报中注明 — "⚠️ 会话中引用了 `path/to/file.ts`,但在磁盘上未找到。"
**会话文件来自超过7天前**
注明时间间隔 — "⚠️ 此会话来自 N 天前阈值7天。情况可能已发生变化。" — 然后正常继续。
**用户直接提供了文件路径(例如,从队友处转发而来):**
读取它并遵循相同的简报流程 — 无论来源如何,格式都是相同的。
**会话文件为空或格式错误:**
报告:"找到会话文件,但似乎为空或无法读取。您可能需要使用 /save-session 创建一个新的。"
***
## 示例输出
```
SESSION LOADED: /Users/you/.claude/sessions/2024-01-15-abc123de-session.tmp
════════════════════════════════════════════════
PROJECT: my-app — JWT Authentication
WHAT WE'RE BUILDING:
User authentication with JWT tokens stored in httpOnly cookies.
Register and login endpoints are partially done. Route protection
via middleware hasn't been started yet.
CURRENT STATE:
✅ Working: 3 items (register endpoint, JWT generation, password hashing)
🔄 In Progress: app/api/auth/login/route.ts (token works, cookie not set yet)
🗒️ Not Started: middleware.ts, app/login/page.tsx
WHAT NOT TO RETRY:
❌ Next-Auth — conflicts with custom Prisma adapter, threw adapter error on every request
❌ localStorage for JWT — causes SSR hydration mismatch, incompatible with Next.js
OPEN QUESTIONS / BLOCKERS:
- Does cookies().set() work inside a Route Handler or only Server Actions?
NEXT STEP:
In app/api/auth/login/route.ts — set the JWT as an httpOnly cookie using
cookies().set('token', jwt, { httpOnly: true, secure: true, sameSite: 'strict' })
then test with Postman for a Set-Cookie header in the response.
════════════════════════════════════════════════
Ready to continue. What would you like to do?
```
***
## 注意事项
* 加载时切勿修改会话文件 — 它是一个只读的历史记录
* 简报格式是固定的 — 即使某些部分为空,也不要跳过
* "不应重试的内容"必须始终显示,即使它只是说"无" — 这太重要了,不容遗漏
* 恢复后,用户可能希望在新的会话结束时再次运行 `/save-session`,以创建一个新的带日期文件

View File

@@ -0,0 +1,252 @@
---
description: 将当前会话状态保存到 ~/.claude/sessions/ 目录下带日期的文件中,以便在未来的会话中恢复完整上下文并继续工作。
---
# 保存会话命令
捕获本次会话中发生的一切——构建了什么、什么成功了、什么失败了、还有哪些遗留事项——并将其写入一个带日期的文件,以便下次会话能从此处继续。
## 使用时机
* 在关闭 Claude Code 之前,工作会话结束时
* 在达到上下文限制之前(先运行此命令,然后开始一个新会话)
* 解决了一个想要记住的复杂问题之后
* 任何需要将上下文移交给未来会话的时候
## 流程
### 步骤 1收集上下文
在写入文件之前,收集:
* 读取本次会话期间修改的所有文件(使用 git diff 或从对话中回忆)
* 回顾讨论、尝试和决定的内容
* 记录遇到的任何错误及其解决方法(或未解决的情况)
* 如果相关,检查当前的测试/构建状态
### 步骤 2如果不存在则创建会话文件夹
在用户的 Claude 主目录中创建规范的会话文件夹:
```bash
mkdir -p ~/.claude/sessions
```
### 步骤 3写入会话文件
创建 `~/.claude/sessions/YYYY-MM-DD-<short-id>-session.tmp`,使用今天的实际日期和一个满足 `session-manager.js``SESSION_FILENAME_REGEX` 强制规则的短 ID
* 允许的字符:小写 `a-z`,数字 `0-9`,连字符 `-`
* 最小长度8 个字符
* 不允许大写字母、下划线、空格
有效示例:`abc123de``a1b2c3d4``frontend-worktree-1`
无效示例:`ABC123de`(大写)、`short`(少于 8 个字符)、`test_id1`(下划线)
完整有效文件名示例:`2024-01-15-abc123de-session.tmp`
旧文件名 `YYYY-MM-DD-session.tmp` 仍然有效,但新的会话文件应首选短 ID 形式,以避免同一天的冲突。
### 步骤 4用以下所有部分填充文件
诚实地写入每个部分。不要跳过任何部分——如果某个部分确实没有内容则写“Nothing yet”或“N/A”。一个不完整的文件比诚实的空部分更糟糕。
### 步骤 5向用户展示文件
写入后,显示完整内容并询问:
```
Session saved to [actual resolved path to the session file]
Does this look accurate? Anything to correct or add before we close?
```
等待确认。如果用户要求,进行编辑。
***
## 会话文件格式
```markdown
# 会话YYYY-MM-DD
**开始时间:** [若已知大致时间]
**最后更新:** [当前时间]
**项目:** [项目名称或路径]
**主题:** [关于本次会话的一行摘要]
---
## 正在构建的内容
[1-3段文字描述功能、错误修复或任务。包含足够的背景信息让对此会话毫无记忆的人也能理解目标。包含它做什么、为什么需要它、它如何融入更大的系统。]
---
## 已确认有效的工作(附证据)
[仅列出已确认有效的事项。对于每个事项说明你如何知道它有效——测试通过、在浏览器中运行、Postman 返回 200 等。没有证据的,请移至"尚未尝试"部分。]
- **[有效的事项]** — 确认依据:[具体证据]
- **[有效的事项]** — 确认依据:[具体证据]
如果尚无任何事项确认有效:"尚无确认有效的事项——所有方法仍在进行中或未测试。"
---
## 无效的事项(及原因)
[这是最重要的部分。列出所有尝试过但失败的方法。对于每个失败,写出确切原因,以便下次会话不再重试。要具体:"因 Y 而抛出 X 错误"是有用的。"无效"是无用的。]
- **[尝试过的方法]** — 失败原因:[确切原因 / 错误信息]
- **[尝试过的方法]** — 失败原因:[确切原因 / 错误信息]
如果无失败事项:"尚无失败的方法。"
---
## 尚未尝试的事项
[看起来有希望但尚未尝试的方法。对话中产生的想法。值得探索的替代方案。描述要足够具体,以便下次会话确切知道要尝试什么。]
- [方法 / 想法]
- [方法 / 想法]
如果无待办事项:"未确定具体的待尝试方法。"
---
## 文件当前状态
[本次会话中修改过的每个文件。准确说明每个文件的状态。]
| 文件 | 状态 | 备注 |
| ----------------- | -------------- | ---------------------------- |
| `path/to/file.ts` | ✅ 完成 | [其作用] |
| `path/to/file.ts` | 🔄 进行中 | [已完成什么,剩余什么] |
| `path/to/file.ts` | ❌ 损坏 | [问题所在] |
| `path/to/file.ts` | 🗒️ 未开始 | [计划但尚未接触] |
如果未修改任何文件:"本次会话未修改任何文件。"
---
## 已作出的决策
[架构选择、接受的权衡、选择的方法及其原因。这些可防止下次会话重新讨论已确定的决策。]
- **[决策]** — 原因:[选择此方案而非其他方案的原因]
如果无重大决策:"本次会话未作出重大决策。"
---
## 阻碍与待解决问题
[任何未解决、需要下次会话处理或调查的事项。出现但未解答的问题。等待中的外部依赖。]
- [阻碍 / 待解决问题]
如果无:"无当前阻碍。"
---
## 确切下一步
[若已知:恢复工作时最重要的单件事项。描述要足够精确,使得恢复工作时无需思考从何处开始。]
[若未知:"下一步未确定——在开始前,请查看'尚未尝试的事项'和'阻碍'部分以决定方向。"]
---
## 环境与设置说明
[仅在相关时填写——运行项目所需的命令、所需的环境变量、需要运行的服务等。若为标准设置,请跳过。]
[若无:请完全省略此部分。]
```
***
## 示例输出
```markdown
# 会话2024-01-15
**开始时间:** ~下午2点
**最后更新:** 下午5:30
**项目:** my-app
**主题:** 使用 httpOnly cookies 构建 JWT 认证
---
## 我们正在构建什么
为 Next.js 应用构建用户认证系统。用户使用电子邮件/密码注册,收到存储在 httpOnly cookie而非 localStorage中的 JWT受保护的路由通过中间件检查有效的令牌。目标是在浏览器刷新时保持会话持久性同时不将令牌暴露给 JavaScript。
---
## 哪些工作有效(附证据)
- **`/api/auth/register` 端点** — 确认依据Postman POST 请求返回 200 并包含用户对象Supabase 仪表板中可见行记录bcrypt 哈希正确存储
- **在 `lib/auth.ts` 中生成 JWT** — 确认依据:单元测试通过 (`npm test -- auth.test.ts`),在 jwt.io 解码的令牌显示正确的负载
- **密码哈希** — 确认依据:`bcrypt.compare()` 在测试中返回 true
---
## 哪些工作无效(及原因)
- **Next-Auth 库** — 失败原因:与我们的自定义 Prisma 适配器冲突,每次请求都抛出“无法在此配置中将适配器与凭据提供程序一起使用”。不值得调试 — 对我们的设置来说过于固执己见。
- **将 JWT 存储在 localStorage 中** — 失败原因SSR 渲染发生在 localStorage 可用之前,导致每次页面加载都出现 React 水合不匹配错误。此方法从根本上与 Next.js SSR 不兼容。
---
## 尚未尝试的事项
- 在登录路由响应中将 JWT 存储为 httpOnly cookie最可能的解决方案
- 使用 `cookies()``next/headers` 中读取服务器组件中的令牌
- 编写 middleware.ts 通过检查 cookie 是否存在来保护路由
---
## 文件当前状态
| 文件 | 状态 | 备注 |
| -------------------------------- | -------------- | ----------------------------------------------- |
| `app/api/auth/register/route.ts` | ✅ 已完成 | 工作正常,已测试 |
| `app/api/auth/login/route.ts` | 🔄 进行中 | 令牌已生成但尚未设置 cookie |
| `lib/auth.ts` | ✅ 已完成 | JWT 辅助函数,全部已测试 |
| `middleware.ts` | 🗒️ 未开始 | 路由保护,需要先实现 cookie 读取逻辑 |
| `app/login/page.tsx` | 🗒️ 未开始 | UI 尚未开始 |
---
## 已做出的决策
- **选择 httpOnly cookie 而非 localStorage** — 原因:防止 XSS 令牌窃取,与 SSR 兼容
- **选择自定义认证而非 Next-Auth** — 原因Next-Auth 与我们的 Prisma 设置冲突,不值得折腾
---
## 阻碍与未决问题
- `cookies().set()` 在路由处理器中有效,还是仅在服务器操作中有效?需要验证。
---
## 确切下一步
`app/api/auth/login/route.ts` 中,生成 JWT 后,使用 `cookies().set('token', jwt, { httpOnly: true, secure: true, sameSite: 'strict' })` 将其设置为 httpOnly cookie。
然后用 Postman 测试 — 响应应包含一个 `Set-Cookie` 头。
```
***
## 注意事项
* 每个会话都有其自己的文件——切勿追加到先前会话的文件中
* “什么没有成功”部分是最关键的——没有它,未来的会话将盲目地重试失败的方法
* 如果用户要求中途保存会话(而不仅仅是在结束时),则保存目前已知的内容,并清楚地标记进行中的项目
* 该文件旨在通过 `/resume-session` 在下次会话开始时由 Claude 读取
* 使用规范的全局会话存储:`~/.claude/sessions/`
* 对于任何新的会话文件,首选短 ID 文件名形式(`YYYY-MM-DD-<short-id>-session.tmp`

View File

@@ -12,6 +12,8 @@
显示所有会话及其元数据,支持筛选和分页。
当您需要群组的操作员表层上下文时,使用 `/sessions info`:分支、工作树路径和会话最近性。
```bash
/sessions # List all sessions (default)
/sessions list # Same as above
@@ -26,6 +28,7 @@
node -e "
const sm = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-manager');
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
const path = require('path');
const result = sm.getAllSessions({ limit: 20 });
const aliases = aa.listAliases();
@@ -34,17 +37,18 @@ for (const a of aliases) aliasMap[a.sessionPath] = a.name;
console.log('Sessions (showing ' + result.sessions.length + ' of ' + result.total + '):');
console.log('');
console.log('ID Date Time Size Lines Alias');
console.log('────────────────────────────────────────────────────');
console.log('ID Date Time Branch Worktree Alias');
console.log('────────────────────────────────────────────────────────────────────');
for (const s of result.sessions) {
const alias = aliasMap[s.filename] || '';
const size = sm.getSessionSize(s.sessionPath);
const stats = sm.getSessionStats(s.sessionPath);
const metadata = sm.parseSessionMetadata(sm.getSessionContent(s.sessionPath));
const id = s.shortId === 'no-id' ? '(none)' : s.shortId.slice(0, 8);
const time = s.modifiedTime.toTimeString().slice(0, 5);
const branch = (metadata.branch || '-').slice(0, 12);
const worktree = metadata.worktree ? path.basename(metadata.worktree).slice(0, 18) : '-';
console.log(id.padEnd(8) + ' ' + s.date + ' ' + time + ' ' + size.padEnd(7) + ' ' + String(stats.lineCount).padEnd(5) + ' ' + alias);
console.log(id.padEnd(8) + ' ' + s.date + ' ' + time + ' ' + branch.padEnd(12) + ' ' + worktree.padEnd(18) + ' ' + alias);
}
"
```
@@ -110,6 +114,18 @@ if (session.metadata.started) {
if (session.metadata.lastUpdated) {
console.log('Last Updated: ' + session.metadata.lastUpdated);
}
if (session.metadata.project) {
console.log('Project: ' + session.metadata.project);
}
if (session.metadata.branch) {
console.log('Branch: ' + session.metadata.branch);
}
if (session.metadata.worktree) {
console.log('Worktree: ' + session.metadata.worktree);
}
" "$ARGUMENTS"
```
@@ -220,6 +236,9 @@ console.log('ID: ' + (session.shortId === 'no-id' ? '(none)' : session.
console.log('Filename: ' + session.filename);
console.log('Date: ' + session.date);
console.log('Modified: ' + session.modifiedTime.toISOString().slice(0, 19).replace('T', ' '));
console.log('Project: ' + (session.metadata.project || '-'));
console.log('Branch: ' + (session.metadata.branch || '-'));
console.log('Worktree: ' + (session.metadata.worktree || '-'));
console.log('');
console.log('Content:');
console.log(' Lines: ' + stats.lineCount);
@@ -241,6 +260,11 @@ if (aliases.length > 0) {
/sessions aliases # List all aliases
```
## 操作员笔记
* 会话文件在头部持久化 `Project``Branch``Worktree`,以便 `/sessions info` 可以区分并行 tmux/工作树运行。
* 对于指挥中心式监控,请结合使用 `/sessions info``git diff --stat` 以及由 `scripts/hooks/cost-tracker.js` 发出的成本指标。
**脚本:**
```bash

View File

@@ -321,10 +321,12 @@ Never skip the RED phase. Never write code before tests.
## Related Agents
This command invokes the `tdd-guide` agent located at:
`~/.claude/agents/tdd-guide.md`
This command invokes the `tdd-guide` agent provided by ECC.
And can reference the `tdd-workflow` skill at:
`~/.claude/skills/tdd-workflow/`
The related `tdd-workflow` skill is also bundled with ECC.
For manual installs, the source files live at:
- `agents/tdd-guide.md`
- `skills/tdd-workflow/SKILL.md`
```