@lumpcode/recipes 0.0.14 → 0.0.16
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/README.md +15 -9
- package/dist/index.cjs +39 -39
- package/dist/index.d.ts +3 -3
- package/dist/index.js +39 -39
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,32 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
Lumpcode **recipes** and **kit** helpers for authoring lump configs without boilerplate.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Install [`@lumpcode/cli`](https://www.npmjs.com/package/@lumpcode/cli) for the Lumpcode CLI. Add this package when you want the recipes and kit helpers. Built on [`@lumpcode/cli-utils`](https://www.npmjs.com/package/@lumpcode/cli-utils) and [`@lumpcode/core`](https://www.npmjs.com/package/@lumpcode/core).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @lumpcode/recipes
|
|
11
|
+
```
|
|
6
12
|
|
|
7
13
|
## Recipes
|
|
8
14
|
|
|
9
15
|
| Recipe | Export | Use when |
|
|
10
16
|
|--------|--------|----------|
|
|
11
17
|
| **backlog** | `backlog` | Generic folder backlog with a typed stage map and per-item stage resolution |
|
|
12
|
-
| **featureBacklog** | `featureBacklog` | Feature items with
|
|
13
|
-
| **abstractionFinder** | `abstractionFinder` | Ephemeral contexts that scan for duplicated CLI utils and append one backlog item +
|
|
14
|
-
| **abstractionBacklog** | `abstractionBacklog` | Folder backlog items with
|
|
18
|
+
| **featureBacklog** | `featureBacklog` | Feature items with requirements → test plan → test implementation → implementation |
|
|
19
|
+
| **abstractionFinder** | `abstractionFinder` | Ephemeral contexts that scan for duplicated CLI utils and append one backlog item + requirements doc per run |
|
|
20
|
+
| **abstractionBacklog** | `abstractionBacklog` | Folder backlog items with requirements — implement abstraction with verify-until-green, then move item to completed/ |
|
|
15
21
|
|
|
16
22
|
## Backlog layout
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
The backlog recipes (`backlog`, `featureBacklog`, `abstractionBacklog`) use a folder backlog under `backlogItems/`:
|
|
19
25
|
|
|
20
26
|
```
|
|
21
27
|
.lumpcode/lumps/<lump>/backlogItems/
|
|
22
28
|
todo/<name>/desc.yml
|
|
23
|
-
todo/<name>/
|
|
29
|
+
todo/<name>/requirements.md # optional until makeReq / finder writes it
|
|
24
30
|
todo/<name>/testPlan.md # featureBacklog only; optional until makeTestPlan
|
|
25
31
|
completed/<name>/desc.yml # includes completedAt after move-to-done
|
|
26
|
-
completed/<name>/
|
|
32
|
+
completed/<name>/requirements.md # moves with the folder
|
|
27
33
|
completed/<name>/testPlan.md
|
|
28
34
|
```
|
|
29
35
|
|
|
30
|
-
`desc.yml` is a single YAML object with `name`, `task`, `priority`, optional `dependsOn`, and recipe-specific fields (e.g. `
|
|
36
|
+
`desc.yml` is a single YAML object with `name`, `task`, `priority`, optional `dependsOn`, and recipe-specific fields (e.g. `manualReq` for featureBacklog).
|
|
31
37
|
|
|
32
38
|
## Kit
|
|
33
39
|
|
|
@@ -98,7 +104,7 @@ export default {
|
|
|
98
104
|
|
|
99
105
|
### abstractionFinder + abstractionBacklog
|
|
100
106
|
|
|
101
|
-
Two-lump pipeline: finder tops up the implementer backlog; implementer runs items that already have
|
|
107
|
+
Two-lump pipeline: finder tops up the implementer backlog; implementer runs items that already have requirements documents.
|
|
102
108
|
|
|
103
109
|
```ts
|
|
104
110
|
// .lumpcode/lumps/abstractionFinder/config.ts
|
package/dist/index.cjs
CHANGED
|
@@ -578,15 +578,15 @@ const abstractionBacklog = defineRecipe((options) => {
|
|
|
578
578
|
return backlog({
|
|
579
579
|
configUrl,
|
|
580
580
|
async resolveItem({ item, paths }) {
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
if (!
|
|
581
|
+
const itemReqPath = path$1.join(paths.backlogItemsDir, 'todo', item.name, 'requirements.md');
|
|
582
|
+
const hasReq = await core.pathExists(path$1.join(projectRoot, itemReqPath));
|
|
583
|
+
if (!hasReq) {
|
|
584
584
|
return { ignored: true };
|
|
585
585
|
}
|
|
586
586
|
return {
|
|
587
587
|
stage: 'implementation',
|
|
588
588
|
variables: {
|
|
589
|
-
|
|
589
|
+
REQ_FILE: itemReqPath,
|
|
590
590
|
},
|
|
591
591
|
};
|
|
592
592
|
},
|
|
@@ -597,9 +597,9 @@ const abstractionBacklog = defineRecipe((options) => {
|
|
|
597
597
|
steps: implSteps ?? [{
|
|
598
598
|
promptFn({ context: ctx }) {
|
|
599
599
|
const vars = ctx.variables;
|
|
600
|
-
const {
|
|
600
|
+
const { REQ_FILE, TASK_NAME, TASK } = vars;
|
|
601
601
|
return `
|
|
602
|
-
Implement the abstraction described in @${
|
|
602
|
+
Implement the abstraction described in @${REQ_FILE}.
|
|
603
603
|
|
|
604
604
|
Backlog item: ${TASK_NAME}
|
|
605
605
|
Task summary:
|
|
@@ -651,19 +651,19 @@ Create exactly one new backlog item folder at @${backlogItemsDir}/todo/<utilName
|
|
|
651
651
|
- task: a concise summary of the repeated pattern, proposed util name, and affected areas
|
|
652
652
|
- priority: max existing priority in todo/ plus 1 (or 1 if todo/ is empty)
|
|
653
653
|
- dependsOn: optional list of util names from todo/ or completed/ that must land first (only when clearly needed)
|
|
654
|
-
-
|
|
654
|
+
- requirements.md: an implementation-ready requirements document for the same util name. It should be self-contained and include:
|
|
655
655
|
- Problem statement and repeated pattern
|
|
656
656
|
- Goals and non-goals
|
|
657
657
|
- Proposed util API and affected files
|
|
658
658
|
- Acceptance criteria (including net line reduction and unit tests)
|
|
659
659
|
|
|
660
|
-
Do not implement code. Only create @${backlogItemsDir}/todo/<utilName>/desc.yml and @${backlogItemsDir}/todo/<utilName>/
|
|
660
|
+
Do not implement code. Only create @${backlogItemsDir}/todo/<utilName>/desc.yml and @${backlogItemsDir}/todo/<utilName>/requirements.md.
|
|
661
661
|
|
|
662
662
|
Do not take too much time looking for every possible abstraction. Once you found a good abstraction, stop and create the backlog item.
|
|
663
663
|
`.trim();
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
-
const RESERVED_NAME_SUFFIXES = ['
|
|
666
|
+
const RESERVED_NAME_SUFFIXES = ['_req', '_testPlan', '_tests_impl'];
|
|
667
667
|
function assertValidFeatureItemName(name) {
|
|
668
668
|
for (const suffix of RESERVED_NAME_SUFFIXES) {
|
|
669
669
|
if (name.endsWith(suffix)) {
|
|
@@ -673,8 +673,8 @@ function assertValidFeatureItemName(name) {
|
|
|
673
673
|
}
|
|
674
674
|
function featureContextName(itemName, stage) {
|
|
675
675
|
switch (stage) {
|
|
676
|
-
case '
|
|
677
|
-
return `${itemName}
|
|
676
|
+
case 'makeReq':
|
|
677
|
+
return `${itemName}_req`;
|
|
678
678
|
case 'makeTestPlan':
|
|
679
679
|
return `${itemName}_testPlan`;
|
|
680
680
|
case 'testImpl':
|
|
@@ -688,17 +688,17 @@ function featureContextName(itemName, stage) {
|
|
|
688
688
|
}
|
|
689
689
|
}
|
|
690
690
|
async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, baseBranch) {
|
|
691
|
-
const
|
|
691
|
+
const reqFilePath = path$1.join(paths.backlogItemsDir, 'todo', item.name, 'requirements.md');
|
|
692
692
|
const testPlanFilePath = path$1.join(paths.backlogItemsDir, 'todo', item.name, 'testPlan.md');
|
|
693
|
-
const
|
|
694
|
-
if (!
|
|
695
|
-
if (item.
|
|
693
|
+
const hasReq = await core.pathExists(path$1.join(projectRoot, reqFilePath));
|
|
694
|
+
if (!hasReq) {
|
|
695
|
+
if (item.manualReq === true) {
|
|
696
696
|
return { ignored: true };
|
|
697
697
|
}
|
|
698
698
|
return {
|
|
699
|
-
stage: '
|
|
700
|
-
contextName: featureContextName(item.name, '
|
|
701
|
-
variables: {
|
|
699
|
+
stage: 'makeReq',
|
|
700
|
+
contextName: featureContextName(item.name, 'makeReq'),
|
|
701
|
+
variables: { REQ_FILE: reqFilePath },
|
|
702
702
|
};
|
|
703
703
|
}
|
|
704
704
|
const hasTestPlan = await core.pathExists(path$1.join(projectRoot, testPlanFilePath));
|
|
@@ -707,7 +707,7 @@ async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, bas
|
|
|
707
707
|
stage: 'makeTestPlan',
|
|
708
708
|
contextName: featureContextName(item.name, 'makeTestPlan'),
|
|
709
709
|
variables: {
|
|
710
|
-
|
|
710
|
+
REQ_FILE: reqFilePath,
|
|
711
711
|
TEST_PLAN_FILE: testPlanFilePath,
|
|
712
712
|
},
|
|
713
713
|
};
|
|
@@ -724,7 +724,7 @@ async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, bas
|
|
|
724
724
|
stage: 'implementation',
|
|
725
725
|
contextName: featureContextName(item.name, 'implementation'),
|
|
726
726
|
variables: {
|
|
727
|
-
|
|
727
|
+
REQ_FILE: reqFilePath,
|
|
728
728
|
TEST_PLAN_FILE: testPlanFilePath,
|
|
729
729
|
},
|
|
730
730
|
};
|
|
@@ -736,7 +736,7 @@ async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, bas
|
|
|
736
736
|
stage: 'testImpl',
|
|
737
737
|
contextName: testsImplContextName,
|
|
738
738
|
variables: {
|
|
739
|
-
|
|
739
|
+
REQ_FILE: reqFilePath,
|
|
740
740
|
TEST_PLAN_FILE: testPlanFilePath,
|
|
741
741
|
},
|
|
742
742
|
};
|
|
@@ -752,36 +752,36 @@ const featureBacklog = defineRecipe((options) => {
|
|
|
752
752
|
parseItem(baseItem, _folderName, raw) {
|
|
753
753
|
assertValidFeatureItemName(baseItem.name);
|
|
754
754
|
const record = raw;
|
|
755
|
-
if (record.
|
|
756
|
-
throw new Error(`Backlog item "${baseItem.name}" field "
|
|
755
|
+
if (record.manualReq !== undefined && typeof record.manualReq !== 'boolean') {
|
|
756
|
+
throw new Error(`Backlog item "${baseItem.name}" field "manualReq" must be a boolean`);
|
|
757
757
|
}
|
|
758
758
|
return {
|
|
759
759
|
...baseItem,
|
|
760
|
-
|
|
760
|
+
manualReq: record.manualReq === true ? true : undefined,
|
|
761
761
|
};
|
|
762
762
|
},
|
|
763
763
|
async resolveItem({ item, paths }) {
|
|
764
764
|
return resolveFeatureBacklogItem(item, paths, projectRoot, paths.lumpName, baseBranch);
|
|
765
765
|
},
|
|
766
766
|
stages: {
|
|
767
|
-
|
|
767
|
+
makeReq: {
|
|
768
768
|
completion: 'keepPending',
|
|
769
769
|
steps: [
|
|
770
770
|
{
|
|
771
771
|
promptFn({ context: ctx }) {
|
|
772
772
|
const vars = ctx.variables;
|
|
773
|
-
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK,
|
|
773
|
+
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK, REQ_FILE } = vars;
|
|
774
774
|
return `
|
|
775
|
-
Write a
|
|
775
|
+
Write a requirements document for the following backlog item from @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
776
776
|
|
|
777
777
|
Task name: ${TASK_NAME}
|
|
778
778
|
|
|
779
779
|
Task:
|
|
780
780
|
${TASK}
|
|
781
781
|
|
|
782
|
-
Save the
|
|
782
|
+
Save the requirements document to @${REQ_FILE}. Do not edit @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
783
783
|
|
|
784
|
-
The
|
|
784
|
+
The requirements document should be self-contained and implementation-ready. Include:
|
|
785
785
|
- Problem statement and motivation
|
|
786
786
|
- Goals and non-goals
|
|
787
787
|
- User stories / use cases
|
|
@@ -790,12 +790,12 @@ The PRD should be self-contained and implementation-ready. Include:
|
|
|
790
790
|
- Technical approach and affected packages or docs
|
|
791
791
|
- Acceptance criteria
|
|
792
792
|
|
|
793
|
-
Do not implement the feature — only create the
|
|
794
|
-
The
|
|
793
|
+
Do not implement the feature — only create the requirements markdown file.
|
|
794
|
+
The requirements document should not contain any testing strategy details.
|
|
795
795
|
`.trim();
|
|
796
796
|
},
|
|
797
797
|
},
|
|
798
|
-
requireArtifactStep('
|
|
798
|
+
requireArtifactStep('REQ_FILE'),
|
|
799
799
|
],
|
|
800
800
|
},
|
|
801
801
|
makeTestPlan: {
|
|
@@ -804,7 +804,7 @@ The PRD should not contain any testing strategy details.
|
|
|
804
804
|
{
|
|
805
805
|
promptFn({ context: ctx }) {
|
|
806
806
|
const vars = ctx.variables;
|
|
807
|
-
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK,
|
|
807
|
+
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK, REQ_FILE, TEST_PLAN_FILE } = vars;
|
|
808
808
|
return `
|
|
809
809
|
Write a test plan for the following backlog item from @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
810
810
|
|
|
@@ -812,9 +812,9 @@ Task name: ${TASK_NAME}
|
|
|
812
812
|
Task:
|
|
813
813
|
${TASK}
|
|
814
814
|
|
|
815
|
-
The
|
|
815
|
+
The requirements for this task are in @${REQ_FILE}. The test plan should match those requirements.
|
|
816
816
|
|
|
817
|
-
Save the test plan to @${TEST_PLAN_FILE}. Do not edit @${BACKLOG_ITEM_DIR}/desc.yml nor @${
|
|
817
|
+
Save the test plan to @${TEST_PLAN_FILE}. Do not edit @${BACKLOG_ITEM_DIR}/desc.yml nor @${REQ_FILE}.
|
|
818
818
|
|
|
819
819
|
The test plan should be self-contained and implementation-ready. Include:
|
|
820
820
|
- Test cases
|
|
@@ -833,7 +833,7 @@ The test plan should be self-contained and implementation-ready. Include:
|
|
|
833
833
|
{
|
|
834
834
|
promptFn({ context: ctx }) {
|
|
835
835
|
const vars = ctx.variables;
|
|
836
|
-
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK,
|
|
836
|
+
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK, REQ_FILE, TEST_PLAN_FILE } = vars;
|
|
837
837
|
return `
|
|
838
838
|
Write a test implementation for the following backlog item from @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
839
839
|
|
|
@@ -842,7 +842,7 @@ Task:
|
|
|
842
842
|
${TASK}
|
|
843
843
|
|
|
844
844
|
Follow the test plan in @${TEST_PLAN_FILE}.
|
|
845
|
-
The
|
|
845
|
+
The requirements for this task are in @${REQ_FILE}.
|
|
846
846
|
`.trim();
|
|
847
847
|
},
|
|
848
848
|
},
|
|
@@ -855,9 +855,9 @@ The PRD for this task is @${PRD_FILE}.
|
|
|
855
855
|
{
|
|
856
856
|
promptFn({ context: ctx }) {
|
|
857
857
|
const vars = ctx.variables;
|
|
858
|
-
const {
|
|
858
|
+
const { REQ_FILE, TEST_PLAN_FILE } = vars;
|
|
859
859
|
return `
|
|
860
|
-
Implement the feature described in @${
|
|
860
|
+
Implement the feature described in @${REQ_FILE}.
|
|
861
861
|
The tests have already been implemented according to the test plan in @${TEST_PLAN_FILE}.
|
|
862
862
|
The implementation should make the tests pass. Do not edit any test file.
|
|
863
863
|
`.trim();
|
package/dist/index.d.ts
CHANGED
|
@@ -179,16 +179,16 @@ declare function backlog<Item extends BaseBacklogItem, Stages extends Record<str
|
|
|
179
179
|
declare const backlogRecipe: Recipe<BacklogOptions<BaseBacklogItem, Record<string, BacklogStageDefinition>>>;
|
|
180
180
|
|
|
181
181
|
type FeatureBacklogItem = BaseBacklogItem & {
|
|
182
|
-
|
|
182
|
+
manualReq?: boolean;
|
|
183
183
|
};
|
|
184
|
-
type FeatureBacklogStage = '
|
|
184
|
+
type FeatureBacklogStage = 'makeReq' | 'makeTestPlan' | 'testImpl' | 'implementation';
|
|
185
185
|
type FeatureBacklogContextVariables = {
|
|
186
186
|
TASK_NAME: string;
|
|
187
187
|
TASK: string;
|
|
188
188
|
BACKLOG_ITEMS_DIR: string;
|
|
189
189
|
BACKLOG_ITEM_DIR: string;
|
|
190
190
|
BACKLOG_STAGE: FeatureBacklogStage;
|
|
191
|
-
|
|
191
|
+
REQ_FILE?: string;
|
|
192
192
|
TEST_PLAN_FILE?: string;
|
|
193
193
|
};
|
|
194
194
|
type FeatureBacklogOptions = {
|
package/dist/index.js
CHANGED
|
@@ -576,15 +576,15 @@ const abstractionBacklog = defineRecipe((options) => {
|
|
|
576
576
|
return backlog({
|
|
577
577
|
configUrl,
|
|
578
578
|
async resolveItem({ item, paths }) {
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
if (!
|
|
579
|
+
const itemReqPath = path$1.join(paths.backlogItemsDir, 'todo', item.name, 'requirements.md');
|
|
580
|
+
const hasReq = await pathExists(path$1.join(projectRoot, itemReqPath));
|
|
581
|
+
if (!hasReq) {
|
|
582
582
|
return { ignored: true };
|
|
583
583
|
}
|
|
584
584
|
return {
|
|
585
585
|
stage: 'implementation',
|
|
586
586
|
variables: {
|
|
587
|
-
|
|
587
|
+
REQ_FILE: itemReqPath,
|
|
588
588
|
},
|
|
589
589
|
};
|
|
590
590
|
},
|
|
@@ -595,9 +595,9 @@ const abstractionBacklog = defineRecipe((options) => {
|
|
|
595
595
|
steps: implSteps ?? [{
|
|
596
596
|
promptFn({ context: ctx }) {
|
|
597
597
|
const vars = ctx.variables;
|
|
598
|
-
const {
|
|
598
|
+
const { REQ_FILE, TASK_NAME, TASK } = vars;
|
|
599
599
|
return `
|
|
600
|
-
Implement the abstraction described in @${
|
|
600
|
+
Implement the abstraction described in @${REQ_FILE}.
|
|
601
601
|
|
|
602
602
|
Backlog item: ${TASK_NAME}
|
|
603
603
|
Task summary:
|
|
@@ -649,19 +649,19 @@ Create exactly one new backlog item folder at @${backlogItemsDir}/todo/<utilName
|
|
|
649
649
|
- task: a concise summary of the repeated pattern, proposed util name, and affected areas
|
|
650
650
|
- priority: max existing priority in todo/ plus 1 (or 1 if todo/ is empty)
|
|
651
651
|
- dependsOn: optional list of util names from todo/ or completed/ that must land first (only when clearly needed)
|
|
652
|
-
-
|
|
652
|
+
- requirements.md: an implementation-ready requirements document for the same util name. It should be self-contained and include:
|
|
653
653
|
- Problem statement and repeated pattern
|
|
654
654
|
- Goals and non-goals
|
|
655
655
|
- Proposed util API and affected files
|
|
656
656
|
- Acceptance criteria (including net line reduction and unit tests)
|
|
657
657
|
|
|
658
|
-
Do not implement code. Only create @${backlogItemsDir}/todo/<utilName>/desc.yml and @${backlogItemsDir}/todo/<utilName>/
|
|
658
|
+
Do not implement code. Only create @${backlogItemsDir}/todo/<utilName>/desc.yml and @${backlogItemsDir}/todo/<utilName>/requirements.md.
|
|
659
659
|
|
|
660
660
|
Do not take too much time looking for every possible abstraction. Once you found a good abstraction, stop and create the backlog item.
|
|
661
661
|
`.trim();
|
|
662
662
|
}
|
|
663
663
|
|
|
664
|
-
const RESERVED_NAME_SUFFIXES = ['
|
|
664
|
+
const RESERVED_NAME_SUFFIXES = ['_req', '_testPlan', '_tests_impl'];
|
|
665
665
|
function assertValidFeatureItemName(name) {
|
|
666
666
|
for (const suffix of RESERVED_NAME_SUFFIXES) {
|
|
667
667
|
if (name.endsWith(suffix)) {
|
|
@@ -671,8 +671,8 @@ function assertValidFeatureItemName(name) {
|
|
|
671
671
|
}
|
|
672
672
|
function featureContextName(itemName, stage) {
|
|
673
673
|
switch (stage) {
|
|
674
|
-
case '
|
|
675
|
-
return `${itemName}
|
|
674
|
+
case 'makeReq':
|
|
675
|
+
return `${itemName}_req`;
|
|
676
676
|
case 'makeTestPlan':
|
|
677
677
|
return `${itemName}_testPlan`;
|
|
678
678
|
case 'testImpl':
|
|
@@ -686,17 +686,17 @@ function featureContextName(itemName, stage) {
|
|
|
686
686
|
}
|
|
687
687
|
}
|
|
688
688
|
async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, baseBranch) {
|
|
689
|
-
const
|
|
689
|
+
const reqFilePath = path$1.join(paths.backlogItemsDir, 'todo', item.name, 'requirements.md');
|
|
690
690
|
const testPlanFilePath = path$1.join(paths.backlogItemsDir, 'todo', item.name, 'testPlan.md');
|
|
691
|
-
const
|
|
692
|
-
if (!
|
|
693
|
-
if (item.
|
|
691
|
+
const hasReq = await pathExists(path$1.join(projectRoot, reqFilePath));
|
|
692
|
+
if (!hasReq) {
|
|
693
|
+
if (item.manualReq === true) {
|
|
694
694
|
return { ignored: true };
|
|
695
695
|
}
|
|
696
696
|
return {
|
|
697
|
-
stage: '
|
|
698
|
-
contextName: featureContextName(item.name, '
|
|
699
|
-
variables: {
|
|
697
|
+
stage: 'makeReq',
|
|
698
|
+
contextName: featureContextName(item.name, 'makeReq'),
|
|
699
|
+
variables: { REQ_FILE: reqFilePath },
|
|
700
700
|
};
|
|
701
701
|
}
|
|
702
702
|
const hasTestPlan = await pathExists(path$1.join(projectRoot, testPlanFilePath));
|
|
@@ -705,7 +705,7 @@ async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, bas
|
|
|
705
705
|
stage: 'makeTestPlan',
|
|
706
706
|
contextName: featureContextName(item.name, 'makeTestPlan'),
|
|
707
707
|
variables: {
|
|
708
|
-
|
|
708
|
+
REQ_FILE: reqFilePath,
|
|
709
709
|
TEST_PLAN_FILE: testPlanFilePath,
|
|
710
710
|
},
|
|
711
711
|
};
|
|
@@ -722,7 +722,7 @@ async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, bas
|
|
|
722
722
|
stage: 'implementation',
|
|
723
723
|
contextName: featureContextName(item.name, 'implementation'),
|
|
724
724
|
variables: {
|
|
725
|
-
|
|
725
|
+
REQ_FILE: reqFilePath,
|
|
726
726
|
TEST_PLAN_FILE: testPlanFilePath,
|
|
727
727
|
},
|
|
728
728
|
};
|
|
@@ -734,7 +734,7 @@ async function resolveFeatureBacklogItem(item, paths, projectRoot, lumpName, bas
|
|
|
734
734
|
stage: 'testImpl',
|
|
735
735
|
contextName: testsImplContextName,
|
|
736
736
|
variables: {
|
|
737
|
-
|
|
737
|
+
REQ_FILE: reqFilePath,
|
|
738
738
|
TEST_PLAN_FILE: testPlanFilePath,
|
|
739
739
|
},
|
|
740
740
|
};
|
|
@@ -750,36 +750,36 @@ const featureBacklog = defineRecipe((options) => {
|
|
|
750
750
|
parseItem(baseItem, _folderName, raw) {
|
|
751
751
|
assertValidFeatureItemName(baseItem.name);
|
|
752
752
|
const record = raw;
|
|
753
|
-
if (record.
|
|
754
|
-
throw new Error(`Backlog item "${baseItem.name}" field "
|
|
753
|
+
if (record.manualReq !== undefined && typeof record.manualReq !== 'boolean') {
|
|
754
|
+
throw new Error(`Backlog item "${baseItem.name}" field "manualReq" must be a boolean`);
|
|
755
755
|
}
|
|
756
756
|
return {
|
|
757
757
|
...baseItem,
|
|
758
|
-
|
|
758
|
+
manualReq: record.manualReq === true ? true : undefined,
|
|
759
759
|
};
|
|
760
760
|
},
|
|
761
761
|
async resolveItem({ item, paths }) {
|
|
762
762
|
return resolveFeatureBacklogItem(item, paths, projectRoot, paths.lumpName, baseBranch);
|
|
763
763
|
},
|
|
764
764
|
stages: {
|
|
765
|
-
|
|
765
|
+
makeReq: {
|
|
766
766
|
completion: 'keepPending',
|
|
767
767
|
steps: [
|
|
768
768
|
{
|
|
769
769
|
promptFn({ context: ctx }) {
|
|
770
770
|
const vars = ctx.variables;
|
|
771
|
-
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK,
|
|
771
|
+
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK, REQ_FILE } = vars;
|
|
772
772
|
return `
|
|
773
|
-
Write a
|
|
773
|
+
Write a requirements document for the following backlog item from @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
774
774
|
|
|
775
775
|
Task name: ${TASK_NAME}
|
|
776
776
|
|
|
777
777
|
Task:
|
|
778
778
|
${TASK}
|
|
779
779
|
|
|
780
|
-
Save the
|
|
780
|
+
Save the requirements document to @${REQ_FILE}. Do not edit @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
781
781
|
|
|
782
|
-
The
|
|
782
|
+
The requirements document should be self-contained and implementation-ready. Include:
|
|
783
783
|
- Problem statement and motivation
|
|
784
784
|
- Goals and non-goals
|
|
785
785
|
- User stories / use cases
|
|
@@ -788,12 +788,12 @@ The PRD should be self-contained and implementation-ready. Include:
|
|
|
788
788
|
- Technical approach and affected packages or docs
|
|
789
789
|
- Acceptance criteria
|
|
790
790
|
|
|
791
|
-
Do not implement the feature — only create the
|
|
792
|
-
The
|
|
791
|
+
Do not implement the feature — only create the requirements markdown file.
|
|
792
|
+
The requirements document should not contain any testing strategy details.
|
|
793
793
|
`.trim();
|
|
794
794
|
},
|
|
795
795
|
},
|
|
796
|
-
requireArtifactStep('
|
|
796
|
+
requireArtifactStep('REQ_FILE'),
|
|
797
797
|
],
|
|
798
798
|
},
|
|
799
799
|
makeTestPlan: {
|
|
@@ -802,7 +802,7 @@ The PRD should not contain any testing strategy details.
|
|
|
802
802
|
{
|
|
803
803
|
promptFn({ context: ctx }) {
|
|
804
804
|
const vars = ctx.variables;
|
|
805
|
-
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK,
|
|
805
|
+
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK, REQ_FILE, TEST_PLAN_FILE } = vars;
|
|
806
806
|
return `
|
|
807
807
|
Write a test plan for the following backlog item from @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
808
808
|
|
|
@@ -810,9 +810,9 @@ Task name: ${TASK_NAME}
|
|
|
810
810
|
Task:
|
|
811
811
|
${TASK}
|
|
812
812
|
|
|
813
|
-
The
|
|
813
|
+
The requirements for this task are in @${REQ_FILE}. The test plan should match those requirements.
|
|
814
814
|
|
|
815
|
-
Save the test plan to @${TEST_PLAN_FILE}. Do not edit @${BACKLOG_ITEM_DIR}/desc.yml nor @${
|
|
815
|
+
Save the test plan to @${TEST_PLAN_FILE}. Do not edit @${BACKLOG_ITEM_DIR}/desc.yml nor @${REQ_FILE}.
|
|
816
816
|
|
|
817
817
|
The test plan should be self-contained and implementation-ready. Include:
|
|
818
818
|
- Test cases
|
|
@@ -831,7 +831,7 @@ The test plan should be self-contained and implementation-ready. Include:
|
|
|
831
831
|
{
|
|
832
832
|
promptFn({ context: ctx }) {
|
|
833
833
|
const vars = ctx.variables;
|
|
834
|
-
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK,
|
|
834
|
+
const { BACKLOG_ITEM_DIR, TASK_NAME, TASK, REQ_FILE, TEST_PLAN_FILE } = vars;
|
|
835
835
|
return `
|
|
836
836
|
Write a test implementation for the following backlog item from @${BACKLOG_ITEM_DIR}/desc.yml.
|
|
837
837
|
|
|
@@ -840,7 +840,7 @@ Task:
|
|
|
840
840
|
${TASK}
|
|
841
841
|
|
|
842
842
|
Follow the test plan in @${TEST_PLAN_FILE}.
|
|
843
|
-
The
|
|
843
|
+
The requirements for this task are in @${REQ_FILE}.
|
|
844
844
|
`.trim();
|
|
845
845
|
},
|
|
846
846
|
},
|
|
@@ -853,9 +853,9 @@ The PRD for this task is @${PRD_FILE}.
|
|
|
853
853
|
{
|
|
854
854
|
promptFn({ context: ctx }) {
|
|
855
855
|
const vars = ctx.variables;
|
|
856
|
-
const {
|
|
856
|
+
const { REQ_FILE, TEST_PLAN_FILE } = vars;
|
|
857
857
|
return `
|
|
858
|
-
Implement the feature described in @${
|
|
858
|
+
Implement the feature described in @${REQ_FILE}.
|
|
859
859
|
The tests have already been implemented according to the test plan in @${TEST_PLAN_FILE}.
|
|
860
860
|
The implementation should make the tests pass. Do not edit any test file.
|
|
861
861
|
`.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumpcode/recipes",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Lumpcode lump recipes and kit helpers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lumpcode",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"test:watch": "vitest watch"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@lumpcode/cli-utils": "^0.0.
|
|
48
|
-
"@lumpcode/core": "^0.0.
|
|
47
|
+
"@lumpcode/cli-utils": "^0.0.13",
|
|
48
|
+
"@lumpcode/core": "^0.0.13",
|
|
49
49
|
"js-yaml": "^5.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|