@haoyiyin/workflow 0.2.10 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/src/agents/contracts/implementer.d.ts +29 -0
  2. package/dist/src/agents/contracts/implementer.d.ts.map +1 -0
  3. package/dist/src/agents/contracts/implementer.js +94 -0
  4. package/dist/src/agents/contracts/implementer.js.map +1 -0
  5. package/dist/src/agents/contracts/index.d.ts +11 -0
  6. package/dist/src/agents/contracts/index.d.ts.map +1 -0
  7. package/dist/src/agents/contracts/index.js +11 -0
  8. package/dist/src/agents/contracts/index.js.map +1 -0
  9. package/dist/src/agents/contracts/planner.d.ts +25 -0
  10. package/dist/src/agents/contracts/planner.d.ts.map +1 -0
  11. package/dist/src/agents/contracts/planner.js +107 -0
  12. package/dist/src/agents/contracts/planner.js.map +1 -0
  13. package/dist/src/agents/contracts/router.d.ts +24 -0
  14. package/dist/src/agents/contracts/router.d.ts.map +1 -0
  15. package/dist/src/agents/contracts/router.js +137 -0
  16. package/dist/src/agents/contracts/router.js.map +1 -0
  17. package/dist/src/agents/contracts/verifier.d.ts +27 -0
  18. package/dist/src/agents/contracts/verifier.d.ts.map +1 -0
  19. package/dist/src/agents/contracts/verifier.js +115 -0
  20. package/dist/src/agents/contracts/verifier.js.map +1 -0
  21. package/dist/src/agents/dispatcher.d.ts +94 -51
  22. package/dist/src/agents/dispatcher.d.ts.map +1 -1
  23. package/dist/src/agents/dispatcher.js +207 -164
  24. package/dist/src/agents/dispatcher.js.map +1 -1
  25. package/dist/src/persistence/index.d.ts +4 -2
  26. package/dist/src/persistence/index.d.ts.map +1 -1
  27. package/dist/src/persistence/index.js +4 -1
  28. package/dist/src/persistence/index.js.map +1 -1
  29. package/dist/src/persistence/plan-md.d.ts +3 -2
  30. package/dist/src/persistence/plan-md.d.ts.map +1 -1
  31. package/dist/src/persistence/plan-md.js +47 -15
  32. package/dist/src/persistence/plan-md.js.map +1 -1
  33. package/dist/src/persistence/state-md.d.ts +2 -0
  34. package/dist/src/persistence/state-md.d.ts.map +1 -1
  35. package/dist/src/persistence/state-md.js +40 -22
  36. package/dist/src/persistence/state-md.js.map +1 -1
  37. package/dist/src/persistence/types.d.ts +35 -39
  38. package/dist/src/persistence/types.d.ts.map +1 -1
  39. package/dist/src/router/namespace/core/intent-router.d.ts +24 -0
  40. package/dist/src/router/namespace/core/intent-router.d.ts.map +1 -0
  41. package/dist/src/router/namespace/core/intent-router.js +190 -0
  42. package/dist/src/router/namespace/core/intent-router.js.map +1 -0
  43. package/dist/src/router/namespace/core/lifecycle-router.d.ts +28 -0
  44. package/dist/src/router/namespace/core/lifecycle-router.d.ts.map +1 -0
  45. package/dist/src/router/namespace/core/lifecycle-router.js +132 -0
  46. package/dist/src/router/namespace/core/lifecycle-router.js.map +1 -0
  47. package/dist/src/router/namespace/core/state-router.d.ts +32 -0
  48. package/dist/src/router/namespace/core/state-router.d.ts.map +1 -0
  49. package/dist/src/router/namespace/core/state-router.js +157 -0
  50. package/dist/src/router/namespace/core/state-router.js.map +1 -0
  51. package/dist/src/router/namespace/domain/code-router.d.ts +26 -0
  52. package/dist/src/router/namespace/domain/code-router.d.ts.map +1 -0
  53. package/dist/src/router/namespace/domain/code-router.js +171 -0
  54. package/dist/src/router/namespace/domain/code-router.js.map +1 -0
  55. package/dist/src/router/namespace/domain/debug-router.d.ts +25 -0
  56. package/dist/src/router/namespace/domain/debug-router.d.ts.map +1 -0
  57. package/dist/src/router/namespace/domain/debug-router.js +139 -0
  58. package/dist/src/router/namespace/domain/debug-router.js.map +1 -0
  59. package/dist/src/router/namespace/domain/plan-router.d.ts +29 -0
  60. package/dist/src/router/namespace/domain/plan-router.d.ts.map +1 -0
  61. package/dist/src/router/namespace/domain/plan-router.js +160 -0
  62. package/dist/src/router/namespace/domain/plan-router.js.map +1 -0
  63. package/dist/src/router/namespace/domain/review-router.d.ts +24 -0
  64. package/dist/src/router/namespace/domain/review-router.d.ts.map +1 -0
  65. package/dist/src/router/namespace/domain/review-router.js +116 -0
  66. package/dist/src/router/namespace/domain/review-router.js.map +1 -0
  67. package/dist/src/router/namespace/index.d.ts +19 -0
  68. package/dist/src/router/namespace/index.d.ts.map +1 -0
  69. package/dist/src/router/namespace/index.js +22 -0
  70. package/dist/src/router/namespace/index.js.map +1 -0
  71. package/dist/src/router/namespace/registry.d.ts +67 -0
  72. package/dist/src/router/namespace/registry.d.ts.map +1 -0
  73. package/dist/src/router/namespace/registry.js +197 -0
  74. package/dist/src/router/namespace/registry.js.map +1 -0
  75. package/dist/src/router/namespace/types.d.ts +124 -0
  76. package/dist/src/router/namespace/types.d.ts.map +1 -0
  77. package/dist/src/router/namespace/types.js +20 -0
  78. package/dist/src/router/namespace/types.js.map +1 -0
  79. package/dist/src/router/namespace/utility/fallback-router.d.ts +28 -0
  80. package/dist/src/router/namespace/utility/fallback-router.d.ts.map +1 -0
  81. package/dist/src/router/namespace/utility/fallback-router.js +88 -0
  82. package/dist/src/router/namespace/utility/fallback-router.js.map +1 -0
  83. package/dist/src/router/namespace/utility/quick-task-router.d.ts +28 -0
  84. package/dist/src/router/namespace/utility/quick-task-router.d.ts.map +1 -0
  85. package/dist/src/router/namespace/utility/quick-task-router.js +99 -0
  86. package/dist/src/router/namespace/utility/quick-task-router.js.map +1 -0
  87. package/dist/src/router/namespace/utility/research-router.d.ts +24 -0
  88. package/dist/src/router/namespace/utility/research-router.d.ts.map +1 -0
  89. package/dist/src/router/namespace/utility/research-router.js +84 -0
  90. package/dist/src/router/namespace/utility/research-router.js.map +1 -0
  91. package/dist/src/skills/agents-md/index.js +2 -2
  92. package/dist/src/skills/agents-md/index.js.map +1 -1
  93. package/dist/src/skills/execute-plan/index.d.ts +45 -65
  94. package/dist/src/skills/execute-plan/index.d.ts.map +1 -1
  95. package/dist/src/skills/execute-plan/index.js +325 -551
  96. package/dist/src/skills/execute-plan/index.js.map +1 -1
  97. package/dist/src/skills/index.d.ts +1 -0
  98. package/dist/src/skills/index.d.ts.map +1 -1
  99. package/dist/src/skills/index.js +1 -0
  100. package/dist/src/skills/index.js.map +1 -1
  101. package/dist/src/skills/quick-task/index.d.ts +4 -4
  102. package/dist/src/skills/quick-task/index.js +1 -1
  103. package/dist/src/skills/quick-task/index.js.map +1 -1
  104. package/dist/src/skills/review-diff/index.d.ts +6 -6
  105. package/dist/src/skills/review-diff/index.js +1 -1
  106. package/dist/src/skills/review-diff/index.js.map +1 -1
  107. package/dist/src/skills/router/index.d.ts +101 -0
  108. package/dist/src/skills/router/index.d.ts.map +1 -0
  109. package/dist/src/skills/router/index.js +450 -0
  110. package/dist/src/skills/router/index.js.map +1 -0
  111. package/dist/src/skills/router/types.d.ts +79 -0
  112. package/dist/src/skills/router/types.d.ts.map +1 -0
  113. package/dist/src/skills/router/types.js +8 -0
  114. package/dist/src/skills/router/types.js.map +1 -0
  115. package/dist/src/skills/systematic-debugging/index.js +1 -1
  116. package/dist/src/skills/systematic-debugging/index.js.map +1 -1
  117. package/dist/src/skills/tdd/index.d.ts +14 -14
  118. package/dist/src/skills/tdd/index.js +1 -1
  119. package/dist/src/skills/tdd/index.js.map +1 -1
  120. package/dist/src/skills/to-plan/index-enhanced.d.ts +4 -4
  121. package/dist/src/skills/to-plan/index-enhanced.d.ts.map +1 -1
  122. package/dist/src/skills/to-plan/index-enhanced.js +3 -5
  123. package/dist/src/skills/to-plan/index-enhanced.js.map +1 -1
  124. package/dist/src/skills/to-plan/index.d.ts +24 -91
  125. package/dist/src/skills/to-plan/index.d.ts.map +1 -1
  126. package/dist/src/skills/to-plan/index.js +214 -409
  127. package/dist/src/skills/to-plan/index.js.map +1 -1
  128. package/package.json +3 -5
  129. package/src/agents/contracts/implementer.ts +122 -0
  130. package/src/agents/contracts/index.ts +27 -0
  131. package/src/agents/contracts/planner.ts +129 -0
  132. package/src/agents/contracts/router.ts +168 -0
  133. package/src/agents/contracts/verifier.ts +137 -0
  134. package/src/agents/dispatcher.ts +387 -362
  135. package/src/persistence/index.ts +10 -4
  136. package/src/persistence/plan-md.ts +52 -18
  137. package/src/persistence/state-md.ts +45 -23
  138. package/src/persistence/types.ts +37 -40
  139. package/src/router/namespace/README.md +127 -0
  140. package/src/router/namespace/core/intent-router.ts +221 -0
  141. package/src/router/namespace/core/lifecycle-router.ts +156 -0
  142. package/src/router/namespace/core/state-router.ts +192 -0
  143. package/src/router/namespace/domain/code-router.ts +202 -0
  144. package/src/router/namespace/domain/debug-router.ts +167 -0
  145. package/src/router/namespace/domain/plan-router.ts +196 -0
  146. package/src/router/namespace/domain/review-router.ts +142 -0
  147. package/src/router/namespace/index.ts +84 -0
  148. package/src/router/namespace/registry.ts +242 -0
  149. package/src/router/namespace/types.ts +182 -0
  150. package/src/router/namespace/utility/fallback-router.ts +107 -0
  151. package/src/router/namespace/utility/quick-task-router.ts +121 -0
  152. package/src/router/namespace/utility/research-router.ts +105 -0
  153. package/src/skills/agents-md/index.ts +2 -2
  154. package/src/skills/execute-plan/index.ts +419 -673
  155. package/src/skills/index.ts +1 -0
  156. package/src/skills/quick-task/index.ts +1 -1
  157. package/src/skills/review-diff/index.ts +1 -1
  158. package/src/skills/router/SKILL.md +181 -0
  159. package/src/skills/router/index.ts +577 -0
  160. package/src/skills/router/types.ts +90 -0
  161. package/src/skills/systematic-debugging/index.ts +1 -1
  162. package/src/skills/tdd/index.ts +1 -1
  163. package/src/skills/to-plan/index-enhanced.ts +3 -5
  164. package/src/skills/to-plan/index.ts +231 -502
