@we-scrum/cli 1.0.4 → 1.0.5
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/cli.js +99 -47
- package/package.json +18 -14
- package/src/cli.ts +73 -38
- package/src/hbs.d.ts +4 -0
- package/src/helpers/auth-helper.ts +1 -1
- package/src/helpers/index.ts +1 -0
- package/src/helpers/template.helper.ts +23 -0
- package/src/helpers/we-scrum.helper.ts +77 -93
- package/src/mcp-server/mcp-server.ts +26 -54
- package/src/mcp-server/tools/get-next-task.ts +19 -143
- package/src/mcp-server/tools/index.ts +0 -3
- package/templates/develop-story-skill.hbs +40 -0
- package/templates/get-next-task-description.hbs +3 -0
- package/templates/get-next-task.hbs +21 -0
- package/tsconfig.json +2 -1
- package/src/mcp-server/tools/complete-task.ts +0 -6
- package/src/mcp-server/tools/get-unit-test-guidelines.ts +0 -15
- package/src/mcp-server/tools/start-task.ts +0 -6
|
@@ -1,150 +1,26 @@
|
|
|
1
|
-
import { WeScrumHelper } from '@helpers';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
ProjectStorySectionModelEnumerationChange,
|
|
6
|
-
ProjectStorySectionModelObjectChange,
|
|
7
|
-
ProjectStorySectionModelRelationChange,
|
|
8
|
-
ProjectStorySectionModelRouteChange,
|
|
9
|
-
ProjectStorySectionModelTask,
|
|
10
|
-
} from '@we-scrum/models';
|
|
1
|
+
import { renderTemplate, WeScrumHelper } from '@helpers';
|
|
2
|
+
import { ProgressStatus } from '@we-scrum/enums';
|
|
3
|
+
import { StorySectionHelper, stringifyAnalysisDslChange } from '@we-scrum/utils';
|
|
11
4
|
|
|
12
|
-
export async function getNextTask(identificationNumber: string): Promise<
|
|
13
|
-
const
|
|
5
|
+
export async function getNextTask(identificationNumber: string): Promise<string> {
|
|
6
|
+
const nextChange = await WeScrumHelper.getNextChange(identificationNumber);
|
|
14
7
|
|
|
15
|
-
if (!
|
|
16
|
-
return
|
|
8
|
+
if (!nextChange) {
|
|
9
|
+
return `## Story ${identificationNumber}\n\nAll tasks are complete.`;
|
|
17
10
|
}
|
|
18
11
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
'Refer to `implementationGuidelines` for coding conventions and project-specific instructions.',
|
|
23
|
-
isTodo ? 'Before making any changes, run `start_task` to mark the task as in progress.' : null,
|
|
24
|
-
'If anything is unclear, stop and ask before making any changes.',
|
|
25
|
-
'Once all changes are done, commit your code and run `complete_task`.',
|
|
26
|
-
'After completing a task, immediately run `get_next_task` again and continue until all tasks are complete.',
|
|
27
|
-
]).join('\n');
|
|
12
|
+
const analysisChange = StorySectionHelper.mapSingleChange(nextChange);
|
|
13
|
+
const isTodo = nextChange.progress.status === ProgressStatus.ToDo;
|
|
14
|
+
const developmentPolicy = await WeScrumHelper.getChangeDevelopmentPolicy(nextChange);
|
|
28
15
|
|
|
29
|
-
const
|
|
30
|
-
const implementationGuidelines = developmentPolicy?.codeGuidelines ?? 'No guidelines found for this task... :-(';
|
|
16
|
+
const { guidelinesPath, unitTestsPath } = WeScrumHelper.getDevelopmentPolicyPaths(developmentPolicy);
|
|
31
17
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.join('\n');
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
generalInstructions,
|
|
44
|
-
taskType: `${nextTask.operation} enumeration`,
|
|
45
|
-
enumerationName: nextTask.enumerationName,
|
|
46
|
-
propertyChanges: propertyChanges || 'No change on properties',
|
|
47
|
-
taskDescription: nextTask.description ?? undefined,
|
|
48
|
-
implementationGuidelines,
|
|
49
|
-
unitTests,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
if (nextTask instanceof ProjectStorySectionModelObjectChange) {
|
|
53
|
-
const propertyMap = new Map(nextTask.propertyChanges.map((pc) => [pc.objectPropertyId, pc]));
|
|
54
|
-
|
|
55
|
-
const buildPath = (pc: (typeof nextTask.propertyChanges)[0]): string => {
|
|
56
|
-
const name = pc.isArray ? `${pc.propertyName}[]` : pc.propertyName;
|
|
57
|
-
if (!pc.objectPropertyParentId) return name;
|
|
58
|
-
const parent = propertyMap.get(pc.objectPropertyParentId);
|
|
59
|
-
return parent ? `${buildPath(parent)}.${name}` : name;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const changedProperties = nextTask.propertyChanges.filter((pc) => !!pc.operation);
|
|
63
|
-
const parentIdsWithChangedChildren = new Set(changedProperties.map((pc) => pc.objectPropertyParentId).filter(Boolean));
|
|
64
|
-
|
|
65
|
-
const propertyChanges = changedProperties
|
|
66
|
-
.filter((pc) => !(pc.operation === Operation.Create && parentIdsWithChangedChildren.has(pc.objectPropertyId)))
|
|
67
|
-
.map((pc) => {
|
|
68
|
-
const enumInfo = pc.enumerationName ? ` (enum: ${pc.enumerationName})` : '';
|
|
69
|
-
return `${pc.operation} property ${buildPath(pc)}: ${pc.propertyType}${enumInfo}`;
|
|
70
|
-
})
|
|
71
|
-
.sort()
|
|
72
|
-
.join('\n');
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
generalInstructions,
|
|
76
|
-
taskType: `${nextTask.operation} object`,
|
|
77
|
-
objectName: nextTask.objectName,
|
|
78
|
-
renamedFrom: nextTask.initialObjectName
|
|
79
|
-
? `Object renamed from "${nextTask.initialObjectName}" to "${nextTask.objectName}"`
|
|
80
|
-
: undefined,
|
|
81
|
-
propertyChanges: propertyChanges || 'No change on properties',
|
|
82
|
-
taskDescription: nextTask.description ?? undefined,
|
|
83
|
-
implementationGuidelines,
|
|
84
|
-
unitTests,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
if (nextTask instanceof ProjectStorySectionModelRouteChange) {
|
|
88
|
-
const queryParamChanges = nextTask.queryParamChanges
|
|
89
|
-
.filter((qp) => !!qp.operation)
|
|
90
|
-
.map((qp) => {
|
|
91
|
-
const enumInfo = qp.enumerationName ? ` (enum: ${qp.enumerationName})` : '';
|
|
92
|
-
return `${qp.operation} query param ${qp.routeQueryParamName}: ${qp.routeQueryParamType}${enumInfo}`;
|
|
93
|
-
})
|
|
94
|
-
.sort()
|
|
95
|
-
.join('\n');
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
generalInstructions,
|
|
99
|
-
taskType: `${nextTask.operation} route`,
|
|
100
|
-
route: `${nextTask.routeMethod} ${nextTask.routePath}`,
|
|
101
|
-
routeObject: nextTask.routeObjectName ?? undefined,
|
|
102
|
-
pathChangedFrom:
|
|
103
|
-
nextTask.initialRoutePath && nextTask.initialRoutePath !== nextTask.routePath ? nextTask.initialRoutePath : undefined,
|
|
104
|
-
methodChangedFrom:
|
|
105
|
-
nextTask.initialRouteMethod && nextTask.initialRouteMethod !== nextTask.routeMethod
|
|
106
|
-
? nextTask.initialRouteMethod
|
|
107
|
-
: undefined,
|
|
108
|
-
objectChangedFrom:
|
|
109
|
-
nextTask.initialRouteObjectName && nextTask.initialRouteObjectName !== nextTask.routeObjectName
|
|
110
|
-
? nextTask.initialRouteObjectName
|
|
111
|
-
: undefined,
|
|
112
|
-
permissionChangedFrom:
|
|
113
|
-
nextTask.initialRoutePermission && nextTask.initialRoutePermission !== nextTask.routePermission
|
|
114
|
-
? nextTask.initialRoutePermission
|
|
115
|
-
: undefined,
|
|
116
|
-
queryParamChanges: queryParamChanges || 'No change on query params',
|
|
117
|
-
taskDescription: nextTask.description ?? undefined,
|
|
118
|
-
implementationGuidelines,
|
|
119
|
-
unitTests,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
if (nextTask instanceof ProjectStorySectionModelRelationChange) {
|
|
123
|
-
const relations = nextTask.relations
|
|
124
|
-
.filter((r) => !!r.operation)
|
|
125
|
-
.map((r) => `${r.operation} [${r.objects.map((o) => o.objectName).join(' ⇒ ')}]`)
|
|
126
|
-
.sort()
|
|
127
|
-
.join('\n');
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
generalInstructions,
|
|
131
|
-
taskType: 'relation change',
|
|
132
|
-
handlerName: nextTask.handlerName,
|
|
133
|
-
boundedContext: nextTask.boundedContext,
|
|
134
|
-
subscriptionName: nextTask.subscriptionName ?? undefined,
|
|
135
|
-
relations: relations || 'No relation changes',
|
|
136
|
-
taskDescription: nextTask.description ?? undefined,
|
|
137
|
-
implementationGuidelines,
|
|
138
|
-
unitTests,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
if (nextTask instanceof ProjectStorySectionModelTask) {
|
|
142
|
-
return {
|
|
143
|
-
generalInstructions,
|
|
144
|
-
taskType: nextTask.taskTypeName,
|
|
145
|
-
taskDescription: nextTask.description ?? undefined,
|
|
146
|
-
implementationGuidelines,
|
|
147
|
-
unitTests,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
18
|
+
return renderTemplate('get-next-task', {
|
|
19
|
+
taskDetails: stringifyAnalysisDslChange(analysisChange),
|
|
20
|
+
guidelinesPath,
|
|
21
|
+
unitTestsPath: developmentPolicy?.areUnitTestsMandatory ? unitTestsPath : null,
|
|
22
|
+
isTodo,
|
|
23
|
+
identificationNumber,
|
|
24
|
+
taskId: analysisChange.id,
|
|
25
|
+
});
|
|
150
26
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: develop-story
|
|
3
|
+
description: >
|
|
4
|
+
Develop a we-scrum user story by iterating through its tasks one by one.
|
|
5
|
+
Use this skill whenever the user says "develop story XXXXX", "/develop-story XXXXX",
|
|
6
|
+
or asks to implement or work on a specific story number. The skill synchronizes
|
|
7
|
+
development policies, then fetches and implements each task in sequence using
|
|
8
|
+
the we-scrum MCP server and CLI.
|
|
9
|
+
compatibility: "Requires: we-scrum MCP server, we-scrum CLI (we-scrum)"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Develop Story Skill
|
|
13
|
+
|
|
14
|
+
Iterates through a we-scrum story's tasks, implementing each one in sequence until
|
|
15
|
+
all tasks are complete.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Step 0 — Resolve the story identification number
|
|
20
|
+
|
|
21
|
+
If the user provided a story identification number (e.g. `/develop-story 00240`), use it.
|
|
22
|
+
Otherwise, ask: _"Which story would you like to develop? Please provide the identification number."_
|
|
23
|
+
Do not proceed until a number is provided.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Step 1 — Synchronize development policies
|
|
28
|
+
|
|
29
|
+
Pull the latest development guidelines into the project before starting any work:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
we-scrum synchronize-development-policies
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Step 2 — Fetch and implement tasks
|
|
38
|
+
|
|
39
|
+
Call the `get_next_task` MCP tool with the story identification number and follow
|
|
40
|
+
the instructions it returns. Repeat until all tasks are complete.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{{{taskDetails}}}
|
|
2
|
+
|
|
3
|
+
## Development guidelines
|
|
4
|
+
{{#if guidelinesPath}}Refer to `{{{guidelinesPath}}}` for coding conventions and project-specific instructions.{{else}}_No development guidelines file configured for this task._{{/if}}
|
|
5
|
+
|
|
6
|
+
## Unit tests
|
|
7
|
+
{{#if unitTestsPath}}Unit tests are required. Refer to `{{{unitTestsPath}}}` for test writing guidelines.{{else}}No unit tests required.{{/if}}
|
|
8
|
+
|
|
9
|
+
## Next steps
|
|
10
|
+
{{#if isTodo}}
|
|
11
|
+
1. Run `we-scrum start-task --identificationNumber "{{identificationNumber}}" --taskId "{{taskId}}"` before making any changes.
|
|
12
|
+
2. Implement the task described above.
|
|
13
|
+
3. Commit your changes.
|
|
14
|
+
4. Run `we-scrum complete-task --identificationNumber "{{identificationNumber}}" --taskId "{{taskId}}"` when done.
|
|
15
|
+
5. Call `get_next_task` to continue with the next task.
|
|
16
|
+
{{else}}
|
|
17
|
+
1. Implement the task described above.
|
|
18
|
+
2. Commit your changes.
|
|
19
|
+
3. Run `we-scrum complete-task --identificationNumber "{{identificationNumber}}" --taskId "{{taskId}}"` when done.
|
|
20
|
+
4. Call `get_next_task` to continue with the next task.
|
|
21
|
+
{{/if}}
|
package/tsconfig.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { WeScrumHelper } from '@helpers';
|
|
2
|
-
|
|
3
|
-
export async function getUnitTestGuidelines(identificationNumber: string): Promise<Record<string, string>> {
|
|
4
|
-
const nextTask = await WeScrumHelper.getNextChange(identificationNumber);
|
|
5
|
-
|
|
6
|
-
if (!nextTask) {
|
|
7
|
-
return { message: `All tasks for story "${identificationNumber}" are complete.` };
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const developmentPolicy = await WeScrumHelper.getChangeDevelopmentPolicy(nextTask);
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
unitTestGuidelines: developmentPolicy?.unitTestsGuidelines ?? 'No unit test guidelines found for this task.',
|
|
14
|
-
};
|
|
15
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { WeScrumHelper } from '@helpers';
|
|
2
|
-
|
|
3
|
-
export async function startTask(identificationNumber: string): Promise<Record<string, string>> {
|
|
4
|
-
await WeScrumHelper.startTask(identificationNumber);
|
|
5
|
-
return { message: 'Task started successfully. You can now make changes to the codebase.' };
|
|
6
|
-
}
|