Skip to content

Commit 4da0686

Browse files
author
catlog22
committed
feat: Enhance issue and solution management with new UI components and functionality
- Added internationalization support for new issue and solution-related strings in i18n.js. - Implemented a solution detail modal in issue-manager.js to display solution information and bind/unbind actions. - Enhanced the skill loading function to combine project and user skills in hook-manager.js. - Improved queue rendering logic to handle empty states and display queue statistics in issue-manager.js. - Introduced command modals for queue operations, allowing users to generate execution queues via CLI commands. - Added functionality to auto-generate issue IDs and regenerate them in the create issue modal. - Implemented detailed rendering of solution tasks, including acceptance criteria and modification points.
1 parent 8f31033 commit 4da0686

File tree

11 files changed

+2489
-168
lines changed

11 files changed

+2489
-168
lines changed

.claude/agents/issue-plan-agent.md

Lines changed: 240 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ async function ripgrepFallback(issue, projectRoot) {
199199

200200
## Phase 3: Solution Planning
201201

202-
### Task Decomposition
202+
### Task Decomposition (Closed-Loop)
203203

204204
```javascript
205205
function decomposeTasks(issue, exploration) {
@@ -217,15 +217,104 @@ function decomposeTasks(issue, exploration) {
217217
action: inferAction(group),
218218
description: group.description,
219219
modification_points: group.points,
220+
221+
// Phase 1: Implementation
220222
implementation: generateImplementationSteps(group, exploration),
223+
224+
// Phase 2: Test
225+
test: generateTestRequirements(group, exploration, issue.lifecycle_requirements),
226+
227+
// Phase 3: Regression
228+
regression: generateRegressionChecks(group, issue.lifecycle_requirements),
229+
230+
// Phase 4: Acceptance
221231
acceptance: generateAcceptanceCriteria(group),
232+
233+
// Phase 5: Commit
234+
commit: generateCommitSpec(group, issue),
235+
222236
depends_on: inferDependencies(group, tasks),
223-
estimated_minutes: estimateTime(group)
237+
estimated_minutes: estimateTime(group),
238+
executor: inferExecutor(group)
224239
})
225240
}
226241

227242
return tasks
228243
}
244+
245+
function generateTestRequirements(group, exploration, lifecycle) {
246+
const test = {
247+
unit: [],
248+
integration: [],
249+
commands: [],
250+
coverage_target: 80
251+
}
252+
253+
// Generate unit test requirements based on action
254+
if (group.action === 'Create' || group.action === 'Implement') {
255+
test.unit.push(`Test ${group.title} happy path`)
256+
test.unit.push(`Test ${group.title} error cases`)
257+
}
258+
259+
// Generate test commands based on project patterns
260+
if (exploration.test_patterns?.includes('jest')) {
261+
test.commands.push(`npm test -- --grep '${group.scope}'`)
262+
} else if (exploration.test_patterns?.includes('vitest')) {
263+
test.commands.push(`npx vitest run ${group.scope}`)
264+
} else {
265+
test.commands.push(`npm test`)
266+
}
267+
268+
// Add integration tests if needed
269+
if (lifecycle?.test_strategy === 'integration' || lifecycle?.test_strategy === 'e2e') {
270+
test.integration.push(`Integration test for ${group.title}`)
271+
}
272+
273+
return test
274+
}
275+
276+
function generateRegressionChecks(group, lifecycle) {
277+
const regression = []
278+
279+
switch (lifecycle?.regression_scope) {
280+
case 'full':
281+
regression.push('npm test')
282+
regression.push('npm run test:integration')
283+
break
284+
case 'related':
285+
regression.push(`npm test -- --grep '${group.scope}'`)
286+
regression.push(`npm test -- --changed`)
287+
break
288+
case 'affected':
289+
default:
290+
regression.push(`npm test -- --findRelatedTests ${group.points[0]?.file}`)
291+
break
292+
}
293+
294+
return regression
295+
}
296+
297+
function generateCommitSpec(group, issue) {
298+
const typeMap = {
299+
'Create': 'feat',
300+
'Implement': 'feat',
301+
'Update': 'feat',
302+
'Fix': 'fix',
303+
'Refactor': 'refactor',
304+
'Test': 'test',
305+
'Configure': 'chore',
306+
'Delete': 'chore'
307+
}
308+
309+
const scope = group.scope.split('/').pop()?.replace(/\..*$/, '') || 'core'
310+
311+
return {
312+
type: typeMap[group.action] || 'feat',
313+
scope: scope,
314+
message_template: `${typeMap[group.action] || 'feat'}(${scope}): ${group.title.toLowerCase()}\n\n${group.description || ''}`,
315+
breaking: false
316+
}
317+
}
229318
```
230319
231320
### Action Type Inference
@@ -347,11 +436,15 @@ function generateImplementationSteps(group, exploration) {
347436
}
348437
```
349438
350-
### Acceptance Criteria Generation
439+
### Acceptance Criteria Generation (Closed-Loop)
351440
352441
```javascript
353442
function generateAcceptanceCriteria(task) {
354-
const criteria = []
443+
const acceptance = {
444+
criteria: [],
445+
verification: [],
446+
manual_checks: []
447+
}
355448
356449
// Action-specific criteria
357450
const actionCriteria = {
@@ -363,14 +456,41 @@ function generateAcceptanceCriteria(task) {
363456
'Configure': [`Configuration applied correctly`]
364457
}
365458
366-
criteria.push(...(actionCriteria[task.action] || []))
459+
acceptance.criteria.push(...(actionCriteria[task.action] || []))
367460
368461
// Add quantified criteria
369462
if (task.modification_points.length > 0) {
370-
criteria.push(`${task.modification_points.length} file(s) modified correctly`)
463+
acceptance.criteria.push(`${task.modification_points.length} file(s) modified correctly`)
464+
}
465+
466+
// Generate verification steps for each criterion
467+
for (const criterion of acceptance.criteria) {
468+
acceptance.verification.push(generateVerificationStep(criterion, task))
371469
}
372470
373-
return criteria.slice(0, 4) // Max 4 criteria
471+
// Limit to reasonable counts
472+
acceptance.criteria = acceptance.criteria.slice(0, 4)
473+
acceptance.verification = acceptance.verification.slice(0, 4)
474+
475+
return acceptance
476+
}
477+
478+
function generateVerificationStep(criterion, task) {
479+
// Generate executable verification for criterion
480+
if (criterion.includes('file created')) {
481+
return `ls -la ${task.modification_points[0]?.file} && head -20 ${task.modification_points[0]?.file}`
482+
}
483+
if (criterion.includes('test')) {
484+
return `npm test -- --grep '${task.scope}'`
485+
}
486+
if (criterion.includes('export')) {
487+
return `node -e "console.log(require('./${task.modification_points[0]?.file}'))"`
488+
}
489+
if (criterion.includes('API') || criterion.includes('endpoint')) {
490+
return `curl -X GET http://localhost:3000/${task.scope} -v`
491+
}
492+
// Default: describe manual check
493+
return `Manually verify: ${criterion}`
374494
}
375495
```
376496
@@ -413,20 +533,61 @@ function validateSolution(solution) {
413533
function validateTask(task) {
414534
const errors = []
415535
536+
// Basic fields
416537
if (!/^T\d+$/.test(task.id)) errors.push('Invalid task ID format')
417538
if (!task.title?.trim()) errors.push('Missing title')
418539
if (!task.scope?.trim()) errors.push('Missing scope')
419540
if (!['Create', 'Update', 'Implement', 'Refactor', 'Configure', 'Test', 'Fix', 'Delete'].includes(task.action)) {
420541
errors.push('Invalid action type')
421542
}
543+
544+
// Phase 1: Implementation
422545
if (!task.implementation || task.implementation.length < 2) {
423546
errors.push('Need 2+ implementation steps')
424547
}
425-
if (!task.acceptance || task.acceptance.length < 1) {
426-
errors.push('Need 1+ acceptance criteria')
548+
549+
// Phase 2: Test
550+
if (!task.test) {
551+
errors.push('Missing test phase')
552+
} else {
553+
if (!task.test.commands || task.test.commands.length < 1) {
554+
errors.push('Need 1+ test commands')
555+
}
427556
}
428-
if (task.acceptance?.some(a => /works correctly|good performance|properly/i.test(a))) {
429-
errors.push('Vague acceptance criteria')
557+
558+
// Phase 3: Regression
559+
if (!task.regression || task.regression.length < 1) {
560+
errors.push('Need 1+ regression checks')
561+
}
562+
563+
// Phase 4: Acceptance
564+
if (!task.acceptance) {
565+
errors.push('Missing acceptance phase')
566+
} else {
567+
if (!task.acceptance.criteria || task.acceptance.criteria.length < 1) {
568+
errors.push('Need 1+ acceptance criteria')
569+
}
570+
if (!task.acceptance.verification || task.acceptance.verification.length < 1) {
571+
errors.push('Need 1+ verification steps')
572+
}
573+
if (task.acceptance.criteria?.some(a => /works correctly|good performance|properly/i.test(a))) {
574+
errors.push('Vague acceptance criteria')
575+
}
576+
}
577+
578+
// Phase 5: Commit
579+
if (!task.commit) {
580+
errors.push('Missing commit phase')
581+
} else {
582+
if (!['feat', 'fix', 'refactor', 'test', 'docs', 'chore'].includes(task.commit.type)) {
583+
errors.push('Invalid commit type')
584+
}
585+
if (!task.commit.scope?.trim()) {
586+
errors.push('Missing commit scope')
587+
}
588+
if (!task.commit.message_template?.trim()) {
589+
errors.push('Missing commit message template')
590+
}
430591
}
431592
432593
return errors
@@ -500,7 +661,9 @@ function generateOutput(solutions, conflicts) {
500661
}
501662
```
502663
503-
### Solution Schema
664+
### Solution Schema (Closed-Loop Tasks)
665+
666+
Each task MUST include ALL 5 lifecycle phases:
504667
505668
```json
506669
{
@@ -517,10 +680,62 @@ function generateOutput(solutions, conflicts) {
517680
"modification_points": [
518681
{ "file": "src/middleware/auth.ts", "target": "new file", "change": "Create middleware" }
519682
],
520-
"implementation": ["Step 1", "Step 2", "..."],
521-
"acceptance": ["Criterion 1", "Criterion 2"],
683+
684+
"implementation": [
685+
"Create auth.ts file in src/middleware/",
686+
"Implement JWT token extraction from Authorization header",
687+
"Add token validation using jsonwebtoken library",
688+
"Handle error cases (missing, invalid, expired tokens)",
689+
"Export middleware function"
690+
],
691+
692+
"test": {
693+
"unit": [
694+
"Test valid token passes through",
695+
"Test invalid token returns 401",
696+
"Test expired token returns 401",
697+
"Test missing token returns 401"
698+
],
699+
"integration": [
700+
"Protected route returns 401 without token",
701+
"Protected route returns 200 with valid token"
702+
],
703+
"commands": [
704+
"npm test -- --grep 'auth middleware'",
705+
"npm run test:coverage -- src/middleware/auth.ts"
706+
],
707+
"coverage_target": 80
708+
},
709+
710+
"regression": [
711+
"npm test -- --grep 'existing routes'",
712+
"npm run test:integration"
713+
],
714+
715+
"acceptance": {
716+
"criteria": [
717+
"Middleware validates JWT tokens successfully",
718+
"Returns 401 with appropriate error for invalid tokens",
719+
"Passes decoded user payload to request context"
720+
],
721+
"verification": [
722+
"curl -H 'Authorization: Bearer <valid>' /api/protected → 200",
723+
"curl /api/protected → 401 {error: 'No token'}",
724+
"curl -H 'Authorization: Bearer invalid' /api/protected → 401"
725+
],
726+
"manual_checks": []
727+
},
728+
729+
"commit": {
730+
"type": "feat",
731+
"scope": "auth",
732+
"message_template": "feat(auth): add JWT validation middleware\n\n- Implement token extraction and validation\n- Add error handling for invalid/expired tokens\n- Export middleware for route protection",
733+
"breaking": false
734+
},
735+
522736
"depends_on": [],
523-
"estimated_minutes": 30
737+
"estimated_minutes": 30,
738+
"executor": "codex"
524739
}
525740
],
526741
"exploration_context": {
@@ -622,6 +837,14 @@ Before outputting solution:
622837
6. Include file:line references in modification_points where possible
623838
7. Detect and report cross-issue file conflicts in batch mode
624839
8. Include exploration_context with patterns and relevant_files
840+
9. **Generate ALL 5 lifecycle phases for each task**:
841+
- `implementation`: 2-7 concrete steps
842+
- `test`: unit tests, commands, coverage target
843+
- `regression`: regression check commands
844+
- `acceptance`: criteria + verification steps
845+
- `commit`: type, scope, message template
846+
10. Infer test commands from project's test framework
847+
11. Generate commit message following conventional commits
625848
626849
**NEVER**:
627850
1. Execute implementation (return plan only)
@@ -632,3 +855,5 @@ Before outputting solution:
632855
6. Assume file exists without verification
633856
7. Generate more than 10 tasks per issue
634857
8. Skip ACE search (unless fallback triggered)
858+
9. **Omit any of the 5 lifecycle phases** (test, regression, acceptance, commit)
859+
10. Skip verification steps in acceptance criteria

0 commit comments

Comments
 (0)