From f96febe09ac077d01a362764f86c9c801ea00986 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Wed, 25 Feb 2026 22:32:33 +0800 Subject: [PATCH] feat: add /workflow:session:sync command and integrate auto-sync into execution pipelines Add a new session sync command that updates both project-guidelines.json and project-tech.json from session context in one shot. Replace inline Step 6 (Update Development Index) in lite-execute with sync call, and add auto-sync to Post-Completion Expansion across 6 execution commands. Simplify session/complete by replacing Phase 4+5 with single sync call. --- .claude/commands/workflow/debug-with-file.md | 2 + .claude/commands/workflow/refactor-cycle.md | 2 + .claude/commands/workflow/session/complete.md | 74 +------ .claude/commands/workflow/session/sync.md | 196 ++++++++++++++++++ .../skills/review-cycle/phases/review-fix.md | 2 + .claude/skills/workflow-execute/SKILL.md | 2 + .../phases/02-lite-execute.md | 52 +---- .../phases/02-lite-execute.md | 54 +---- .claude/skills/workflow-test-fix/SKILL.md | 2 + .../phases/05-test-cycle-execute.md | 2 + 10 files changed, 224 insertions(+), 164 deletions(-) create mode 100644 .claude/commands/workflow/session/sync.md diff --git a/.claude/commands/workflow/debug-with-file.md b/.claude/commands/workflow/debug-with-file.md index 7207dee5..9c32cc2a 100644 --- a/.claude/commands/workflow/debug-with-file.md +++ b/.claude/commands/workflow/debug-with-file.md @@ -630,6 +630,8 @@ Why is config value None during update? ## Post-Completion Expansion +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。 + 完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` --- diff --git a/.claude/commands/workflow/refactor-cycle.md b/.claude/commands/workflow/refactor-cycle.md index 3c82cda5..afb8df7b 100644 --- a/.claude/commands/workflow/refactor-cycle.md +++ b/.claude/commands/workflow/refactor-cycle.md @@ -843,6 +843,8 @@ AskUserQuestion({ ## Post-Completion Expansion +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。 + 完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` --- diff --git a/.claude/commands/workflow/session/complete.md b/.claude/commands/workflow/session/complete.md index ab325183..2d667108 100644 --- a/.claude/commands/workflow/session/complete.md +++ b/.claude/commands/workflow/session/complete.md @@ -109,79 +109,16 @@ rm -f .workflow/archives/$SESSION_ID/.archiving Manifest: Updated with N total sessions ``` -### Phase 4: Update project-tech.json (Optional) +### Phase 4: Auto-Sync Project State -**Skip if**: `.workflow/project-tech.json` doesn't exist +Execute `/workflow:session:sync -y "{description}"` to update both `project-guidelines.json` and `project-tech.json` from session context. -```bash -# Check -test -f .workflow/project-tech.json || echo "SKIP" -``` - -**If exists**, add feature entry: - -```json -{ - "id": "", - "title": "", - "status": "completed", - "tags": [""], - "timeline": { "implemented_at": "" }, - "traceability": { "session_id": "", "archive_path": "" } -} -``` - -**Output**: -``` -✓ Feature added to project registry -``` - -### Phase 5: Ask About Solidify (Always) - -After successful archival, prompt user to capture learnings: - -```javascript -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -if (autoYes) { - // Auto mode: Skip solidify - console.log(`[--yes] Auto-selecting: Skip solidify`) - console.log(`Session archived successfully.`) - // Done - no solidify -} else { - // Interactive mode: Ask user - AskUserQuestion({ - questions: [{ - question: "Would you like to solidify learnings from this session into project guidelines?", - header: "Solidify", - options: [ - { label: "Yes, solidify now", description: "Extract learnings and update project-guidelines.json" }, - { label: "Skip", description: "Archive complete, no learnings to capture" } - ], - multiSelect: false - }] - }) - - // **If "Yes, solidify now"**: Execute `/workflow:session:solidify` with the archived session ID. -} -``` +Description 取自 Phase 2 的 `workflow-session.json` description 字段。 ## Auto Mode Defaults When `--yes` or `-y` flag is used: -- **Solidify Learnings**: Auto-selected "Skip" (archive only, no solidify) - -**Flag Parsing**: -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -``` - -**Output**: -``` -Session archived successfully. -→ Run /workflow:session:solidify to capture learnings (recommended) -``` +- **Sync**: Auto-executed with `-y` (no confirmation) ## Error Recovery @@ -198,6 +135,5 @@ Session archived successfully. Phase 1: find session → create .archiving marker Phase 2: read key files → build manifest entry (no writes) Phase 3: mkdir → mv → update manifest.json → rm marker -Phase 4: update project-tech.json features array (optional) -Phase 5: ask user → solidify learnings (optional) +Phase 4: /workflow:session:sync -y → update project-guidelines + project-tech ``` diff --git a/.claude/commands/workflow/session/sync.md b/.claude/commands/workflow/session/sync.md new file mode 100644 index 00000000..37c5dd01 --- /dev/null +++ b/.claude/commands/workflow/session/sync.md @@ -0,0 +1,196 @@ +--- +name: sync +description: Quick-sync session work to project-guidelines and project-tech +argument-hint: "[-y|--yes] [\"what was done\"]" +allowed-tools: Bash(*), Read(*), Write(*), Edit(*) +--- + +# Session Sync (/workflow:session:sync) + +One-shot update `project-guidelines.json` + `project-tech.json` from current session context. + +**Design**: Scan context → extract → write. No interactive wizards. + +## Auto Mode + +`--yes` or `-y`: Skip confirmation, auto-write both files. + +## Process + +``` +Step 1: Gather Context + ├─ git diff --stat HEAD~3..HEAD (recent changes) + ├─ Active session folder (.workflow/.lite-plan/*) if exists + └─ User summary ($ARGUMENTS or auto-generate from git log) + +Step 2: Extract Updates + ├─ Guidelines: conventions / constraints / learnings + └─ Tech: development_index entry + +Step 3: Preview & Confirm (skip if --yes) + +Step 4: Write both files + +Step 5: One-line confirmation +``` + +## Step 1: Gather Context + +```javascript +const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') +const userSummary = $ARGUMENTS.replace(/--yes|-y/g, '').trim() + +// Recent changes +const gitStat = Bash('git diff --stat HEAD~3..HEAD 2>/dev/null || git diff --stat HEAD 2>/dev/null') +const gitLog = Bash('git log --oneline -5') + +// Active session (optional) +const sessionFolders = Glob('.workflow/.lite-plan/*/plan.json') +let sessionContext = null +if (sessionFolders.length > 0) { + const latest = sessionFolders[sessionFolders.length - 1] + sessionContext = JSON.parse(Read(latest)) +} + +// Build summary +const summary = userSummary + || sessionContext?.summary + || gitLog.split('\n')[0].replace(/^[a-f0-9]+ /, '') +``` + +## Step 2: Extract Updates + +Analyze context and produce two update payloads. Use LLM reasoning (current agent) — no CLI calls. + +```javascript +// ── Guidelines extraction ── +// Scan git diff + session for: +// - New patterns adopted → convention +// - Restrictions discovered → constraint +// - Surprises / gotchas → learning +// +// Output: array of { type, category, text } +// RULE: Only extract genuinely reusable insights. Skip trivial/obvious items. +// RULE: Deduplicate against existing guidelines before adding. + +const existingGuidelines = JSON.parse(Read('.workflow/project-guidelines.json')) +const guidelineUpdates = [] // populated by agent analysis + +// ── Tech extraction ── +// Build one development_index entry from session work + +function detectCategory(text) { + text = text.toLowerCase() + if (/\b(fix|bug|error|crash)\b/.test(text)) return 'bugfix' + if (/\b(refactor|cleanup|reorganize)\b/.test(text)) return 'refactor' + if (/\b(doc|readme|comment)\b/.test(text)) return 'docs' + if (/\b(add|new|create|implement)\b/.test(text)) return 'feature' + return 'enhancement' +} + +function detectSubFeature(gitStat) { + // Most-changed directory from git diff --stat + const dirs = gitStat.match(/\S+\//g) || [] + const counts = {} + dirs.forEach(d => { + const seg = d.split('/').filter(Boolean).slice(-2, -1)[0] || 'general' + counts[seg] = (counts[seg] || 0) + 1 + }) + return Object.entries(counts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'general' +} + +const techEntry = { + title: summary.slice(0, 60), + sub_feature: detectSubFeature(gitStat), + date: new Date().toISOString().split('T')[0], + description: summary.slice(0, 100), + status: 'completed', + session_id: sessionContext ? sessionFolders[sessionFolders.length - 1].match(/lite-plan\/([^/]+)/)?.[1] : null +} +``` + +## Step 3: Preview & Confirm + +```javascript +// Show preview +console.log(` +── Sync Preview ── + +Guidelines (${guidelineUpdates.length} items): +${guidelineUpdates.map(g => ` [${g.type}/${g.category}] ${g.text}`).join('\n') || ' (none)'} + +Tech [${detectCategory(summary)}]: + ${techEntry.title} + +Target files: + .workflow/project-guidelines.json + .workflow/project-tech.json +`) + +if (!autoYes) { + const confirm = AskUserQuestion("Apply these updates? (modify/skip items if needed)") + // User can say "skip guidelines" or "change category to bugfix" etc. +} +``` + +## Step 4: Write + +```javascript +// ── Update project-guidelines.json ── +if (guidelineUpdates.length > 0) { + const guidelines = JSON.parse(Read('.workflow/project-guidelines.json')) + + for (const g of guidelineUpdates) { + if (g.type === 'learning') { + // Deduplicate by insight text + if (!guidelines.learnings.some(l => l.insight === g.text)) { + guidelines.learnings.push({ + date: new Date().toISOString().split('T')[0], + session_id: techEntry.session_id, + insight: g.text, + category: g.category + }) + } + } else { + // convention or constraint + const section = g.type === 'convention' ? 'conventions' : 'constraints' + if (!guidelines[section][g.category]) guidelines[section][g.category] = [] + if (!guidelines[section][g.category].includes(g.text)) { + guidelines[section][g.category].push(g.text) + } + } + } + + guidelines._metadata.updated_at = new Date().toISOString() + Write('.workflow/project-guidelines.json', JSON.stringify(guidelines, null, 2)) +} + +// ── Update project-tech.json ── +const techPath = '.workflow/project-tech.json' +const tech = JSON.parse(Read(techPath)) + +if (!tech.development_index) { + tech.development_index = { feature: [], enhancement: [], bugfix: [], refactor: [], docs: [] } +} + +const category = detectCategory(summary) +tech.development_index[category].push(techEntry) +tech._metadata.last_updated = new Date().toISOString() + +Write(techPath, JSON.stringify(tech, null, 2)) +``` + +## Step 5: Confirm + +``` +✓ Synced: ${guidelineUpdates.length} guidelines + 1 tech entry [${category}] +``` + +## Error Handling + +| Error | Resolution | +|-------|------------| +| File missing | Create scaffold (same as solidify Step 1) | +| No git history | Use user summary or session context only | +| No meaningful updates | Skip guidelines, still add tech entry | +| Duplicate entry | Skip silently (dedup check in Step 4) | diff --git a/.claude/skills/review-cycle/phases/review-fix.md b/.claude/skills/review-cycle/phases/review-fix.md index bd51edc8..78f2221c 100644 --- a/.claude/skills/review-cycle/phases/review-fix.md +++ b/.claude/skills/review-cycle/phases/review-fix.md @@ -736,6 +736,8 @@ TodoWrite({ ## Post-Completion Expansion +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。 + 完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` ## Best Practices diff --git a/.claude/skills/workflow-execute/SKILL.md b/.claude/skills/workflow-execute/SKILL.md index ebbf822b..6e323e64 100644 --- a/.claude/skills/workflow-execute/SKILL.md +++ b/.claude/skills/workflow-execute/SKILL.md @@ -361,6 +361,8 @@ if (autoYes) { ### Post-Completion Expansion +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。 + 完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` ## Execution Strategy (IMPL_PLAN-Driven) diff --git a/.claude/skills/workflow-lite-plan/phases/02-lite-execute.md b/.claude/skills/workflow-lite-plan/phases/02-lite-execute.md index 42eabe3f..5550dbc1 100644 --- a/.claude/skills/workflow-lite-plan/phases/02-lite-execute.md +++ b/.claude/skills/workflow-lite-plan/phases/02-lite-execute.md @@ -661,57 +661,13 @@ if (hasUnresolvedIssues(reviewResult)) { - `@{plan.json}` → `@${executionContext.session.artifacts.plan}` - `[@{exploration.json}]` → exploration files from artifacts (if exists) -### Step 6: Update Development Index +### Step 6: Auto-Sync Project State **Trigger**: After all executions complete (regardless of code review) -**Skip Condition**: Skip if `.workflow/project-tech.json` does not exist +**Operation**: Execute `/workflow:session:sync -y "{summary}"` to update both `project-guidelines.json` and `project-tech.json` in one shot. -**Operations**: -```javascript -const projectJsonPath = '.workflow/project-tech.json' -if (!fileExists(projectJsonPath)) return // Silent skip - -const projectJson = JSON.parse(Read(projectJsonPath)) - -// Initialize if needed -if (!projectJson.development_index) { - projectJson.development_index = { feature: [], enhancement: [], bugfix: [], refactor: [], docs: [] } -} - -// Detect category from keywords -function detectCategory(text) { - text = text.toLowerCase() - if (/\b(fix|bug|error|issue|crash)\b/.test(text)) return 'bugfix' - if (/\b(refactor|cleanup|reorganize)\b/.test(text)) return 'refactor' - if (/\b(doc|readme|comment)\b/.test(text)) return 'docs' - if (/\b(add|new|create|implement)\b/.test(text)) return 'feature' - return 'enhancement' -} - -// Detect sub_feature from task file paths -function detectSubFeature(tasks) { - const dirs = tasks.map(t => t.file?.split('/').slice(-2, -1)[0]).filter(Boolean) - const counts = dirs.reduce((a, d) => { a[d] = (a[d] || 0) + 1; return a }, {}) - return Object.entries(counts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'general' -} - -const category = detectCategory(`${planObject.summary} ${planObject.approach}`) -const entry = { - title: planObject.summary.slice(0, 60), - sub_feature: detectSubFeature(getTasks(planObject)), - date: new Date().toISOString().split('T')[0], - description: planObject.approach.slice(0, 100), - status: previousExecutionResults.every(r => r.status === 'completed') ? 'completed' : 'partial', - session_id: executionContext?.session?.id || null -} - -projectJson.development_index[category].push(entry) -projectJson.statistics.last_updated = new Date().toISOString() -Write(projectJsonPath, JSON.stringify(projectJson, null, 2)) - -console.log(`✓ Development index: [${category}] ${entry.title}`) -``` +Summary 取值优先级:`originalUserInput` → `planObject.summary` → git log 自动推断。 ## Best Practices @@ -804,6 +760,8 @@ Appended to `previousExecutionResults` array for context continuity in multi-exe ## Post-Completion Expansion +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech(Step 6 已触发,此处不重复)。 + 完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` **Fixed ID Pattern**: `${sessionId}-${groupId}` enables predictable lookup without auto-generated timestamps. diff --git a/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md b/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md index e2456f9f..a55dc98f 100644 --- a/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md +++ b/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md @@ -668,57 +668,13 @@ if (hasUnresolvedIssues(reviewResult)) { - `@{plan.json}` → `@${executionContext.session.artifacts.plan}` - `[@{exploration.json}]` → exploration files from artifacts (if exists) -### Step 6: Update Development Index +### Step 6: Auto-Sync Project State **Trigger**: After all executions complete (regardless of code review) -**Skip Condition**: Skip if `.workflow/project-tech.json` does not exist +**Operation**: Execute `/workflow:session:sync -y "{summary}"` to update both `project-guidelines.json` and `project-tech.json` in one shot. -**Operations**: -```javascript -const projectJsonPath = '.workflow/project-tech.json' -if (!fileExists(projectJsonPath)) return // Silent skip - -const projectJson = JSON.parse(Read(projectJsonPath)) - -// Initialize if needed -if (!projectJson.development_index) { - projectJson.development_index = { feature: [], enhancement: [], bugfix: [], refactor: [], docs: [] } -} - -// Detect category from keywords -function detectCategory(text) { - text = text.toLowerCase() - if (/\b(fix|bug|error|issue|crash)\b/.test(text)) return 'bugfix' - if (/\b(refactor|cleanup|reorganize)\b/.test(text)) return 'refactor' - if (/\b(doc|readme|comment)\b/.test(text)) return 'docs' - if (/\b(add|new|create|implement)\b/.test(text)) return 'feature' - return 'enhancement' -} - -// Detect sub_feature from task file paths -function detectSubFeature(tasks) { - const dirs = tasks.map(t => t.file?.split('/').slice(-2, -1)[0]).filter(Boolean) - const counts = dirs.reduce((a, d) => { a[d] = (a[d] || 0) + 1; return a }, {}) - return Object.entries(counts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'general' -} - -const category = detectCategory(`${planObject.summary} ${planObject.approach}`) -const entry = { - title: planObject.summary.slice(0, 60), - sub_feature: detectSubFeature(getTasks(planObject)), - date: new Date().toISOString().split('T')[0], - description: planObject.approach.slice(0, 100), - status: previousExecutionResults.every(r => r.status === 'completed') ? 'completed' : 'partial', - session_id: executionContext?.session?.id || null -} - -projectJson.development_index[category].push(entry) -projectJson.statistics.last_updated = new Date().toISOString() -Write(projectJsonPath, JSON.stringify(projectJson, null, 2)) - -console.log(`✓ Development index: [${category}] ${entry.title}`) -``` +Summary 取值优先级:`originalUserInput` → `planObject.summary` → git log 自动推断。 ## Best Practices @@ -811,7 +767,9 @@ Appended to `previousExecutionResults` array for context continuity in multi-exe ## Post-Completion Expansion -完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `Skill(skill="issue:new", args="{summary} - {dimension}")` +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech(Step 6 已触发,此处不重复)。 + +完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` **Fixed ID Pattern**: `${sessionId}-${groupId}` enables predictable lookup without auto-generated timestamps. diff --git a/.claude/skills/workflow-test-fix/SKILL.md b/.claude/skills/workflow-test-fix/SKILL.md index 855627f4..54976397 100644 --- a/.claude/skills/workflow-test-fix/SKILL.md +++ b/.claude/skills/workflow-test-fix/SKILL.md @@ -396,6 +396,8 @@ Automatic commits at key checkpoints: ## Post-Completion Expansion +**Auto-sync**: Execute `/workflow:session:sync -y "{summary}"` to update project-guidelines + project-tech. + After completion, ask user if they want to expand into issues (test/enhance/refactor/doc). Selected items call `/issue:new "{summary} - {dimension}"`. ## Coordinator Checklist diff --git a/.claude/skills/workflow-test-fix/phases/05-test-cycle-execute.md b/.claude/skills/workflow-test-fix/phases/05-test-cycle-execute.md index 79f9a3b2..041c62f1 100644 --- a/.claude/skills/workflow-test-fix/phases/05-test-cycle-execute.md +++ b/.claude/skills/workflow-test-fix/phases/05-test-cycle-execute.md @@ -454,6 +454,8 @@ The orchestrator automatically creates git commits at key checkpoints to enable #### Post-Completion Expansion +**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。 + 完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` ## Agent Roles Summary