@haoyiyin/workflow 0.2.0 → 0.2.3
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/package.json +15 -10
- package/scripts/postinstall.js +2 -2
- package/src/agents/contracts.ts +559 -0
- package/src/agents/dispatcher-enhanced.ts +350 -0
- package/src/agents/dispatcher.ts +680 -0
- package/src/agents/index.ts +48 -0
- package/src/agents/resilience.ts +255 -0
- package/src/agents/token-budget.ts +83 -0
- package/src/agents/types.ts +73 -0
- package/src/guard/main-agent.ts +245 -0
- package/src/hooks/builtin/index.ts +8 -0
- package/src/hooks/builtin/on-error.ts +23 -0
- package/src/hooks/builtin/post-execute.ts +40 -0
- package/src/hooks/builtin/post-plan.ts +23 -0
- package/src/hooks/builtin/pre-execute.ts +30 -0
- package/src/hooks/builtin/pre-plan.ts +26 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/loader.ts +98 -0
- package/src/hooks/manager.ts +99 -0
- package/src/hooks/types-enhanced.ts +38 -0
- package/src/hooks/types.ts +35 -0
- package/src/index.ts +127 -0
- package/src/persistence/index.ts +17 -0
- package/src/persistence/plan-md.ts +141 -0
- package/src/persistence/state-md.ts +167 -0
- package/src/persistence/types.ts +89 -0
- package/src/router/classifier.ts +610 -0
- package/src/router/guard.ts +483 -0
- package/src/router/index.ts +22 -0
- package/src/router/router.ts +108 -0
- package/src/router/types.ts +127 -0
- package/src/skills/agents-md/SKILL.md +45 -0
- package/src/skills/agents-md/index.ts +33 -0
- package/src/skills/execute-plan/SKILL.md +60 -0
- package/src/skills/execute-plan/index.ts +970 -0
- package/src/skills/index.ts +13 -0
- package/src/skills/quick-task/SKILL.md +54 -0
- package/src/skills/quick-task/index.ts +346 -0
- package/src/skills/registry.ts +59 -0
- package/src/skills/review-diff/SKILL.md +53 -0
- package/src/skills/review-diff/index.ts +394 -0
- package/src/skills/skill.ts +59 -0
- package/src/skills/systematic-debugging/SKILL.md +56 -0
- package/src/skills/systematic-debugging/index.ts +404 -0
- package/src/skills/tdd/SKILL.md +52 -0
- package/src/skills/tdd/index.ts +409 -0
- package/src/skills/to-plan/SKILL.md +56 -0
- package/src/skills/to-plan/index-enhanced.ts +551 -0
- package/src/skills/to-plan/index.ts +586 -0
- package/src/skills/types.ts +47 -0
- package/src/state/cleanup.ts +118 -0
- package/src/state/index.ts +8 -0
- package/src/state/manager.ts +96 -0
- package/src/state/persistence.ts +77 -0
- package/src/state/types.ts +30 -0
- package/src/state/validator.ts +78 -0
- package/src/types.ts +102 -0
- package/src/utils/compress.ts +347 -0
- package/src/utils/git.ts +82 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/logger.ts +23 -0
- package/src/utils/paths.ts +55 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills module index
|
|
3
|
+
*/
|
|
4
|
+
export type { SkillDefinition, SkillRegistry, SkillContext, ExecutionResult } from './types.js'
|
|
5
|
+
export { Registry, createRegistry } from './registry.js'
|
|
6
|
+
export { Skill } from './skill.js'
|
|
7
|
+
export { toPlanSkill, ToPlanSkill } from './to-plan/index.js'
|
|
8
|
+
export { executePlanSkill, ExecutePlanSkill } from './execute-plan/index.js'
|
|
9
|
+
export { quickTaskSkill, QuickTaskSkill } from './quick-task/index.js'
|
|
10
|
+
export { reviewDiffSkill, ReviewDiffSkill } from './review-diff/index.js'
|
|
11
|
+
export { tddSkill, TDDSkill } from './tdd/index.js'
|
|
12
|
+
export { systematicDebuggingSkill, SystematicDebuggingSkill } from './systematic-debugging/index.js'
|
|
13
|
+
export { agentsMdSkill, AgentsMdSkill } from './agents-md/index.js'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quick-task
|
|
3
|
+
description: Handle small scoped tasks in an isolated worktree. Promotes to full plan if scope exceeds the quick-task limit.
|
|
4
|
+
requires: [to-plan, execute-plan, systematic-debugging]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ⛔ MAIN AGENT CONSTRAINT
|
|
8
|
+
|
|
9
|
+
You are a THIN DISPATCHER. Your ONLY job is to dispatch subagents.
|
|
10
|
+
You MUST NOT: read source files, search code, write/edit files, run tests, run git commands.
|
|
11
|
+
You MAY only: read plan/state files, dispatch subagents via Agent tool, relay results.
|
|
12
|
+
For EVERY user request (including this skill), dispatch a subagent. Never execute yourself.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Use/Exclude Matrix
|
|
17
|
+
|
|
18
|
+
| Use When | Exclude When |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Typo fixes, renames, small edits | Multi-file architectural changes |
|
|
21
|
+
| Description under ~100 chars | Unknown scope or high risk |
|
|
22
|
+
| 1-5 files expected to change | Requires exploration before estimating |
|
|
23
|
+
| Low-risk, well-understood change | Needs TDD cycle or comprehensive review |
|
|
24
|
+
|
|
25
|
+
## Workflow
|
|
26
|
+
|
|
27
|
+
1. **Classify Scope** — Check if description matches trivial patterns (typo/rename/format). Fast-path trivial changes.
|
|
28
|
+
2. **Gather Context** — Dispatch read-only explorer subagent with tight token budget (8k) for focused context.
|
|
29
|
+
3. **Write Compact Plan** — Write minimal plan to `.pi/quick/` directory for audit trail.
|
|
30
|
+
4. **Implement** — Dispatch implementer subagent in isolated worktree. If scope exceeds 5 files, subagent returns PROMOTED_TO_FULL_PLAN.
|
|
31
|
+
5. **Quick Review** — Dispatch reviewer subagent with tight budget for surface-level check.
|
|
32
|
+
|
|
33
|
+
## Output Spec
|
|
34
|
+
|
|
35
|
+
| Field | Type | Description |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `status` | enum | `complete`, `needs-fixes`, `promoted`, `blocked` |
|
|
38
|
+
| `planPath` | string? | Path to compact plan if one was written |
|
|
39
|
+
| `filesModified` | string[] | Paths of files changed |
|
|
40
|
+
| `verification` | string? | Review output or verification result |
|
|
41
|
+
| `risks` | string[] | Identified risks or promotion reasons |
|
|
42
|
+
| `summary` | string | One-line description of result |
|
|
43
|
+
| `tokensUsed` | number | Total tokens consumed |
|
|
44
|
+
| `durationMs` | number | Wall-clock duration |
|
|
45
|
+
|
|
46
|
+
## Error Handling
|
|
47
|
+
|
|
48
|
+
| Error | Action |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Explorer subagent fails | Proceed with empty context |
|
|
51
|
+
| Implementer returns PROMOTED | Return status=promoted; caller should invoke to-plan |
|
|
52
|
+
| Implementer subagent fails | Return status=needs-fixes with errors |
|
|
53
|
+
| Reviewer subagent fails | Return complete with empty verification |
|
|
54
|
+
| Trivial change (<30 chars) | Fast-path: return immediately with status=complete |
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quick Task Skill - Handles small, scoped tasks with worktree isolation
|
|
3
|
+
*
|
|
4
|
+
* Use case: "Fix typo in README", "Rename function X to Y", "Add validation to endpoint"
|
|
5
|
+
* Pattern: Main Agent → Dispatcher → Single Implementer Subagent (worktree) → Result
|
|
6
|
+
*
|
|
7
|
+
* Design principles:
|
|
8
|
+
* - Single subagent, minimal overhead
|
|
9
|
+
* - Worktree isolation for safety
|
|
10
|
+
* - Returns subagent result directly
|
|
11
|
+
* - Fast-path for trivial changes
|
|
12
|
+
* - Promotes to full plan if scope exceeds quick-task limit
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { z } from 'zod'
|
|
16
|
+
import { Skill } from '../skill.js'
|
|
17
|
+
import type { SkillContext } from '../types.js'
|
|
18
|
+
import { createDispatcher } from '../../agents/dispatcher.js'
|
|
19
|
+
import { researcherContract } from '../../agents/contracts.js'
|
|
20
|
+
import { createMainAgentGuard } from '../../guard/main-agent.js'
|
|
21
|
+
import { mkdir, writeFile } from 'fs/promises'
|
|
22
|
+
import { join } from 'path'
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Schemas
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
const QuickTaskInputSchema = z.object({
|
|
29
|
+
description: z.string().min(1, 'Task description is required'),
|
|
30
|
+
filesHint: z.array(z.string()).optional(),
|
|
31
|
+
model: z.string().optional(),
|
|
32
|
+
skipTests: z.boolean().optional(),
|
|
33
|
+
tokenBudget: z.number().int().positive().max(100000).optional(),
|
|
34
|
+
timeout: z.number().int().positive().max(600).optional(),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const QuickTaskOutputSchema = z.object({
|
|
38
|
+
status: z.enum(['complete', 'needs-fixes', 'promoted', 'blocked']),
|
|
39
|
+
planPath: z.string().optional(),
|
|
40
|
+
filesModified: z.array(z.string()),
|
|
41
|
+
verification: z.string().optional(),
|
|
42
|
+
risks: z.array(z.string()),
|
|
43
|
+
summary: z.string(),
|
|
44
|
+
tokensUsed: z.number(),
|
|
45
|
+
durationMs: z.number(),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
type QuickTaskInput = z.infer<typeof QuickTaskInputSchema>
|
|
49
|
+
type QuickTaskOutput = z.infer<typeof QuickTaskOutputSchema>
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Constants
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
const DEFAULT_TOKEN_BUDGET = 16000
|
|
56
|
+
const DEFAULT_TIMEOUT_SECONDS = 120
|
|
57
|
+
const TRIVIAL_PATTERN = /fix typo|rename|format|add comment|update readme|fix lint/i
|
|
58
|
+
const MAX_TRIVIAL_LENGTH = 30
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Prompt builders (pure functions)
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
function buildExplorerPrompt(description: string): string {
|
|
65
|
+
return [
|
|
66
|
+
`Quick exploration for: ${description}`,
|
|
67
|
+
'',
|
|
68
|
+
'Gather focused context only. Do NOT deep-dive.',
|
|
69
|
+
'Return: relevant files, key dependencies, risks.',
|
|
70
|
+
'Keep output under 500 words.',
|
|
71
|
+
].join('\n')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function buildImplementerPrompt(
|
|
75
|
+
description: string,
|
|
76
|
+
planContent: string,
|
|
77
|
+
skipTests: boolean,
|
|
78
|
+
): string {
|
|
79
|
+
return [
|
|
80
|
+
`## Quick Task`,
|
|
81
|
+
'',
|
|
82
|
+
description,
|
|
83
|
+
'',
|
|
84
|
+
'## Compact Plan',
|
|
85
|
+
'',
|
|
86
|
+
planContent,
|
|
87
|
+
'',
|
|
88
|
+
'## Requirements',
|
|
89
|
+
'',
|
|
90
|
+
'1. Minimal changes only — stay in scope (1-5 files)',
|
|
91
|
+
'2. Read only files necessary for the task',
|
|
92
|
+
'3. Do NOT refactor unrelated code',
|
|
93
|
+
skipTests
|
|
94
|
+
? '4. Basic validation only (tests skipped for trivial change)'
|
|
95
|
+
: '4. Run relevant tests if they exist',
|
|
96
|
+
'5. Report every file changed',
|
|
97
|
+
'',
|
|
98
|
+
'## Scope Check',
|
|
99
|
+
'',
|
|
100
|
+
'If this task requires more than 5 files or architectural changes:',
|
|
101
|
+
'STOP and output "PROMOTED_TO_FULL_PLAN" in your response.',
|
|
102
|
+
'',
|
|
103
|
+
'## Output Format',
|
|
104
|
+
'',
|
|
105
|
+
'```json',
|
|
106
|
+
'{',
|
|
107
|
+
' "status": "success" | "failure" | "promoted",',
|
|
108
|
+
' "summary": "one-line description",',
|
|
109
|
+
' "filesModified": ["path/to/file"],',
|
|
110
|
+
' "notes": "warnings or follow-ups"',
|
|
111
|
+
'}',
|
|
112
|
+
'```',
|
|
113
|
+
].join('\n')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Skill class
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
export class QuickTaskSkill extends Skill<QuickTaskInput, QuickTaskOutput> {
|
|
121
|
+
constructor() {
|
|
122
|
+
super({
|
|
123
|
+
name: 'quick-task',
|
|
124
|
+
description:
|
|
125
|
+
'Handle small, scoped tasks in an isolated worktree. Promotes to full plan if scope exceeds limit.',
|
|
126
|
+
requires: ['to-plan', 'execute-plan', 'systematic-debugging'],
|
|
127
|
+
inputSchema: QuickTaskInputSchema,
|
|
128
|
+
outputSchema: QuickTaskOutputSchema,
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async execute(
|
|
133
|
+
input: QuickTaskInput,
|
|
134
|
+
context: SkillContext,
|
|
135
|
+
): Promise<QuickTaskOutput> {
|
|
136
|
+
const { config, logger } = context
|
|
137
|
+
const dispatcher = createDispatcher(logger)
|
|
138
|
+
const guard = createMainAgentGuard({}, logger)
|
|
139
|
+
let totalTokens = 0
|
|
140
|
+
|
|
141
|
+
// Step 1: Classify scope — fast-path for trivial changes
|
|
142
|
+
logger.info(`[quick-task] Classifying: ${input.description.slice(0, 100)}`)
|
|
143
|
+
const isTrivial =
|
|
144
|
+
input.description.length < MAX_TRIVIAL_LENGTH &&
|
|
145
|
+
TRIVIAL_PATTERN.test(input.description)
|
|
146
|
+
|
|
147
|
+
if (isTrivial) {
|
|
148
|
+
logger.info('[quick-task] Trivial change detected, fast-path')
|
|
149
|
+
return {
|
|
150
|
+
status: 'complete',
|
|
151
|
+
filesModified: [],
|
|
152
|
+
risks: [],
|
|
153
|
+
summary: 'Trivial change — handled directly',
|
|
154
|
+
tokensUsed: 0,
|
|
155
|
+
durationMs: 0,
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Step 2: Research if needed (new APIs, patterns, etc.)
|
|
160
|
+
let researchContext = ''
|
|
161
|
+
const needsResearch = /api|library|npm|install|upgrade|version|pattern|how to/i.test(input.description)
|
|
162
|
+
if (needsResearch) {
|
|
163
|
+
logger.info('[quick-task] Step 2a: Researching external context...')
|
|
164
|
+
const researchResult = await dispatcher.dispatch(
|
|
165
|
+
{
|
|
166
|
+
role: 'researcher',
|
|
167
|
+
model: input.model || config.defaultModel,
|
|
168
|
+
tokenBudget: 8000,
|
|
169
|
+
},
|
|
170
|
+
researcherContract({
|
|
171
|
+
topic: input.description,
|
|
172
|
+
scope: 'technical',
|
|
173
|
+
questions: ['What are current best practices?', 'Any breaking changes or gotchas?'],
|
|
174
|
+
timeRange: '6m'
|
|
175
|
+
})
|
|
176
|
+
)
|
|
177
|
+
totalTokens += researchResult.tokensUsed
|
|
178
|
+
researchContext = researchResult.output.slice(0, 800)
|
|
179
|
+
logger.info(`[quick-task] Research complete`)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Step 2b: Gather bounded context via read-only explorer
|
|
183
|
+
logger.info('[quick-task] Step 2b: Gathering context...')
|
|
184
|
+
const exploreResult = await dispatcher.dispatch(
|
|
185
|
+
{
|
|
186
|
+
role: 'explorer',
|
|
187
|
+
model: input.model || config.defaultModel,
|
|
188
|
+
tokenBudget: 8000,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
permissions: {
|
|
192
|
+
readFiles: true,
|
|
193
|
+
searchCode: true,
|
|
194
|
+
runCommands: false,
|
|
195
|
+
writeFiles: false,
|
|
196
|
+
gitOperations: false,
|
|
197
|
+
},
|
|
198
|
+
prompt: buildExplorerPrompt(input.description),
|
|
199
|
+
owns: [],
|
|
200
|
+
reads: input.filesHint ?? [],
|
|
201
|
+
},
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
totalTokens += exploreResult.tokensUsed
|
|
205
|
+
|
|
206
|
+
// Step 3: Write compact plan to disk
|
|
207
|
+
const date = new Date().toISOString().split('T')[0]
|
|
208
|
+
const sanitized = input.description
|
|
209
|
+
.toLowerCase()
|
|
210
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
211
|
+
.slice(0, 40)
|
|
212
|
+
const planPath = join(
|
|
213
|
+
config.planPath,
|
|
214
|
+
'quick',
|
|
215
|
+
`${date}-${sanitized}.md`,
|
|
216
|
+
)
|
|
217
|
+
await mkdir(join(config.planPath, 'quick'), { recursive: true })
|
|
218
|
+
|
|
219
|
+
const planContent = [
|
|
220
|
+
`# Quick Task: ${input.description}`,
|
|
221
|
+
'',
|
|
222
|
+
'## Context',
|
|
223
|
+
exploreResult.output.slice(0, 500),
|
|
224
|
+
...(researchContext ? ['', '## Research', researchContext] : []),
|
|
225
|
+
'',
|
|
226
|
+
'## Verification',
|
|
227
|
+
`- Run focused tests`,
|
|
228
|
+
`- No regressions`,
|
|
229
|
+
].join('\n')
|
|
230
|
+
|
|
231
|
+
await writeFile(planPath, planContent, 'utf-8')
|
|
232
|
+
|
|
233
|
+
// Step 4: Dispatch implementation in isolated worktree
|
|
234
|
+
guard.activateEmbargo()
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const implResult = await dispatcher.dispatch(
|
|
238
|
+
{
|
|
239
|
+
role: 'implementer',
|
|
240
|
+
model: input.model || config.defaultModel,
|
|
241
|
+
isolation: 'worktree',
|
|
242
|
+
tokenBudget: input.tokenBudget ?? DEFAULT_TOKEN_BUDGET,
|
|
243
|
+
timeout: input.timeout ?? DEFAULT_TIMEOUT_SECONDS,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
permissions: {
|
|
247
|
+
readFiles: true,
|
|
248
|
+
searchCode: true,
|
|
249
|
+
runCommands: true,
|
|
250
|
+
writeFiles: true,
|
|
251
|
+
gitOperations: false,
|
|
252
|
+
},
|
|
253
|
+
prompt: buildImplementerPrompt(
|
|
254
|
+
input.description,
|
|
255
|
+
planContent,
|
|
256
|
+
input.skipTests ?? false,
|
|
257
|
+
),
|
|
258
|
+
owns: [],
|
|
259
|
+
reads: input.filesHint ?? [],
|
|
260
|
+
},
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
totalTokens += implResult.tokensUsed
|
|
264
|
+
const needsPromotion =
|
|
265
|
+
implResult.output.includes('PROMOTED_TO_FULL_PLAN')
|
|
266
|
+
|
|
267
|
+
if (needsPromotion) {
|
|
268
|
+
return {
|
|
269
|
+
status: 'promoted',
|
|
270
|
+
planPath,
|
|
271
|
+
filesModified: [],
|
|
272
|
+
risks: ['Scope exceeded quick-task limit — promote to to-plan'],
|
|
273
|
+
summary: 'Promoted to full plan. Use to-plan for comprehensive planning.',
|
|
274
|
+
tokensUsed: totalTokens,
|
|
275
|
+
durationMs: implResult.duration,
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (implResult.status !== 'success') {
|
|
280
|
+
return {
|
|
281
|
+
status: 'needs-fixes',
|
|
282
|
+
planPath,
|
|
283
|
+
filesModified: [],
|
|
284
|
+
risks: implResult.errors,
|
|
285
|
+
summary: `Implementation failed: ${implResult.errors.join('; ')}`,
|
|
286
|
+
tokensUsed: totalTokens,
|
|
287
|
+
durationMs: implResult.duration,
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Step 5: Quick review of the changes
|
|
292
|
+
let reviewOutput = ''
|
|
293
|
+
const reviewResult = await dispatcher.dispatch(
|
|
294
|
+
{
|
|
295
|
+
role: 'reviewer',
|
|
296
|
+
model: input.model || config.defaultModel,
|
|
297
|
+
tokenBudget: 8000,
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
permissions: {
|
|
301
|
+
readFiles: true,
|
|
302
|
+
searchCode: false,
|
|
303
|
+
runCommands: false,
|
|
304
|
+
writeFiles: false,
|
|
305
|
+
gitOperations: false,
|
|
306
|
+
},
|
|
307
|
+
prompt: [
|
|
308
|
+
`Quick review of: ${input.description}`,
|
|
309
|
+
'',
|
|
310
|
+
'## Implementation Output',
|
|
311
|
+
'',
|
|
312
|
+
implResult.output.slice(0, 2000),
|
|
313
|
+
'',
|
|
314
|
+
'Check for: obvious bugs, missed edge cases, style violations.',
|
|
315
|
+
'Keep review concise — under 300 words.',
|
|
316
|
+
].join('\n'),
|
|
317
|
+
owns: [],
|
|
318
|
+
reads: [],
|
|
319
|
+
},
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
totalTokens += reviewResult.tokensUsed
|
|
323
|
+
reviewOutput = reviewResult.output
|
|
324
|
+
|
|
325
|
+
const filesModified = implResult.artifacts
|
|
326
|
+
.filter((a) => a.path)
|
|
327
|
+
.map((a) => a.path as string)
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
status: implResult.status === 'success' ? 'complete' : 'needs-fixes',
|
|
331
|
+
planPath,
|
|
332
|
+
filesModified,
|
|
333
|
+
verification: reviewOutput,
|
|
334
|
+
risks: [],
|
|
335
|
+
summary: implResult.output.slice(0, 200),
|
|
336
|
+
tokensUsed: totalTokens,
|
|
337
|
+
durationMs: implResult.duration,
|
|
338
|
+
}
|
|
339
|
+
} finally {
|
|
340
|
+
guard.deactivateEmbargo()
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export const quickTaskSkill = new QuickTaskSkill()
|
|
346
|
+
export default quickTaskSkill
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill registry implementation
|
|
3
|
+
*/
|
|
4
|
+
import type { SkillDefinition, SkillRegistry } from './types.js'
|
|
5
|
+
|
|
6
|
+
export class Registry implements SkillRegistry {
|
|
7
|
+
private skills: Map<string, SkillDefinition<any, any>> = new Map()
|
|
8
|
+
|
|
9
|
+
register(skill: SkillDefinition<any, any>): void {
|
|
10
|
+
if (this.skills.has(skill.name)) {
|
|
11
|
+
throw new Error(`Skill already registered: ${skill.name}`)
|
|
12
|
+
}
|
|
13
|
+
this.skills.set(skill.name, skill)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
unregister(name: string): void {
|
|
17
|
+
this.skills.delete(name)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get(name: string): SkillDefinition<any, any> | null {
|
|
21
|
+
return this.skills.get(name) || null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
list(): SkillDefinition<any, any>[] {
|
|
25
|
+
return Array.from(this.skills.values())
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getDependencies(name: string): string[] {
|
|
29
|
+
const skill = this.get(name)
|
|
30
|
+
return skill?.requires || []
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
resolveOrder(skillNames: string[]): string[] {
|
|
34
|
+
const visited = new Set<string>()
|
|
35
|
+
const result: string[] = []
|
|
36
|
+
|
|
37
|
+
const visit = (name: string) => {
|
|
38
|
+
if (visited.has(name)) return
|
|
39
|
+
visited.add(name)
|
|
40
|
+
|
|
41
|
+
const deps = this.getDependencies(name)
|
|
42
|
+
for (const dep of deps) {
|
|
43
|
+
visit(dep)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
result.push(name)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const name of skillNames) {
|
|
50
|
+
visit(name)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function createRegistry(): SkillRegistry {
|
|
58
|
+
return new Registry()
|
|
59
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-diff
|
|
3
|
+
description: Review code changes via reviewer subagents. Returns structured report with severity-classified issues.
|
|
4
|
+
requires: []
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ⛔ MAIN AGENT CONSTRAINT
|
|
8
|
+
|
|
9
|
+
You are a THIN DISPATCHER. Your ONLY job is to dispatch subagents.
|
|
10
|
+
You MUST NOT: read source files, search code, write/edit files, run tests, run git commands.
|
|
11
|
+
You MAY only: read plan/state files, dispatch subagents via Agent tool, relay results.
|
|
12
|
+
For EVERY user request (including this skill), dispatch a subagent. Never execute yourself.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Use/Exclude Matrix
|
|
17
|
+
|
|
18
|
+
| Use When | Exclude When |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Reviewing branch, PR, commit, or diff file | No diff/changes to review |
|
|
21
|
+
| Pre-merge quality gate | Trivial one-line change |
|
|
22
|
+
| Need structured issue report | Review is purely informational (no action needed) |
|
|
23
|
+
| Spec compliance check against a plan | Plan file unavailable and spec check not required |
|
|
24
|
+
|
|
25
|
+
## Workflow
|
|
26
|
+
|
|
27
|
+
1. **Get Diff** — Dispatch explorer subagent to fetch diff via git/gh/cat depending on target type.
|
|
28
|
+
2. **Inspect Surface** — Dispatch explorer to analyze changed files, line counts, and scope.
|
|
29
|
+
3. **Check Spec Compliance** — If plan path provided, dispatch reviewer to compare implementation against plan requirements.
|
|
30
|
+
4. **Assess Tests** — Dispatch reviewer to check whether changed files have corresponding test changes.
|
|
31
|
+
5. **Review Quality** — Dispatch reviewer to check correctness, security, performance, style, error handling.
|
|
32
|
+
6. **Compile Report** — Parse structured issue output into final report with decision.
|
|
33
|
+
|
|
34
|
+
## Output Spec
|
|
35
|
+
|
|
36
|
+
| Field | Type | Description |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `decision` | enum | `approve`, `changes`, `blocked`, `needs-evidence` |
|
|
39
|
+
| `issues` | array | Each with severity (blocker/major/minor/note), file, line, description, action |
|
|
40
|
+
| `specCompliance` | enum | `pass`, `partial`, `fail` |
|
|
41
|
+
| `testAssessment` | enum | `adequate`, `missing`, `failing` |
|
|
42
|
+
| `strengths` | string[] | Positive observations |
|
|
43
|
+
| `summary` | string | Human-readable review summary |
|
|
44
|
+
| `tokensUsed` | number | Total tokens consumed |
|
|
45
|
+
|
|
46
|
+
## Error Handling
|
|
47
|
+
|
|
48
|
+
| Error | Action |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Cannot access diff (bad target) | Return decision=needs-evidence with blocker issue |
|
|
51
|
+
| Diff subagent fails | Return needs-evidence; caller verifies target exists |
|
|
52
|
+
| Quality review produces no parseable issues | Return approve with empty issues list |
|
|
53
|
+
| Plan file not found for spec check | Skip spec compliance; mark as partial |
|