mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
fix: 为所有 skill 的 .workflow/ 路径添加 projectRoot 前缀
从子目录执行 skill 时,相对路径 .workflow/ 会导致产物落到错误位置。
通过 git rev-parse --show-toplevel || pwd 检测项目根目录,
所有 .workflow/ 路径引用统一加上 {projectRoot} 前缀确保路径正确。
涉及 72 个文件,覆盖 20+ 个 skill。
This commit is contained in:
@@ -20,8 +20,8 @@ Stateless iterative development loop using Codex single-agent deep interaction p
|
||||
+-------------------------------------------------------------+
|
||||
| loop-v2-routes.ts (Control Plane) |
|
||||
| |
|
||||
| State: .workflow/.loop/{loopId}.json (MASTER) |
|
||||
| Tasks: .workflow/.loop/{loopId}.tasks.jsonl |
|
||||
| State: {projectRoot}/.workflow/.loop/{loopId}.json (MASTER) |
|
||||
| Tasks: {projectRoot}/.workflow/.loop/{loopId}.tasks.jsonl |
|
||||
| |
|
||||
| /start -> Trigger ccw-loop skill with --loop-id |
|
||||
| /pause -> Set status='paused' (skill checks before action) |
|
||||
@@ -43,9 +43,9 @@ Stateless iterative development loop using Codex single-agent deep interaction p
|
||||
## Key Design Principles
|
||||
|
||||
1. **Single Agent Deep Interaction**: One agent handles entire loop lifecycle via `send_input` (no multi-agent overhead)
|
||||
2. **Unified State**: API and Skill share `.workflow/.loop/{loopId}.json` state file
|
||||
2. **Unified State**: API and Skill share `{projectRoot}/.workflow/.loop/{loopId}.json` state file
|
||||
3. **Control Signals**: Skill checks `status` field before each action (paused/stopped → graceful exit)
|
||||
4. **File-Driven Progress**: All progress documented in `.workflow/.loop/{loopId}.progress/`
|
||||
4. **File-Driven Progress**: All progress documented in `{projectRoot}/.workflow/.loop/{loopId}.progress/`
|
||||
5. **Resumable**: Continue any loop with `--loop-id`
|
||||
6. **Dual Trigger**: Supports API trigger (`--loop-id`) and direct call (task description)
|
||||
|
||||
@@ -134,7 +134,7 @@ close_agent → return finalState
|
||||
## Session Structure
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
{projectRoot}/.workflow/.loop/
|
||||
├── {loopId}.json # Master state file (API + Skill shared)
|
||||
├── {loopId}.tasks.jsonl # Task list (API managed)
|
||||
└── {loopId}.progress/ # Skill progress files
|
||||
@@ -151,7 +151,7 @@ close_agent → return finalState
|
||||
|
||||
## State Management
|
||||
|
||||
Master state file: `.workflow/.loop/{loopId}.json`
|
||||
Master state file: `{projectRoot}/.workflow/.loop/{loopId}.json`
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -203,7 +203,7 @@ Master state file: `.workflow/.loop/{loopId}.json`
|
||||
- `failed` → terminate
|
||||
- Other → stop
|
||||
|
||||
**Recovery**: If state corrupted, rebuild `skill_state` from `.progress/` markdown files and logs.
|
||||
**Recovery**: If state corrupted, rebuild `skill_state` from `{projectRoot}/.workflow/.loop/{loopId}.progress/` markdown files and logs.
|
||||
|
||||
## Action Catalog
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Complete CCW Loop session and generate summary report.
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
const state = JSON.parse(Read(`${projectRoot}/.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
@@ -174,7 +174,7 @@ state.updated_at = timestamp
|
||||
state.skill_state.last_action = 'COMPLETE'
|
||||
state.skill_state.summary = stats
|
||||
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
@@ -190,8 +190,8 @@ ACTION_RESULT:
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.json: Status set to completed
|
||||
- .workflow/.loop/{loopId}.progress/summary.md: Summary report generated
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.json: Status set to completed
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/summary.md: Summary report generated
|
||||
|
||||
NEXT_ACTION_NEEDED: COMPLETED
|
||||
```
|
||||
|
||||
@@ -233,7 +233,7 @@ if (confirmedHypothesis) {
|
||||
|
||||
state.skill_state.last_action = 'DEBUG'
|
||||
state.updated_at = timestamp
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
@@ -249,8 +249,8 @@ ACTION_RESULT:
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.progress/debug.md: Understanding updated
|
||||
- .workflow/.loop/{loopId}.progress/hypotheses.json: Hypotheses updated
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/debug.md: Understanding updated
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/hypotheses.json: Hypotheses updated
|
||||
- [Source files]: Instrumentation added
|
||||
|
||||
NEXT_ACTION_NEEDED: {DEBUG | VALIDATE | DEVELOP | MENU}
|
||||
|
||||
@@ -20,7 +20,7 @@ Execute development task and record progress to develop.md.
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
const state = JSON.parse(Read(`${projectRoot}/.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
@@ -133,7 +133,7 @@ state.skill_state.last_action = 'DEVELOP'
|
||||
state.skill_state.completed_actions.push('DEVELOP')
|
||||
state.updated_at = timestamp
|
||||
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
@@ -149,9 +149,9 @@ ACTION_RESULT:
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.json: Task status updated
|
||||
- .workflow/.loop/{loopId}.progress/develop.md: Progress entry added
|
||||
- .workflow/.loop/{loopId}.progress/changes.log: Change entry added
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.json: Task status updated
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/develop.md: Progress entry added
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/changes.log: Change entry added
|
||||
|
||||
NEXT_ACTION_NEEDED: {DEVELOP | DEBUG | VALIDATE | MENU}
|
||||
```
|
||||
|
||||
@@ -19,7 +19,7 @@ Initialize CCW Loop session, create directory structure and initial state.
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
const state = JSON.parse(Read(`${projectRoot}/.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
@@ -34,7 +34,7 @@ if (state.status !== 'running') {
|
||||
### Step 2: Create Directory Structure
|
||||
|
||||
```javascript
|
||||
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||
const progressDir = `${projectRoot}/.workflow/.loop/${loopId}.progress`
|
||||
|
||||
// Directories created by orchestrator, verify they exist
|
||||
// mkdir -p ${progressDir}
|
||||
@@ -131,7 +131,7 @@ const skillState = {
|
||||
|
||||
state.skill_state = skillState
|
||||
state.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
@@ -143,8 +143,8 @@ ACTION_RESULT:
|
||||
- message: Session initialized with {N} development tasks
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.json: skill_state initialized
|
||||
- .workflow/.loop/{loopId}.progress/develop.md: Progress document created
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.json: skill_state initialized
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/develop.md: Progress document created
|
||||
|
||||
NEXT_ACTION_NEEDED: {DEVELOP (auto) | MENU (interactive)}
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ Display interactive action menu for user selection.
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
const state = JSON.parse(Read(`${projectRoot}/.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
@@ -172,7 +172,7 @@ If user selects "exit":
|
||||
// Save current state
|
||||
state.status = 'user_exit'
|
||||
state.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
|
||||
return {
|
||||
action: 'MENU',
|
||||
|
||||
@@ -21,7 +21,7 @@ Run tests and verify implementation, record results to validate.md.
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
const state = JSON.parse(Read(`${projectRoot}/.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
@@ -174,7 +174,7 @@ state.skill_state.validate.last_run_at = timestamp
|
||||
|
||||
state.skill_state.last_action = 'VALIDATE'
|
||||
state.updated_at = timestamp
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
@@ -191,9 +191,9 @@ ACTION_RESULT:
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.progress/validate.md: Validation report created
|
||||
- .workflow/.loop/{loopId}.progress/test-results.json: Test results saved
|
||||
- .workflow/.loop/{loopId}.progress/coverage.json: Coverage data saved (if available)
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/validate.md: Validation report created
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/test-results.json: Test results saved
|
||||
- {projectRoot}/.workflow/.loop/{loopId}.progress/coverage.json: Coverage data saved (if available)
|
||||
|
||||
NEXT_ACTION_NEEDED: {COMPLETE | DEBUG | DEVELOP | MENU}
|
||||
```
|
||||
|
||||
@@ -12,6 +12,13 @@ Create or resume a development loop, initialize state file and directory structu
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 0: Determine Project Root
|
||||
|
||||
```javascript
|
||||
// Step 0: Determine Project Root
|
||||
const projectRoot = Bash('git rev-parse --show-toplevel 2>/dev/null || pwd').trim()
|
||||
```
|
||||
|
||||
### Step 1.1: Parse Arguments
|
||||
|
||||
```javascript
|
||||
@@ -33,7 +40,7 @@ const executionMode = options['--auto'] ? 'auto' : 'interactive'
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
function readLoopState(loopId) {
|
||||
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||
const stateFile = `${projectRoot}/.workflow/.loop/${loopId}.json`
|
||||
if (!fs.existsSync(stateFile)) {
|
||||
return null
|
||||
}
|
||||
@@ -57,14 +64,14 @@ console.log(`Creating new loop: ${loopId}`)
|
||||
#### Create Directory Structure
|
||||
|
||||
```bash
|
||||
mkdir -p .workflow/.loop/${loopId}.progress
|
||||
mkdir -p ${projectRoot}/.workflow/.loop/${loopId}.progress
|
||||
```
|
||||
|
||||
#### Initialize State File
|
||||
|
||||
```javascript
|
||||
function createLoopState(loopId, taskDescription) {
|
||||
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||
const stateFile = `${projectRoot}/.workflow/.loop/${loopId}.json`
|
||||
const now = getUtc8ISOString()
|
||||
|
||||
const state = {
|
||||
@@ -129,7 +136,7 @@ function checkControlSignals(loopId) {
|
||||
|
||||
- **Variable**: `loopId` - Unique loop identifier
|
||||
- **Variable**: `state` - Initialized or resumed loop state object
|
||||
- **Variable**: `progressDir` - `.workflow/.loop/${loopId}.progress`
|
||||
- **Variable**: `progressDir` - `${projectRoot}/.workflow/.loop/${loopId}.progress`
|
||||
- **Variable**: `mode` - `'interactive'` or `'auto'`
|
||||
- **TodoWrite**: Mark Phase 1 completed, Phase 2 in_progress
|
||||
|
||||
|
||||
@@ -23,15 +23,15 @@ const agent = spawn_agent({
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/ccw-loop-executor.md (MUST read first)
|
||||
2. Read: .workflow/project-tech.json (if exists)
|
||||
3. Read: .workflow/project-guidelines.json (if exists)
|
||||
2. Read: ${projectRoot}/.workflow/project-tech.json (if exists)
|
||||
3. Read: ${projectRoot}/.workflow/project-guidelines.json (if exists)
|
||||
|
||||
---
|
||||
|
||||
## LOOP CONTEXT
|
||||
|
||||
- **Loop ID**: ${loopId}
|
||||
- **State File**: .workflow/.loop/${loopId}.json
|
||||
- **State File**: ${projectRoot}/.workflow/.loop/${loopId}.json
|
||||
- **Progress Dir**: ${progressDir}
|
||||
- **Mode**: ${mode}
|
||||
|
||||
@@ -48,7 +48,7 @@ ${state.description || task}
|
||||
You are executing CCW Loop orchestrator. Your job:
|
||||
|
||||
1. **Check Control Signals**
|
||||
- Read .workflow/.loop/${loopId}.json
|
||||
- Read ${projectRoot}/.workflow/.loop/${loopId}.json
|
||||
- If status === 'paused' -> Output "PAUSED" and stop
|
||||
- If status === 'failed' -> Output "STOPPED" and stop
|
||||
- If status === 'running' -> Continue
|
||||
@@ -62,7 +62,7 @@ You are executing CCW Loop orchestrator. Your job:
|
||||
3. **Execute Action**
|
||||
- Follow action instructions from ~/.codex/skills/ccw-loop/actions/
|
||||
- Update progress files in ${progressDir}/
|
||||
- Update state in .workflow/.loop/${loopId}.json
|
||||
- Update state in ${projectRoot}/.workflow/.loop/${loopId}.json
|
||||
|
||||
4. **Output Format**
|
||||
\`\`\`
|
||||
@@ -123,7 +123,7 @@ Execution timeout reached. Please:
|
||||
state = readLoopState(loopId)
|
||||
state.current_iteration = iteration
|
||||
state.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
Write(`${projectRoot}/.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
|
||||
// Handle different outcomes
|
||||
switch (actionResult.next_action) {
|
||||
|
||||
Reference in New Issue
Block a user