@haoyiyin/workflow 0.2.11 → 0.3.1
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.
- package/dist/src/agents/contracts/implementer.d.ts +29 -0
- package/dist/src/agents/contracts/implementer.d.ts.map +1 -0
- package/dist/src/agents/contracts/implementer.js +94 -0
- package/dist/src/agents/contracts/implementer.js.map +1 -0
- package/dist/src/agents/contracts/index.d.ts +11 -0
- package/dist/src/agents/contracts/index.d.ts.map +1 -0
- package/dist/src/agents/contracts/index.js +11 -0
- package/dist/src/agents/contracts/index.js.map +1 -0
- package/dist/src/agents/contracts/planner.d.ts +25 -0
- package/dist/src/agents/contracts/planner.d.ts.map +1 -0
- package/dist/src/agents/contracts/planner.js +107 -0
- package/dist/src/agents/contracts/planner.js.map +1 -0
- package/dist/src/agents/contracts/router.d.ts +24 -0
- package/dist/src/agents/contracts/router.d.ts.map +1 -0
- package/dist/src/agents/contracts/router.js +137 -0
- package/dist/src/agents/contracts/router.js.map +1 -0
- package/dist/src/agents/contracts/verifier.d.ts +27 -0
- package/dist/src/agents/contracts/verifier.d.ts.map +1 -0
- package/dist/src/agents/contracts/verifier.js +115 -0
- package/dist/src/agents/contracts/verifier.js.map +1 -0
- package/dist/src/agents/dispatcher.d.ts +94 -51
- package/dist/src/agents/dispatcher.d.ts.map +1 -1
- package/dist/src/agents/dispatcher.js +207 -164
- package/dist/src/agents/dispatcher.js.map +1 -1
- package/dist/src/persistence/index.d.ts +4 -2
- package/dist/src/persistence/index.d.ts.map +1 -1
- package/dist/src/persistence/index.js +4 -1
- package/dist/src/persistence/index.js.map +1 -1
- package/dist/src/persistence/plan-md.d.ts +3 -2
- package/dist/src/persistence/plan-md.d.ts.map +1 -1
- package/dist/src/persistence/plan-md.js +47 -15
- package/dist/src/persistence/plan-md.js.map +1 -1
- package/dist/src/persistence/state-md.d.ts +2 -0
- package/dist/src/persistence/state-md.d.ts.map +1 -1
- package/dist/src/persistence/state-md.js +40 -22
- package/dist/src/persistence/state-md.js.map +1 -1
- package/dist/src/persistence/types.d.ts +35 -39
- package/dist/src/persistence/types.d.ts.map +1 -1
- package/dist/src/pi-extension.d.ts +4 -3
- package/dist/src/pi-extension.d.ts.map +1 -1
- package/dist/src/pi-extension.js +36 -67
- package/dist/src/pi-extension.js.map +1 -1
- package/dist/src/router/namespace/core/intent-router.d.ts +24 -0
- package/dist/src/router/namespace/core/intent-router.d.ts.map +1 -0
- package/dist/src/router/namespace/core/intent-router.js +190 -0
- package/dist/src/router/namespace/core/intent-router.js.map +1 -0
- package/dist/src/router/namespace/core/lifecycle-router.d.ts +28 -0
- package/dist/src/router/namespace/core/lifecycle-router.d.ts.map +1 -0
- package/dist/src/router/namespace/core/lifecycle-router.js +132 -0
- package/dist/src/router/namespace/core/lifecycle-router.js.map +1 -0
- package/dist/src/router/namespace/core/state-router.d.ts +32 -0
- package/dist/src/router/namespace/core/state-router.d.ts.map +1 -0
- package/dist/src/router/namespace/core/state-router.js +157 -0
- package/dist/src/router/namespace/core/state-router.js.map +1 -0
- package/dist/src/router/namespace/domain/code-router.d.ts +26 -0
- package/dist/src/router/namespace/domain/code-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/code-router.js +171 -0
- package/dist/src/router/namespace/domain/code-router.js.map +1 -0
- package/dist/src/router/namespace/domain/debug-router.d.ts +25 -0
- package/dist/src/router/namespace/domain/debug-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/debug-router.js +139 -0
- package/dist/src/router/namespace/domain/debug-router.js.map +1 -0
- package/dist/src/router/namespace/domain/plan-router.d.ts +29 -0
- package/dist/src/router/namespace/domain/plan-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/plan-router.js +160 -0
- package/dist/src/router/namespace/domain/plan-router.js.map +1 -0
- package/dist/src/router/namespace/domain/review-router.d.ts +24 -0
- package/dist/src/router/namespace/domain/review-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/review-router.js +116 -0
- package/dist/src/router/namespace/domain/review-router.js.map +1 -0
- package/dist/src/router/namespace/index.d.ts +19 -0
- package/dist/src/router/namespace/index.d.ts.map +1 -0
- package/dist/src/router/namespace/index.js +22 -0
- package/dist/src/router/namespace/index.js.map +1 -0
- package/dist/src/router/namespace/registry.d.ts +67 -0
- package/dist/src/router/namespace/registry.d.ts.map +1 -0
- package/dist/src/router/namespace/registry.js +197 -0
- package/dist/src/router/namespace/registry.js.map +1 -0
- package/dist/src/router/namespace/types.d.ts +124 -0
- package/dist/src/router/namespace/types.d.ts.map +1 -0
- package/dist/src/router/namespace/types.js +20 -0
- package/dist/src/router/namespace/types.js.map +1 -0
- package/dist/src/router/namespace/utility/fallback-router.d.ts +28 -0
- package/dist/src/router/namespace/utility/fallback-router.d.ts.map +1 -0
- package/dist/src/router/namespace/utility/fallback-router.js +88 -0
- package/dist/src/router/namespace/utility/fallback-router.js.map +1 -0
- package/dist/src/router/namespace/utility/quick-task-router.d.ts +28 -0
- package/dist/src/router/namespace/utility/quick-task-router.d.ts.map +1 -0
- package/dist/src/router/namespace/utility/quick-task-router.js +99 -0
- package/dist/src/router/namespace/utility/quick-task-router.js.map +1 -0
- package/dist/src/router/namespace/utility/research-router.d.ts +24 -0
- package/dist/src/router/namespace/utility/research-router.d.ts.map +1 -0
- package/dist/src/router/namespace/utility/research-router.js +84 -0
- package/dist/src/router/namespace/utility/research-router.js.map +1 -0
- package/dist/src/skills/agents-md/index.js +2 -2
- package/dist/src/skills/agents-md/index.js.map +1 -1
- package/dist/src/skills/execute-plan/index.d.ts +45 -65
- package/dist/src/skills/execute-plan/index.d.ts.map +1 -1
- package/dist/src/skills/execute-plan/index.js +325 -551
- package/dist/src/skills/execute-plan/index.js.map +1 -1
- package/dist/src/skills/index.d.ts +1 -0
- package/dist/src/skills/index.d.ts.map +1 -1
- package/dist/src/skills/index.js +1 -0
- package/dist/src/skills/index.js.map +1 -1
- package/dist/src/skills/quick-task/index.d.ts +4 -4
- package/dist/src/skills/quick-task/index.js +1 -1
- package/dist/src/skills/quick-task/index.js.map +1 -1
- package/dist/src/skills/review-diff/index.d.ts +6 -6
- package/dist/src/skills/review-diff/index.js +1 -1
- package/dist/src/skills/review-diff/index.js.map +1 -1
- package/dist/src/skills/router/index.d.ts +101 -0
- package/dist/src/skills/router/index.d.ts.map +1 -0
- package/dist/src/skills/router/index.js +450 -0
- package/dist/src/skills/router/index.js.map +1 -0
- package/dist/src/skills/router/types.d.ts +79 -0
- package/dist/src/skills/router/types.d.ts.map +1 -0
- package/dist/src/skills/router/types.js +8 -0
- package/dist/src/skills/router/types.js.map +1 -0
- package/dist/src/skills/systematic-debugging/index.js +1 -1
- package/dist/src/skills/systematic-debugging/index.js.map +1 -1
- package/dist/src/skills/tdd/index.d.ts +14 -14
- package/dist/src/skills/tdd/index.js +1 -1
- package/dist/src/skills/tdd/index.js.map +1 -1
- package/dist/src/skills/to-plan/index-enhanced.d.ts +4 -4
- package/dist/src/skills/to-plan/index-enhanced.d.ts.map +1 -1
- package/dist/src/skills/to-plan/index-enhanced.js +3 -5
- package/dist/src/skills/to-plan/index-enhanced.js.map +1 -1
- package/dist/src/skills/to-plan/index.d.ts +24 -91
- package/dist/src/skills/to-plan/index.d.ts.map +1 -1
- package/dist/src/skills/to-plan/index.js +214 -409
- package/dist/src/skills/to-plan/index.js.map +1 -1
- package/package.json +3 -5
- package/scripts/postinstall.js +42 -47
- package/src/agents/contracts/implementer.ts +122 -0
- package/src/agents/contracts/index.ts +27 -0
- package/src/agents/contracts/planner.ts +129 -0
- package/src/agents/contracts/router.ts +168 -0
- package/src/agents/contracts/verifier.ts +137 -0
- package/src/agents/dispatcher.ts +387 -362
- package/src/persistence/index.ts +10 -4
- package/src/persistence/plan-md.ts +52 -18
- package/src/persistence/state-md.ts +45 -23
- package/src/persistence/types.ts +37 -40
- package/src/pi-extension.ts +38 -76
- package/src/router/namespace/README.md +127 -0
- package/src/router/namespace/core/intent-router.ts +221 -0
- package/src/router/namespace/core/lifecycle-router.ts +156 -0
- package/src/router/namespace/core/state-router.ts +192 -0
- package/src/router/namespace/domain/code-router.ts +202 -0
- package/src/router/namespace/domain/debug-router.ts +167 -0
- package/src/router/namespace/domain/plan-router.ts +196 -0
- package/src/router/namespace/domain/review-router.ts +142 -0
- package/src/router/namespace/index.ts +84 -0
- package/src/router/namespace/registry.ts +242 -0
- package/src/router/namespace/types.ts +182 -0
- package/src/router/namespace/utility/fallback-router.ts +107 -0
- package/src/router/namespace/utility/quick-task-router.ts +121 -0
- package/src/router/namespace/utility/research-router.ts +105 -0
- package/src/skills/agents-md/index.ts +2 -2
- package/src/skills/execute-plan/index.ts +419 -673
- package/src/skills/index.ts +1 -0
- package/src/skills/quick-task/index.ts +1 -1
- package/src/skills/review-diff/index.ts +1 -1
- package/src/skills/router/SKILL.md +81 -0
- package/src/skills/router/index.ts +577 -0
- package/src/skills/router/types.ts +90 -0
- package/src/skills/systematic-debugging/index.ts +1 -1
- package/src/skills/tdd/index.ts +1 -1
- package/src/skills/to-plan/index-enhanced.ts +3 -5
- package/src/skills/to-plan/index.ts +231 -502
- package/dist/src/extension/classifier.d.ts +0 -18
- package/dist/src/extension/classifier.d.ts.map +0 -1
- package/dist/src/extension/classifier.js +0 -143
- package/dist/src/extension/classifier.js.map +0 -1
- package/src/extension/classifier.ts +0 -160
package/src/persistence/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Persistence layer
|
|
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
|
|
15
|
-
PlanMdManager as
|
|
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
|
-
|
|
25
|
-
|
|
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 => `- [
|
|
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(/- \[
|
|
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[
|
|
87
|
-
description: match[
|
|
88
|
-
|
|
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:
|
|
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
|
-
|
|
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}:
|
|
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
|
-
###
|
|
103
|
-
${plan.
|
|
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
|
|
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 =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
157
|
-
lastUpdated: new Date().toISOString(),
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
}
|
package/src/persistence/types.ts
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
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
|
+
}
|
package/src/pi-extension.ts
CHANGED
|
@@ -1,111 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PI Extension - yi-workflow
|
|
2
|
+
* PI Extension - yi-workflow router interceptor
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* ALL user input → /skill:router
|
|
5
|
+
* Router skill handles ALL routing logic (5-layer GSD).
|
|
6
|
+
* Extension does NOT classify intent — that's the router's job.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
import { classifyIntent } from "./extension/classifier.js";
|
|
9
|
-
|
|
10
|
-
// Extension API is provided by PI at runtime
|
|
11
|
-
// We use 'any' to avoid compile-time dependency
|
|
12
9
|
export default function (pi: any) {
|
|
13
|
-
// Store transformed input for before_agent_start to detect
|
|
14
10
|
let transformedInput: string | null = null;
|
|
15
11
|
|
|
16
|
-
// Intercept user input
|
|
12
|
+
// Intercept ALL user input → route to router skill
|
|
17
13
|
pi.on("input", async (event: any, ctx: any) => {
|
|
18
|
-
// Skip
|
|
14
|
+
// Skip slash commands (user explicitly calling a skill)
|
|
19
15
|
if (event.text.startsWith("/")) {
|
|
20
16
|
return { action: "continue" };
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Transform to explicit skill command with instruction not to analyze
|
|
44
|
-
const transformedText = `=== SKILL COMMAND ===\n/skill:${targetSkill}\n\nINPUT:\n${event.text}\n\n=== DO NOT ANALYZE ===\nYou MUST call the skill above immediately. NO thinking. NO planning. NO analysis. Just call the skill.`;
|
|
19
|
+
// Store for before_agent_start
|
|
20
|
+
transformedInput = event.text;
|
|
21
|
+
|
|
22
|
+
// Transform ALL input to router skill call
|
|
23
|
+
// The router skill does 5-layer routing internally
|
|
24
|
+
const transformedText = [
|
|
25
|
+
"=== ROUTER DISPATCH ===",
|
|
26
|
+
"/skill:router",
|
|
27
|
+
"",
|
|
28
|
+
"USER REQUEST:",
|
|
29
|
+
event.text,
|
|
30
|
+
"",
|
|
31
|
+
"=== INSTRUCTIONS ===",
|
|
32
|
+
"Call the router skill above IMMEDIATELY.",
|
|
33
|
+
"Do NOT analyze, plan, or execute the request yourself.",
|
|
34
|
+
"Do NOT use any tools (Read, Edit, Bash, etc.).",
|
|
35
|
+
"The router skill will determine the correct target skill.",
|
|
36
|
+
].join("\n");
|
|
37
|
+
|
|
38
|
+
ctx.ui.notify("[yi-workflow] → router", "info");
|
|
45
39
|
|
|
46
|
-
// Store for before_agent_start hook
|
|
47
|
-
transformedInput = transformedText;
|
|
48
|
-
|
|
49
|
-
// Transform input - this will be passed to main agent
|
|
50
40
|
return {
|
|
51
41
|
action: "transform",
|
|
52
42
|
text: transformedText,
|
|
53
43
|
};
|
|
54
44
|
});
|
|
55
45
|
|
|
56
|
-
// Log when session starts
|
|
57
46
|
pi.on("session_start", async (event: any, ctx: any) => {
|
|
58
|
-
ctx.ui.notify("yi-workflow
|
|
47
|
+
ctx.ui.notify("yi-workflow router active", "info");
|
|
59
48
|
});
|
|
60
49
|
|
|
61
|
-
//
|
|
62
|
-
// This ensures main agent NEVER executes work directly
|
|
50
|
+
// Minimal system prompt injection — just reinforce router dispatch
|
|
63
51
|
pi.on("before_agent_start", async (event: any, ctx: any) => {
|
|
64
52
|
const systemPrompt = event.systemPrompt || "";
|
|
65
|
-
|
|
66
|
-
// Get the user input (either from event or from transformed global)
|
|
67
53
|
const userInput = transformedInput || event.userInput || "";
|
|
68
54
|
|
|
69
|
-
|
|
70
|
-
const isSkillCommand = userInput.startsWith("/skill:");
|
|
71
|
-
|
|
72
|
-
// Prepend THIN DISPATCHER constraints
|
|
73
|
-
const thinDispatcherRules = `
|
|
74
|
-
╔══════════════════════════════════════════════════════════════════╗
|
|
75
|
-
║ THIN DISPATCHER PROTOCOL [ABSOLUTE] ║
|
|
76
|
-
╚══════════════════════════════════════════════════════════════════╝
|
|
55
|
+
const isRouterCommand = userInput.includes("/skill:router");
|
|
77
56
|
|
|
78
|
-
|
|
57
|
+
const rules = `
|
|
58
|
+
## ROUTER DISPATCH RULE (MANDATORY)
|
|
79
59
|
|
|
80
|
-
|
|
81
|
-
⚠️ ABSOLUTE RULE #2: You NEVER execute work yourself - only dispatch.
|
|
82
|
-
⚠️ ABSOLUTE RULE #3: Tools (Read, Edit, Bash, etc.) are FORBIDDEN unless in subagent.
|
|
60
|
+
You MUST follow this rule for ALL user messages:
|
|
83
61
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
- Writing code directly (use /skill:tdd or /skill:execute-plan)
|
|
89
|
-
- Using any tool directly (use /skill:quick-task to dispatch subagent)
|
|
62
|
+
1. If input contains "/skill:router" → CALL THE ROUTER SKILL IMMEDIATELY
|
|
63
|
+
2. You MUST NOT use any tools directly (Read, Edit, Bash, Grep, etc.)
|
|
64
|
+
3. You MUST NOT analyze, plan, or execute user requests yourself
|
|
65
|
+
4. Your ONLY action is: call /skill:router and return its output
|
|
90
66
|
|
|
91
|
-
CURRENT
|
|
92
|
-
IS_SKILL_COMMAND: ${isSkillCommand ? "YES - MUST CALL SKILL" : "NO"}
|
|
93
|
-
|
|
94
|
-
${isSkillCommand ? `
|
|
95
|
-
╔══════════════════════════════════════════════════════════════════╗
|
|
96
|
-
║ ⚠️ MANDATORY: CALL THE SKILL BELOW ⚠️ ║
|
|
97
|
-
╚══════════════════════════════════════════════════════════════════╝
|
|
98
|
-
The input starts with "/skill:". You MUST call that skill.
|
|
99
|
-
DO NOT process this input as a regular conversation.
|
|
100
|
-
DO NOT use tools directly.
|
|
101
|
-
CALL THE SKILL: "${userInput.split(" ")[0]}"
|
|
102
|
-
` : ""}
|
|
67
|
+
CURRENT REQUEST: ${isRouterCommand ? "ROUTER DISPATCH — CALL SKILL NOW" : "Normal message"}
|
|
103
68
|
`;
|
|
104
69
|
|
|
105
|
-
|
|
106
|
-
event.systemPrompt = thinDispatcherRules + "\n\n" + systemPrompt;
|
|
107
|
-
|
|
108
|
-
// Reset transformed input for next turn
|
|
70
|
+
event.systemPrompt = rules + "\n\n" + systemPrompt;
|
|
109
71
|
transformedInput = null;
|
|
110
72
|
|
|
111
73
|
return { action: "continue" };
|