@@ -1,8 +1,14 @@
1
1
  /**
2
- * Persistence layer exports
2
+ * Persistence layer entry point
3
+ *
4
+ * Provides STATE.md and PLAN.md management for workflow state persistence.
3
5
  */
6
+
7
+ // Managers
4
8
  export { StateMdManager } from './state-md.js'
5
9
  export { PlanMdManager } from './plan-md.js'
10
+
11
+ // Types
6
12
  export type {
7
13
  Task,
8
14
  Wave,
@@ -11,7 +17,7 @@ export type {
11
17
  VerificationResult,
12
18
  DimensionResult,
13
19
  WorkflowState,
14
- StateMdManager as IStateMdManager,
15
- PlanMdManager as IPlanMdManager,
16
- PersistenceManager
20
+ StateMdManager as StateMdManagerInterface,
21
+ PlanMdManager as PlanMdManagerInterface,
22
+ PersistenceManager,
17
23
  } from './types.js'
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { promises as fs } from 'fs'
5
5
  import { dirname } from 'path'
6
- import type { Plan, Task, PlanMdManager as IPlanMdManager } from './types.js'
6
+ import type { Plan, Task, Wave, PlanMdManager as IPlanMdManager } from './types.js'
7
7
 
8
8
  export class PlanMdManager implements IPlanMdManager {
9
9
  private planPath: string
@@ -20,9 +20,16 @@ export class PlanMdManager implements IPlanMdManager {
20
20
  await fs.writeFile(this.planPath, content, 'utf-8')
21
21
  }
22
22
 
23
- async readPlan(): Promise<Plan> {
24
- const content = await fs.readFile(this.planPath, 'utf-8')
25
- return this.parsePlan(content)
23
+ async readPlan(): Promise<Plan | null> {
24
+ try {
25
+ const content = await fs.readFile(this.planPath, 'utf-8')
26
+ return this.parsePlan(content)
27
+ } catch (error) {
28
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
29
+ return null
30
+ }
31
+ throw error
32
+ }
26
33
  }
27
34
 
28
35
  async updateTaskStatus(taskId: string, status: 'pending' | 'in_progress' | 'complete'): Promise<void> {
@@ -35,14 +42,37 @@ export class PlanMdManager implements IPlanMdManager {
35
42
  await fs.writeFile(this.planPath, updated, 'utf-8')
36
43
  }
37
44
 
45
+ async getNextPendingWave(): Promise<Wave | null> {
46
+ const plan = await this.readPlan()
47
+ if (!plan) {
48
+ return null
49
+ }
50
+
51
+ // Find first wave with pending tasks
52
+ for (const wave of plan.waves) {
53
+ const hasPendingTask = wave.tasks.some(task => task.status === 'pending')
54
+ if (hasPendingTask) {
55
+ return wave
56
+ }
57
+ }
58
+
59
+ return null
60
+ }
61
+
38
62
  private generatePlanMarkdown(plan: Plan): string {
63
+ const getStatusChar = (status: Task['status']) => {
64
+ if (status === 'completed') return 'x'
65
+ if (status === 'in_progress') return '~'
66
+ return ' '
67
+ }
68
+
39
69
  return `# Execution Plan
40
70
 
41
71
  ## Goal
42
72
  ${plan.goal}
43
73
 
44
74
  ## Tasks
45
- ${plan.tasks.map(t => `- [ ] ${t.id}: ${t.description} (${t.estimatedComplexity})`).join('\n')}
75
+ ${plan.tasks.map(t => `- [${getStatusChar(t.status)}] ${t.id}: ${t.description} (${t.estimatedComplexity})`).join('\n')}
46
76
 
47
77
  ## Dependencies
48
78
  ${Object.entries(plan.dependencies).length > 0
@@ -51,7 +81,7 @@ ${Object.entries(plan.dependencies).length > 0
51
81
  }
52
82
 
53
83
  ## Waves
54
- ${plan.waves.map(w => `- ${w.id}: ${w.tasks.join(', ')}`).join('\n')}
84
+ ${plan.waves.map(w => `- ${w.id}: ${w.tasks.map(t => t.id).join(', ')}`).join('\n')}
55
85
 
56
86
  ## Verification Criteria
57
87
  ${plan.verificationCriteria.map(c => `- ${c}`).join('\n')}
@@ -60,9 +90,6 @@ ${plan.verificationCriteria.map(c => `- ${c}`).join('\n')}
60
90
  - Total Tasks: ${plan.tasks.length}
61
91
  - Parallel Waves: ${plan.waves.length}
62
92
  - Estimated Duration: ${plan.estimatedDuration}ms
63
-
64
- ## Rationale
65
- ${plan.rationale}
66
93
  `
67
94
  }
68
95
 
@@ -73,19 +100,22 @@ ${plan.rationale}
73
100
  const wavesMatch = content.match(/## Waves\n([\s\S]*?)(?=\n## |$)/)
74
101
  const criteriaMatch = content.match(/## Verification Criteria\n([\s\S]*?)(?=\n## |$)/)
75
102
  const durationMatch = content.match(/- Estimated Duration: (\d+)/)
76
- const rationaleMatch = content.match(/## Rationale\n([\s\S]*?)(?=\n## |$)/)
77
103
 
78
104
  // Parse tasks
79
105
  const tasks: Task[] = []
80
106
  if (tasksMatch) {
81
107
  const taskLines = tasksMatch[1].split('\n').filter(l => l.trim().startsWith('- ['))
82
108
  for (const line of taskLines) {
83
- const match = line.match(/- \[[x\s~]]\s+(\w+):\s+(.+)\s+\((\w+)\)/)
109
+ const match = line.match(/- \[(.)\]\s+(\w+):\s+(.+)\s+\((\w+)\)/)
84
110
  if (match) {
111
+ const statusChar = match[1]
112
+ const status = statusChar === 'x' ? 'completed' : statusChar === '~' ? 'in_progress' : 'pending'
85
113
  tasks.push({
86
- id: match[1],
87
- description: match[2],
88
- estimatedComplexity: match[3] as 'low' | 'medium' | 'high'
114
+ id: match[2],
115
+ description: match[3],
116
+ status,
117
+ dependencies: [],
118
+ estimatedComplexity: match[4] as 'low' | 'medium' | 'high'
89
119
  })
90
120
  }
91
121
  }
@@ -103,16 +133,21 @@ ${plan.rationale}
103
133
  }
104
134
  }
105
135
 
136
+ // Build task map for wave parsing
137
+ const taskMap = new Map<string, Task>(tasks.map(t => [t.id, t]))
138
+
106
139
  // Parse waves
107
- const waves = []
140
+ const waves: Wave[] = []
108
141
  if (wavesMatch) {
109
142
  const waveLines = wavesMatch[1].split('\n').filter(l => l.trim().startsWith('- '))
110
143
  for (const line of waveLines) {
111
144
  const match = line.match(/- (\w+):\s*(.+)/)
112
145
  if (match) {
146
+ const taskIds = match[2].split(',').map(s => s.trim()).filter(s => s)
147
+ const waveTasks = taskIds.map(id => taskMap.get(id)).filter((t): t is Task => t !== undefined)
113
148
  waves.push({
114
149
  id: match[1],
115
- tasks: match[2].split(',').map(s => s.trim()).filter(s => s)
150
+ tasks: waveTasks
116
151
  })
117
152
  }
118
153
  }
@@ -134,8 +169,7 @@ ${plan.rationale}
134
169
  dependencies,
135
170
  waves,
136
171
  verificationCriteria,
137
- estimatedDuration: durationMatch ? parseInt(durationMatch[1], 10) : 0,
138
- rationale: rationaleMatch?.[1]?.trim() || ''
172
+ estimatedDuration: durationMatch ? parseInt(durationMatch[1], 10) : 0
139
173
  }
140
174
  }
141
175
  }
@@ -36,10 +36,7 @@ ${goal}
36
36
  <!-- Populated by verify phase -->
37
37
 
38
38
  ## Token Usage
39
- - Plan Phase: 0
40
- - Execute Phase: 0
41
- - Verify Phase: 0
42
- - Total: 0 / 1000000
39
+ 0
43
40
  `
44
41
  await fs.writeFile(this.statePath, content, 'utf-8')
45
42
  }
@@ -65,7 +62,14 @@ ${goal}
65
62
 
66
63
  async recordTaskComplete(taskId: string, result: TaskResult): Promise<void> {
67
64
  const content = await fs.readFile(this.statePath, 'utf-8')
68
- const entry = `- [x] ${taskId}: ${result.success ? '' : '✗'} (${result.duration}ms) - ${result.notes || ''}\n`
65
+ const entry = `- [x] ${taskId}: ✓ (${result.duration}ms) - ${result.notes || ''}\n`
66
+ const updated = this.appendToSection(content, 'Completed Tasks', entry)
67
+ await fs.writeFile(this.statePath, updated, 'utf-8')
68
+ }
69
+
70
+ async recordTaskFailed(taskId: string, error?: string): Promise<void> {
71
+ const content = await fs.readFile(this.statePath, 'utf-8')
72
+ const entry = `- [x] ${taskId}: ✗ FAILED${error ? ` - ${error}` : ''}\n`
69
73
  const updated = this.appendToSection(content, 'Completed Tasks', entry)
70
74
  await fs.writeFile(this.statePath, updated, 'utf-8')
71
75
  }
@@ -77,6 +81,15 @@ ${goal}
77
81
  await fs.writeFile(this.statePath, updated, 'utf-8')
78
82
  }
79
83
 
84
+ async updateTokenUsage(tokens: number): Promise<void> {
85
+ const content = await fs.readFile(this.statePath, 'utf-8')
86
+ const updated = content.replace(
87
+ /## Token Usage\n\d+/,
88
+ `## Token Usage\n${tokens}`
89
+ )
90
+ await fs.writeFile(this.statePath, updated, 'utf-8')
91
+ }
92
+
80
93
  async readCurrentState(): Promise<WorkflowState> {
81
94
  const content = await fs.readFile(this.statePath, 'utf-8')
82
95
  return this.parseState(content)
@@ -91,7 +104,7 @@ ${plan.goal}
91
104
  ${plan.tasks.map(t => `- ${t.id}: ${t.description} (${t.estimatedComplexity})`).join('\n')}
92
105
 
93
106
  ### Waves (${plan.waves.length})
94
- ${plan.waves.map(w => `- ${w.id}: ${w.tasks.join(', ')}`).join('\n')}
107
+ ${plan.waves.map(w => `- ${w.id}: ${w.tasks.map(t => t.id).join(', ')}`).join('\n')}
95
108
 
96
109
  ### Verification Criteria
97
110
  ${plan.verificationCriteria.map(c => `- ${c}`).join('\n')}
@@ -99,8 +112,8 @@ ${plan.verificationCriteria.map(c => `- ${c}`).join('\n')}
99
112
  ### Estimated Duration
100
113
  ${plan.estimatedDuration}ms
101
114
 
102
- ### Rationale
103
- ${plan.rationale}
115
+ ### Dependencies
116
+ ${Object.entries(plan.dependencies).map(([taskId, deps]) => `- ${taskId}: ${deps.join(', ') || 'none'}`).join('\n')}
104
117
  `
105
118
  }
106
119
 
@@ -141,27 +154,36 @@ ${results.join('\n')}
141
154
  const phaseMatch = content.match(/- Phase: (\w+)/)
142
155
  const goalMatch = content.match(/## Goal\n(.+)/)
143
156
  const startedMatch = content.match(/- Started: (.+)/)
144
- const totalMatch = content.match(/### Tasks \((\d+)\)/)
157
+ const lastUpdatedMatch = content.match(/- Last Updated: (.+)/)
158
+ const tokenMatch = content.match(/## Token Usage\n(\d+)/)
145
159
  const completedMatch = content.match(/## Completed Tasks\n([\s\S]*?)(?=\n## |$)/)
146
160
 
147
- const completedTasks = completedMatch
148
- ? completedMatch[1].split('\n').filter(l => l.trim().startsWith('- [x]')).length
149
- : 0
150
-
151
- const totalTasks = totalMatch ? parseInt(totalMatch[1], 10) : 0
161
+ const completedTasks: string[] = []
162
+ const failedTasks: string[] = []
163
+
164
+ if (completedMatch) {
165
+ const lines = completedMatch[1].split('\n').filter(l => l.trim().startsWith('- [x]'))
166
+ for (const line of lines) {
167
+ const taskIdMatch = line.match(/- \[x\] ([^:]+):/)
168
+ if (taskIdMatch) {
169
+ if (line.includes('✗ FAILED')) {
170
+ failedTasks.push(taskIdMatch[1])
171
+ } else {
172
+ completedTasks.push(taskIdMatch[1])
173
+ }
174
+ }
175
+ }
176
+ }
152
177
 
153
178
  return {
154
179
  goal: goalMatch?.[1] || '',
155
180
  phase: (phaseMatch?.[1] as WorkflowState['phase']) || 'planning',
156
- started: startedMatch?.[1] || new Date().toISOString(),
157
- lastUpdated: new Date().toISOString(),
158
- totalTasks,
159
- completedTasks: [],
160
- tokenUsage: {
161
- used: 0,
162
- limit: 1000000,
163
- percentage: 0
164
- }
181
+ startedAt: startedMatch?.[1] || new Date().toISOString(),
182
+ lastUpdated: lastUpdatedMatch?.[1] || new Date().toISOString(),
183
+ completedTasks,
184
+ failedTasks,
185
+ totalTasks: 0,
186
+ tokenUsage: { used: tokenMatch ? parseInt(tokenMatch[1], 10) : 0, limit: 1000000, percentage: 0 }
165
187
  }
166
188
  }
167
189
  }
@@ -5,67 +5,45 @@
5
5
  export interface Task {
6
6
  id: string
7
7
  description: string
8
+ status: 'pending' | 'in_progress' | 'completed' | 'failed'
9
+ dependencies: string[]
8
10
  estimatedComplexity: 'low' | 'medium' | 'high'
9
11
  relatedFiles?: string[]
10
- verificationCriteria?: string[]
11
12
  }
12
13
 
13
14
  export interface Wave {
14
15
  id: string
15
- tasks: string[]
16
+ tasks: Task[]
16
17
  }
17
18
 
18
19
  export interface Plan {
19
20
  goal: string
20
21
  tasks: Task[]
21
- dependencies: Record<string, string[]>
22
22
  waves: Wave[]
23
+ dependencies: Record<string, string[]>
23
24
  verificationCriteria: string[]
24
25
  estimatedDuration: number
25
- rationale: string
26
+ }
27
+
28
+ export interface WorkflowState {
29
+ goal: string
30
+ phase: 'discovery' | 'planning' | 'executing' | 'verifying' | 'completed' | 'failed' | 'idle'
31
+ startedAt: string
32
+ lastUpdated: string
33
+ completedTasks: string[]
34
+ failedTasks: string[]
35
+ totalTasks: number
36
+ tokenUsage: { used: number; limit: number; percentage: number }
26
37
  }
27
38
 
28
39
  export interface TaskResult {
29
40
  taskId: string
30
41
  success: boolean
31
- filesModified: string[]
32
- testsAdded: string[]
33
42
  duration: number
34
43
  notes: string
44
+ filesModified?: string[]
45
+ testsAdded?: string[]
35
46
  error?: string
36
- phases?: { phase: string; status: string; command?: string; evidence?: string }[]
37
- worktreePath?: string
38
- branchName?: string
39
- }
40
-
41
- export interface VerificationResult {
42
- success: boolean
43
- dimensions: {
44
- goals?: DimensionResult
45
- quality?: DimensionResult
46
- tests?: DimensionResult
47
- }
48
- }
49
-
50
- export interface DimensionResult {
51
- success: boolean
52
- details?: unknown
53
- evidence?: string[]
54
- gaps?: string[]
55
- }
56
-
57
- export interface WorkflowState {
58
- goal: string
59
- phase: 'planning' | 'executing' | 'verifying' | 'complete'
60
- started: string
61
- lastUpdated: string
62
- totalTasks: number
63
- completedTasks: TaskResult[]
64
- tokenUsage: {
65
- used: number
66
- limit: number
67
- percentage: number
68
- }
69
47
  }
70
48
 
71
49
  export interface StateMdManager {
@@ -73,17 +51,36 @@ export interface StateMdManager {
73
51
  updatePhase(phase: WorkflowState['phase']): Promise<void>
74
52
  recordPlan(plan: Plan): Promise<void>
75
53
  recordTaskComplete(taskId: string, result: TaskResult): Promise<void>
54
+ recordTaskFailed(taskId: string, error?: string): Promise<void>
76
55
  recordVerification(verification: VerificationResult): Promise<void>
56
+ updateTokenUsage(tokens: number): Promise<void>
77
57
  readCurrentState(): Promise<WorkflowState>
78
58
  }
79
59
 
80
60
  export interface PlanMdManager {
81
61
  writePlan(plan: Plan): Promise<void>
82
- readPlan(): Promise<Plan>
62
+ readPlan(): Promise<Plan | null>
83
63
  updateTaskStatus(taskId: string, status: 'pending' | 'in_progress' | 'complete'): Promise<void>
64
+ getNextPendingWave(): Promise<Wave | null>
84
65
  }
85
66
 
86
67
  export interface PersistenceManager {
87
68
  state: StateMdManager
88
69
  plan: PlanMdManager
89
70
  }
71
+
72
+ export interface VerificationResult {
73
+ success: boolean
74
+ dimensions: {
75
+ goals?: DimensionResult
76
+ quality?: DimensionResult
77
+ tests?: DimensionResult
78
+ }
79
+ }
80
+
81
+ export interface DimensionResult {
82
+ success: boolean
83
+ details?: unknown
84
+ evidence?: string[]
85
+ gaps?: string[]
86
+ }
@@ -0,0 +1,127 @@
1
+ # Namespace 路由分层设计
2
+
3
+ ## 架构概述
4
+
5
+ Namespace 路由分层设计将路由系统组织成层次化的命名空间,每个命名空间负责特定领域的路由决策。
6
+
7
+ ```
8
+ Router (根命名空间)
9
+ ├── Core (核心命名空间)
10
+ │ ├── LifecycleRouter - 生命周期阶段路由
11
+ │ ├── StateRouter - 状态感知路由
12
+ │ └── IntentRouter - 意图分类路由
13
+ ├── Domain (领域命名空间)
14
+ │ ├── PlanRouter - 计划相关路由
15
+ │ ├── CodeRouter - 代码操作路由
16
+ │ ├── DebugRouter - 调试相关路由
17
+ │ └── ReviewRouter - 代码审查路由
18
+ └── Utility (工具命名空间)
19
+ ├── QuickTaskRouter - 快速任务路由
20
+ ├── ResearchRouter - 研究探索路由
21
+ └── FallbackRouter - 降级路由
22
+ ```
23
+
24
+ ## 分层原则
25
+
26
+ ### Layer 1: 核心层 (Core)
27
+ 负责基础路由决策:
28
+ - **LifecycleRouter**: 根据项目生命周期阶段选择可用技能
29
+ - **StateRouter**: 根据 STATE.md 和 PLAN.md 的状态进行路由
30
+ - **IntentRouter**: 基于用户意图的分类和匹配
31
+
32
+ ### Layer 2: 领域层 (Domain)
33
+ 负责特定领域的复杂路由:
34
+ - **PlanRouter**: 计划创建、执行、验证的完整流程
35
+ - **CodeRouter**: 代码编写、重构、测试相关的路由
36
+ - **DebugRouter**: 调试、错误诊断、修复建议
37
+ - **ReviewRouter**: 代码审查、质量检查
38
+
39
+ ### Layer 3: 工具层 (Utility)
40
+ 处理简单的、独立的路由决策:
41
+ - **QuickTaskRouter**: 小任务、快速修复
42
+ - **ResearchRouter**: 研究、探索、信息收集
43
+ - **FallbackRouter**: 当其他路由无法确定时使用
44
+
45
+ ## 路由流程
46
+
47
+ ```
48
+ 用户请求
49
+
50
+ [Core Layer]
51
+ - 检查生命周期
52
+ - 读取 STATE/PLAN
53
+ - 提取意图
54
+
55
+ [Domain Layer] (如果匹配)
56
+ - 领域特定路由逻辑
57
+ - 复杂决策流程
58
+
59
+ [Utility Layer] (如果 Domain 不匹配)
60
+ - 简单匹配
61
+ - 快速决策
62
+
63
+ 选择目标 Skill
64
+ ```
65
+
66
+ ## Namespace 接口
67
+
68
+ ```typescript
69
+ // 命名空间路由接口
70
+ interface NamespaceRouter {
71
+ readonly name: string
72
+ readonly priority: number // 优先级,越高越先匹配
73
+ readonly patterns: string[] // 匹配模式
74
+
75
+ // 检查是否可以处理此请求
76
+ canRoute(context: RoutingContext): boolean | Promise<boolean>
77
+
78
+ // 执行路由决策
79
+ route(context: RoutingContext): RouteDecision | Promise<RouteDecision>
80
+ }
81
+
82
+ // 路由上下文
83
+ interface RoutingContext {
84
+ request: UserRequest
85
+ state: WorkflowState
86
+ plan: Plan | null
87
+ history: ConversationHistory[]
88
+ config: RouterConfig
89
+ }
90
+
91
+ // 路由决策
92
+ interface RouteDecision {
93
+ skill: string
94
+ confidence: number
95
+ reasoning: string
96
+ namespace: string // 来源命名空间
97
+ alternatives: AlternativeRoute[]
98
+ }
99
+ ```
100
+
101
+ ## 配置示例
102
+
103
+ ```typescript
104
+ // router.config.ts
105
+ export const namespaceConfig: NamespaceConfig = {
106
+ core: {
107
+ enabled: true,
108
+ routers: ['lifecycle', 'state', 'intent'],
109
+ },
110
+ domain: {
111
+ enabled: true,
112
+ routers: ['plan', 'code', 'debug', 'review'],
113
+ },
114
+ utility: {
115
+ enabled: true,
116
+ routers: ['quick-task', 'research', 'fallback'],
117
+ },
118
+ }
119
+ ```
120
+
121
+ ## 扩展性
122
+
123
+ 新增命名空间只需:
124
+ 1. 创建命名空间目录
125
+ 2. 实现 NamespaceRouter 接口
126
+ 3. 在配置中注册
127
+ 4. 系统自动加载并按优先级排序