@programinglive/dev-workflow-mcp-server 1.0.7 โ 1.0.9
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/CHANGELOG.md +14 -0
- package/README.md +24 -6
- package/index.js +382 -381
- package/package.json +1 -1
- package/tests/workflowState.test.js +27 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.0.9](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.8...v1.0.9) (2025-10-23)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ๐ Documentation
|
|
9
|
+
|
|
10
|
+
* explain local workflow state ([cb6e333](https://github.com/programinglive/dev-workflow-mcp-server/commit/cb6e33353b4e1c0f693146f6cb07c9437a7f5aa8))
|
|
11
|
+
|
|
12
|
+
### [1.0.8](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.7...v1.0.8) (2025-10-21)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### โจ Features
|
|
16
|
+
|
|
17
|
+
* allow skipping tests and dropping workflow tasks ([2b8b27c](https://github.com/programinglive/dev-workflow-mcp-server/commit/2b8b27cca611d2fe266c1b814c21b6fec2472856))
|
|
18
|
+
|
|
5
19
|
### [1.0.7](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.6...v1.0.7) (2025-10-20)
|
|
6
20
|
|
|
7
21
|
### [1.0.6](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.5...v1.0.6) (2025-10-20)
|
package/README.md
CHANGED
|
@@ -158,6 +158,12 @@ Confirm that you've created the necessary tests covering your change. Required b
|
|
|
158
158
|
|
|
159
159
|
**Parameters:** _none_
|
|
160
160
|
|
|
161
|
+
### `skip_tests`
|
|
162
|
+
Record an explicit justification when automated tests aren't feasible. Marks testing as satisfied so you can proceed with documentation and verification, while flagging the task for manual QA.
|
|
163
|
+
|
|
164
|
+
**Parameters:**
|
|
165
|
+
- `reason` (string, required): Why automated tests were skipped
|
|
166
|
+
|
|
161
167
|
### `run_tests`
|
|
162
168
|
Record test results. **NEVER commit if tests fail!** Only proceed if all tests are green.
|
|
163
169
|
|
|
@@ -204,6 +210,12 @@ Mark the task as complete after successful commit & push. Resets workflow for ne
|
|
|
204
210
|
**Parameters:**
|
|
205
211
|
- `commitMessage` (string, required): The commit message used
|
|
206
212
|
|
|
213
|
+
### `drop_task`
|
|
214
|
+
Abandon the current task without completing the workflow. Preserves an audit entry with context, then resets the state so you can start fresh.
|
|
215
|
+
|
|
216
|
+
**Parameters:**
|
|
217
|
+
- `reason` (string, optional): Additional detail about why the task was dropped
|
|
218
|
+
|
|
207
219
|
### `get_workflow_status`
|
|
208
220
|
Get current workflow status and what needs to be done next.
|
|
209
221
|
|
|
@@ -249,31 +261,36 @@ Here's how you'd use this MCP server in a typical coding session:
|
|
|
249
261
|
```
|
|
250
262
|
- If tests fail, the server will **block** you from proceeding!
|
|
251
263
|
|
|
252
|
-
|
|
264
|
+
7. **Document:**
|
|
253
265
|
```
|
|
254
266
|
"Create documentation: type=README, summary='Added user profile section to docs'"
|
|
255
267
|
```
|
|
256
268
|
|
|
257
|
-
|
|
269
|
+
8. **Check readiness:**
|
|
258
270
|
```
|
|
259
271
|
"Check if I'm ready to commit"
|
|
260
272
|
```
|
|
261
273
|
|
|
262
|
-
|
|
274
|
+
9. **Commit & Push:**
|
|
263
275
|
```
|
|
264
276
|
"Commit and push: commitMessage='feat: add user profile page with tests and docs'"
|
|
265
277
|
```
|
|
266
278
|
|
|
267
|
-
|
|
279
|
+
10. **Record release:**
|
|
268
280
|
```
|
|
269
281
|
"Record release: command='npm run release', notes='v1.2.3'"
|
|
270
282
|
```
|
|
271
283
|
|
|
272
|
-
|
|
284
|
+
11. **Complete:**
|
|
273
285
|
```
|
|
274
286
|
"Complete the task with commit message: 'feat: add user profile page'"
|
|
275
287
|
```
|
|
276
288
|
|
|
289
|
+
12. **Drop task (optional):**
|
|
290
|
+
```
|
|
291
|
+
"Drop task: reason='Switching to a different feature'"
|
|
292
|
+
```
|
|
293
|
+
|
|
277
294
|
## ๐ฏ Key Features
|
|
278
295
|
|
|
279
296
|
- **Enforces discipline**: Won't let you skip steps
|
|
@@ -294,7 +311,7 @@ Here's how you'd use this MCP server in a typical coding session:
|
|
|
294
311
|
## ๐ก Tips
|
|
295
312
|
|
|
296
313
|
1. **Always start with `start_task`** - This sets your intention
|
|
297
|
-
2. **Never skip tests** -
|
|
314
|
+
2. **Never skip tests without justification** - Use `skip_tests` only when absolutely necessary and document the reason for manual QA
|
|
298
315
|
3. **Use `get_workflow_status`** - Check where you are anytime
|
|
299
316
|
4. **Review history** - Learn from your past tasks
|
|
300
317
|
5. **Follow the prompts** - They contain best practices
|
|
@@ -316,6 +333,7 @@ The server maintains state in `.workflow-state.json`:
|
|
|
316
333
|
- History of completed tasks
|
|
317
334
|
|
|
318
335
|
This file is automatically created and managed by the server.
|
|
336
|
+
It contains local, machine-specific progress and is ignored by git so each environment can manage its own workflow history without cross-contamination.
|
|
319
337
|
|
|
320
338
|
## ๐ค Integration with Your Rules
|
|
321
339
|
|
package/index.js
CHANGED
|
@@ -27,6 +27,8 @@ export class WorkflowState {
|
|
|
27
27
|
bugFixed: false,
|
|
28
28
|
testsCreated: false,
|
|
29
29
|
testsPassed: false,
|
|
30
|
+
testsSkipped: false,
|
|
31
|
+
testsSkippedReason: "",
|
|
30
32
|
documentationCreated: false,
|
|
31
33
|
readyToCommit: false,
|
|
32
34
|
readyCheckCompleted: false,
|
|
@@ -51,6 +53,12 @@ export class WorkflowState {
|
|
|
51
53
|
if (typeof this.state.testsCreated !== "boolean") {
|
|
52
54
|
this.state.testsCreated = false;
|
|
53
55
|
}
|
|
56
|
+
if (typeof this.state.testsSkipped !== "boolean") {
|
|
57
|
+
this.state.testsSkipped = false;
|
|
58
|
+
}
|
|
59
|
+
if (typeof this.state.testsSkippedReason !== "string") {
|
|
60
|
+
this.state.testsSkippedReason = "";
|
|
61
|
+
}
|
|
54
62
|
if (typeof this.state.readyCheckCompleted !== "boolean") {
|
|
55
63
|
this.state.readyCheckCompleted = false;
|
|
56
64
|
}
|
|
@@ -88,6 +96,8 @@ export class WorkflowState {
|
|
|
88
96
|
bugFixed: false,
|
|
89
97
|
testsCreated: false,
|
|
90
98
|
testsPassed: false,
|
|
99
|
+
testsSkipped: false,
|
|
100
|
+
testsSkippedReason: "",
|
|
91
101
|
documentationCreated: false,
|
|
92
102
|
readyToCommit: false,
|
|
93
103
|
readyCheckCompleted: false,
|
|
@@ -529,6 +539,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
529
539
|
properties: {},
|
|
530
540
|
},
|
|
531
541
|
},
|
|
542
|
+
{
|
|
543
|
+
name: "skip_tests",
|
|
544
|
+
description:
|
|
545
|
+
"Record that tests were intentionally skipped, with a justification.",
|
|
546
|
+
inputSchema: {
|
|
547
|
+
type: "object",
|
|
548
|
+
properties: {
|
|
549
|
+
reason: {
|
|
550
|
+
type: "string",
|
|
551
|
+
description: "Why tests cannot be created or executed",
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
required: ["reason"],
|
|
555
|
+
},
|
|
556
|
+
},
|
|
532
557
|
{
|
|
533
558
|
name: "run_tests",
|
|
534
559
|
description:
|
|
@@ -635,6 +660,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
635
660
|
required: ["commitMessage"],
|
|
636
661
|
},
|
|
637
662
|
},
|
|
663
|
+
{
|
|
664
|
+
name: "drop_task",
|
|
665
|
+
description:
|
|
666
|
+
"Abandon the current task and reset the workflow without completing it.",
|
|
667
|
+
inputSchema: {
|
|
668
|
+
type: "object",
|
|
669
|
+
properties: {
|
|
670
|
+
reason: {
|
|
671
|
+
type: "string",
|
|
672
|
+
description: "Optional explanation for dropping the task",
|
|
673
|
+
},
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
},
|
|
638
677
|
{
|
|
639
678
|
name: "get_workflow_status",
|
|
640
679
|
description: "Get current workflow status and what needs to be done next.",
|
|
@@ -685,6 +724,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
685
724
|
workflowState.state.currentPhase = "coding";
|
|
686
725
|
workflowState.state.taskDescription = args.description;
|
|
687
726
|
workflowState.state.taskType = args.type;
|
|
727
|
+
workflowState.state.testsSkipped = false;
|
|
728
|
+
workflowState.state.testsSkippedReason = "";
|
|
688
729
|
workflowState.state.commitAndPushCompleted = false;
|
|
689
730
|
workflowState.state.lastCommitMessage = "";
|
|
690
731
|
workflowState.state.lastPushBranch = "";
|
|
@@ -715,12 +756,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
715
756
|
workflowState.state.bugFixed = true;
|
|
716
757
|
workflowState.state.testsCreated = false;
|
|
717
758
|
workflowState.state.currentPhase = "testing";
|
|
759
|
+
workflowState.state.testsSkipped = false;
|
|
760
|
+
workflowState.state.testsSkippedReason = "";
|
|
718
761
|
workflowState.state.fixSummary = args.summary;
|
|
719
762
|
workflowState.state.readyCheckCompleted = false;
|
|
720
763
|
workflowState.state.released = false;
|
|
721
764
|
workflowState.state.releaseCommand = "";
|
|
722
765
|
workflowState.state.releaseNotes = "";
|
|
723
|
-
workflowState.state.readyToCommit = false;
|
|
724
766
|
workflowState.state.commitAndPushCompleted = false;
|
|
725
767
|
workflowState.state.lastCommitMessage = "";
|
|
726
768
|
workflowState.state.lastPushBranch = "";
|
|
@@ -749,6 +791,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
749
791
|
}
|
|
750
792
|
|
|
751
793
|
workflowState.state.testsCreated = true;
|
|
794
|
+
workflowState.state.testsSkipped = false;
|
|
795
|
+
workflowState.state.testsSkippedReason = "";
|
|
752
796
|
workflowState.state.readyCheckCompleted = false;
|
|
753
797
|
workflowState.state.released = false;
|
|
754
798
|
workflowState.state.commitAndPushCompleted = false;
|
|
@@ -766,6 +810,78 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
766
810
|
};
|
|
767
811
|
}
|
|
768
812
|
|
|
813
|
+
case "skip_tests": {
|
|
814
|
+
if (workflowState.state.currentPhase === "idle") {
|
|
815
|
+
return {
|
|
816
|
+
content: [
|
|
817
|
+
{
|
|
818
|
+
type: "text",
|
|
819
|
+
text: "โ ๏ธ No active task. Use 'start_task' before skipping tests.",
|
|
820
|
+
},
|
|
821
|
+
],
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (!workflowState.state.bugFixed) {
|
|
826
|
+
return {
|
|
827
|
+
content: [
|
|
828
|
+
{
|
|
829
|
+
type: "text",
|
|
830
|
+
text: "โ ๏ธ Please mark your feature/bug as fixed first using 'mark_bug_fixed'!",
|
|
831
|
+
},
|
|
832
|
+
],
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const reason =
|
|
837
|
+
typeof args.reason === "string" ? args.reason.trim() : "";
|
|
838
|
+
|
|
839
|
+
if (!reason) {
|
|
840
|
+
return {
|
|
841
|
+
content: [
|
|
842
|
+
{
|
|
843
|
+
type: "text",
|
|
844
|
+
text: "โ ๏ธ Provide a non-empty justification when skipping tests.",
|
|
845
|
+
},
|
|
846
|
+
],
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
workflowState.state.testsCreated = true;
|
|
851
|
+
workflowState.state.testsPassed = true;
|
|
852
|
+
workflowState.state.testsSkipped = true;
|
|
853
|
+
workflowState.state.testsSkippedReason = reason;
|
|
854
|
+
workflowState.state.currentPhase = "documentation";
|
|
855
|
+
workflowState.state.readyToCommit = false;
|
|
856
|
+
workflowState.state.readyCheckCompleted = false;
|
|
857
|
+
workflowState.state.released = false;
|
|
858
|
+
workflowState.state.commitAndPushCompleted = false;
|
|
859
|
+
workflowState.state.lastCommitMessage = "";
|
|
860
|
+
workflowState.state.lastPushBranch = "";
|
|
861
|
+
await workflowState.save();
|
|
862
|
+
|
|
863
|
+
return {
|
|
864
|
+
content: [
|
|
865
|
+
{
|
|
866
|
+
type: "text",
|
|
867
|
+
text: `โ ๏ธ Tests skipped for this task.
|
|
868
|
+
Reason: ${reason}
|
|
869
|
+
|
|
870
|
+
Manual verification is now required.
|
|
871
|
+
|
|
872
|
+
Next Steps:
|
|
873
|
+
1. โ Fix/implement feature
|
|
874
|
+
2. โ ๏ธ Tests skipped (ensure manual QA)
|
|
875
|
+
3. โณ Create/update documentation
|
|
876
|
+
4. โณ Run 'check_ready_to_commit'
|
|
877
|
+
5. โณ Commit & push
|
|
878
|
+
6. โณ Run 'perform_release'
|
|
879
|
+
7. โณ Complete task`,
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
|
|
769
885
|
case "run_tests": {
|
|
770
886
|
if (!workflowState.state.bugFixed) {
|
|
771
887
|
return {
|
|
@@ -808,6 +924,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
808
924
|
workflowState.state.testCommand = args.testCommand;
|
|
809
925
|
workflowState.state.testDetails =
|
|
810
926
|
typeof args.details === "string" ? args.details : "";
|
|
927
|
+
workflowState.state.testsSkipped = false;
|
|
928
|
+
workflowState.state.testsSkippedReason = "";
|
|
811
929
|
workflowState.state.readyCheckCompleted = false;
|
|
812
930
|
workflowState.state.released = false;
|
|
813
931
|
workflowState.state.commitAndPushCompleted = false;
|
|
@@ -841,75 +959,86 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
841
959
|
};
|
|
842
960
|
}
|
|
843
961
|
|
|
844
|
-
|
|
845
|
-
|
|
962
|
+
case "create_documentation": {
|
|
963
|
+
if (!workflowState.state.testsPassed) {
|
|
964
|
+
return {
|
|
965
|
+
content: [
|
|
966
|
+
{
|
|
967
|
+
type: "text",
|
|
968
|
+
text: "โ ๏ธ Please ensure tests are passing first! Run 'run_tests' with passed=true.",
|
|
969
|
+
},
|
|
970
|
+
],
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
workflowState.state.documentationCreated = true;
|
|
975
|
+
workflowState.state.documentationType = args.documentationType;
|
|
976
|
+
workflowState.state.documentationSummary = args.summary;
|
|
977
|
+
workflowState.state.currentPhase = "ready";
|
|
978
|
+
workflowState.state.readyToCommit = true;
|
|
979
|
+
workflowState.state.readyCheckCompleted = false;
|
|
980
|
+
workflowState.state.released = false;
|
|
981
|
+
workflowState.state.commitAndPushCompleted = false;
|
|
982
|
+
workflowState.state.lastCommitMessage = "";
|
|
983
|
+
workflowState.state.lastPushBranch = "";
|
|
984
|
+
await workflowState.save();
|
|
985
|
+
|
|
846
986
|
return {
|
|
847
987
|
content: [
|
|
848
988
|
{
|
|
849
989
|
type: "text",
|
|
850
|
-
text:
|
|
990
|
+
text: `โ
Documentation created!\n\nType: ${args.documentationType}\nSummary: ${args.summary}\n\n๐ You're ready to verify your work!\n\nNext Steps:\n1. โ Fix/implement feature\n2. โ Create tests\n3. โ Run tests (GREEN!)\n4. โ Create documentation\n5. โณ Run 'check_ready_to_commit' to verify\n6. โณ Commit & push, then run 'perform_release'\n7. โณ Mark as complete with 'complete_task'\n\nRemember: git add . && git commit && git push`,
|
|
851
991
|
},
|
|
852
992
|
],
|
|
853
993
|
};
|
|
854
994
|
}
|
|
855
995
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
workflowState.state.commitAndPushCompleted = false;
|
|
864
|
-
workflowState.state.lastCommitMessage = "";
|
|
865
|
-
workflowState.state.lastPushBranch = "";
|
|
866
|
-
await workflowState.save();
|
|
867
|
-
|
|
868
|
-
return {
|
|
869
|
-
content: [
|
|
996
|
+
case "check_ready_to_commit": {
|
|
997
|
+
const status = workflowState.state;
|
|
998
|
+
const testsCreatedDone = status.testsSkipped || status.testsCreated;
|
|
999
|
+
const testsPassedDone = status.testsSkipped || status.testsPassed;
|
|
1000
|
+
const checks = [
|
|
1001
|
+
{ name: "Task started", done: status.currentPhase !== "idle" },
|
|
1002
|
+
{ name: "Feature/bug fixed", done: status.bugFixed },
|
|
870
1003
|
{
|
|
871
|
-
|
|
872
|
-
|
|
1004
|
+
name: status.testsSkipped
|
|
1005
|
+
? "Tests skipped (manual QA documented)"
|
|
1006
|
+
: "Tests created",
|
|
1007
|
+
done: testsCreatedDone,
|
|
873
1008
|
},
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1009
|
+
{
|
|
1010
|
+
name: status.testsSkipped ? "Tests skipped acknowledged" : "Tests passed",
|
|
1011
|
+
done: testsPassedDone,
|
|
1012
|
+
},
|
|
1013
|
+
{ name: "Documentation created", done: status.documentationCreated },
|
|
1014
|
+
];
|
|
1015
|
+
|
|
1016
|
+
const allDone = checks.every((c) => c.done);
|
|
1017
|
+
const checkList = checks
|
|
1018
|
+
.map((c) => `${c.done ? "โ
" : "โ"} ${c.name}`)
|
|
1019
|
+
.join("\n");
|
|
1020
|
+
|
|
1021
|
+
workflowState.state.readyCheckCompleted = allDone;
|
|
1022
|
+
if (allDone) {
|
|
1023
|
+
workflowState.state.currentPhase = workflowState.state.commitAndPushCompleted
|
|
1024
|
+
? workflowState.state.released
|
|
1025
|
+
? "ready_to_complete"
|
|
1026
|
+
: "release"
|
|
1027
|
+
: "commit";
|
|
1028
|
+
}
|
|
1029
|
+
await workflowState.save();
|
|
892
1030
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1031
|
+
if (allDone) {
|
|
1032
|
+
return {
|
|
1033
|
+
content: [
|
|
1034
|
+
{
|
|
1035
|
+
type: "text",
|
|
1036
|
+
text: `๐ ALL CHECKS PASSED!\n\n${checkList}\n\nโ
Next actions:\n1. Run 'commit_and_push' with your commit message\n2. Run 'perform_release' to record the release\n3. Finish with 'complete_task'\n\nTip: Provide the optional 'branch' argument to push to a non-default branch.\n\nTask: ${status.taskDescription}`,
|
|
1037
|
+
},
|
|
1038
|
+
],
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
902
1041
|
|
|
903
|
-
if (allDone) {
|
|
904
|
-
return {
|
|
905
|
-
content: [
|
|
906
|
-
{
|
|
907
|
-
type: "text",
|
|
908
|
-
text: `๐ ALL CHECKS PASSED!\n\n${checkList}\n\nโ
Next actions:\n1. Run 'commit_and_push' with your commit message\n2. Run 'perform_release' to record the release\n3. Finish with 'complete_task'\n\nTip: Provide the optional 'branch' argument to push to a non-default branch.\n\nTask: ${status.taskDescription}`,
|
|
909
|
-
},
|
|
910
|
-
],
|
|
911
|
-
};
|
|
912
|
-
} else {
|
|
913
1042
|
return {
|
|
914
1043
|
content: [
|
|
915
1044
|
{
|
|
@@ -919,371 +1048,243 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
919
1048
|
],
|
|
920
1049
|
};
|
|
921
1050
|
}
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
case "commit_and_push": {
|
|
925
|
-
if (!workflowState.state.readyToCommit) {
|
|
926
|
-
return {
|
|
927
|
-
content: [
|
|
928
|
-
{
|
|
929
|
-
type: "text",
|
|
930
|
-
text: "โ ๏ธ Not ready yet! Run 'check_ready_to_commit' and complete all steps first.",
|
|
931
|
-
},
|
|
932
|
-
],
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
if (!workflowState.state.readyCheckCompleted) {
|
|
937
|
-
return {
|
|
938
|
-
content: [
|
|
939
|
-
{
|
|
940
|
-
type: "text",
|
|
941
|
-
text: "โ ๏ธ Please run 'check_ready_to_commit' and resolve any outstanding items before committing!",
|
|
942
|
-
},
|
|
943
|
-
],
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
const providedCommitMessage =
|
|
948
|
-
typeof args.commitMessage === "string" ? args.commitMessage.trim() : "";
|
|
949
|
-
|
|
950
|
-
if (!(await hasWorkingChanges())) {
|
|
951
|
-
return {
|
|
952
|
-
content: [
|
|
953
|
-
{
|
|
954
|
-
type: "text",
|
|
955
|
-
text: "โ ๏ธ No changes detected. Make sure you have modifications to commit before running 'commit_and_push'.",
|
|
956
|
-
},
|
|
957
|
-
],
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
1051
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
content: [
|
|
964
|
-
{
|
|
965
|
-
type: "text",
|
|
966
|
-
text: "โ ๏ธ Please include test updates in your changes before running 'commit_and_push'. Ensure at least one test file is modified.",
|
|
967
|
-
},
|
|
968
|
-
],
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
try {
|
|
973
|
-
await exec("git add .");
|
|
974
|
-
} catch (error) {
|
|
975
|
-
return {
|
|
976
|
-
content: [
|
|
977
|
-
{
|
|
978
|
-
type: "text",
|
|
979
|
-
text: `โ Failed to stage files:\n\n${error.stderr || error.stdout || error.message}`,
|
|
980
|
-
},
|
|
981
|
-
],
|
|
982
|
-
};
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
const stagedChanges = await getStagedChanges();
|
|
986
|
-
const { summary: generatedSummary, body: commitBody } =
|
|
987
|
-
createCommitMessageParts(stagedChanges, providedCommitMessage);
|
|
988
|
-
|
|
989
|
-
if (!generatedSummary) {
|
|
990
|
-
return {
|
|
991
|
-
content: [
|
|
992
|
-
{
|
|
993
|
-
type: "text",
|
|
994
|
-
text: "โ ๏ธ Unable to generate commit message. Please provide a 'commitMessage' manually.",
|
|
995
|
-
},
|
|
996
|
-
],
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
try {
|
|
1001
|
-
if (commitBody) {
|
|
1002
|
-
await exec(
|
|
1003
|
-
`git commit -m ${shellEscape(generatedSummary)} -m ${shellEscape(commitBody)}`
|
|
1004
|
-
);
|
|
1005
|
-
} else {
|
|
1006
|
-
await exec(`git commit -m ${shellEscape(generatedSummary)}`);
|
|
1007
|
-
}
|
|
1008
|
-
} catch (error) {
|
|
1009
|
-
const output = error.stderr || error.stdout || error.message || "Unknown error";
|
|
1010
|
-
if (output.includes("nothing to commit")) {
|
|
1052
|
+
case "commit_and_push": {
|
|
1053
|
+
if (!workflowState.state.readyToCommit) {
|
|
1011
1054
|
return {
|
|
1012
1055
|
content: [
|
|
1013
1056
|
{
|
|
1014
1057
|
type: "text",
|
|
1015
|
-
text: "โ ๏ธ
|
|
1058
|
+
text: "โ ๏ธ Not ready yet! Run 'check_ready_to_commit' and complete all steps first.",
|
|
1016
1059
|
},
|
|
1017
1060
|
],
|
|
1018
1061
|
};
|
|
1019
1062
|
}
|
|
1020
1063
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
const requestedBranch =
|
|
1032
|
-
typeof args.branch === "string" ? args.branch.trim() : "";
|
|
1033
|
-
const currentBranch = await getCurrentBranch();
|
|
1034
|
-
const pushCommand = requestedBranch
|
|
1035
|
-
? `git push origin ${shellEscape(requestedBranch)}`
|
|
1036
|
-
: "git push";
|
|
1037
|
-
|
|
1038
|
-
try {
|
|
1039
|
-
await exec(pushCommand);
|
|
1040
|
-
} catch (error) {
|
|
1041
|
-
return {
|
|
1042
|
-
content: [
|
|
1043
|
-
{
|
|
1044
|
-
type: "text",
|
|
1045
|
-
text: `โ git push failed:\n\n${error.stderr || error.stdout || error.message}`,
|
|
1046
|
-
},
|
|
1047
|
-
],
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
workflowState.state.commitAndPushCompleted = true;
|
|
1052
|
-
workflowState.state.lastCommitMessage = generatedSummary;
|
|
1053
|
-
workflowState.state.lastPushBranch =
|
|
1054
|
-
requestedBranch || currentBranch || "";
|
|
1055
|
-
workflowState.state.currentPhase = workflowState.state.released
|
|
1056
|
-
? "ready_to_complete"
|
|
1057
|
-
: "release";
|
|
1058
|
-
await workflowState.save();
|
|
1059
|
-
|
|
1060
|
-
return {
|
|
1061
|
-
content: [
|
|
1062
|
-
{
|
|
1063
|
-
type: "text",
|
|
1064
|
-
text: `โ
Commit & push completed!\n\nCommit message: ${generatedSummary}\nPushed to: ${
|
|
1065
|
-
requestedBranch || currentBranch || "(default upstream)"
|
|
1066
|
-
}\n\nNext: Run 'perform_release' to record the release.`,
|
|
1067
|
-
},
|
|
1068
|
-
],
|
|
1069
|
-
};
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
case "perform_release": {
|
|
1073
|
-
if (workflowState.state.currentPhase === "idle") {
|
|
1074
|
-
return {
|
|
1075
|
-
content: [
|
|
1076
|
-
{
|
|
1077
|
-
type: "text",
|
|
1078
|
-
text: "โ ๏ธ Please start a task first using 'start_task'!",
|
|
1079
|
-
},
|
|
1080
|
-
],
|
|
1081
|
-
};
|
|
1082
|
-
}
|
|
1064
|
+
if (!workflowState.state.readyCheckCompleted) {
|
|
1065
|
+
return {
|
|
1066
|
+
content: [
|
|
1067
|
+
{
|
|
1068
|
+
type: "text",
|
|
1069
|
+
text: "โ ๏ธ Please run 'check_ready_to_commit' and resolve any outstanding items before committing!",
|
|
1070
|
+
},
|
|
1071
|
+
],
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1083
1074
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
content: [
|
|
1087
|
-
{
|
|
1088
|
-
type: "text",
|
|
1089
|
-
text: "โ ๏ธ Please run 'commit_and_push' after the ready check before recording a release!",
|
|
1090
|
-
},
|
|
1091
|
-
],
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1075
|
+
const providedCommitMessage =
|
|
1076
|
+
typeof args.commitMessage === "string" ? args.commitMessage.trim() : "";
|
|
1094
1077
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1078
|
+
if (!(await hasWorkingChanges())) {
|
|
1079
|
+
return {
|
|
1080
|
+
content: [
|
|
1081
|
+
{
|
|
1082
|
+
type: "text",
|
|
1083
|
+
text: "โ ๏ธ No changes detected. Make sure you have modifications to commit before running 'commit_and_push'.",
|
|
1084
|
+
},
|
|
1085
|
+
],
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1105
1088
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1089
|
+
if (!(await hasTestChanges()) && !workflowState.state.testsSkipped) {
|
|
1090
|
+
return {
|
|
1091
|
+
content: [
|
|
1092
|
+
{
|
|
1093
|
+
type: "text",
|
|
1094
|
+
text: "โ ๏ธ Please include test updates in your changes before running 'commit_and_push'. Ensure at least one test file is modified.",
|
|
1095
|
+
},
|
|
1096
|
+
],
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1108
1099
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1100
|
+
try {
|
|
1101
|
+
await exec("git add .");
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
return {
|
|
1104
|
+
content: [
|
|
1105
|
+
{
|
|
1106
|
+
type: "text",
|
|
1107
|
+
text: `โ Failed to stage files:\n\n${error.stderr || error.stdout || error.message}`,
|
|
1108
|
+
},
|
|
1109
|
+
],
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1119
1112
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
{
|
|
1124
|
-
type: "text",
|
|
1125
|
-
text: "โ ๏ธ Working tree not clean! Please commit or stash all changes before running 'perform_release'.",
|
|
1126
|
-
},
|
|
1127
|
-
],
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1113
|
+
const stagedChanges = await getStagedChanges();
|
|
1114
|
+
const { summary: generatedSummary, body: commitBody } =
|
|
1115
|
+
createCommitMessageParts(stagedChanges, providedCommitMessage);
|
|
1130
1116
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1117
|
+
if (!generatedSummary) {
|
|
1118
|
+
return {
|
|
1119
|
+
content: [
|
|
1120
|
+
{
|
|
1121
|
+
type: "text",
|
|
1122
|
+
text: "โ ๏ธ Unable to generate commit message. Please provide a 'commitMessage' manually.",
|
|
1123
|
+
},
|
|
1124
|
+
],
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1135
1127
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1128
|
+
try {
|
|
1129
|
+
if (commitBody) {
|
|
1130
|
+
await exec(
|
|
1131
|
+
`git commit -m ${shellEscape(generatedSummary)} -m ${shellEscape(commitBody)}`
|
|
1132
|
+
);
|
|
1133
|
+
} else {
|
|
1134
|
+
await exec(`git commit -m ${shellEscape(generatedSummary)}`);
|
|
1135
|
+
}
|
|
1136
|
+
} catch (error) {
|
|
1137
|
+
const output = error.stderr || error.stdout || error.message || "Unknown error";
|
|
1138
|
+
if (output.includes("nothing to commit")) {
|
|
1139
|
+
return {
|
|
1140
|
+
content: [
|
|
1141
|
+
{
|
|
1142
|
+
type: "text",
|
|
1143
|
+
text: "โ ๏ธ Nothing to commit. Make additional changes before running 'commit_and_push'.",
|
|
1144
|
+
},
|
|
1145
|
+
],
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1139
1148
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
],
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1149
|
+
return {
|
|
1150
|
+
content: [
|
|
1151
|
+
{
|
|
1152
|
+
type: "text",
|
|
1153
|
+
text: `โ git commit failed:\n\n${output}`,
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1152
1158
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
+
const requestedBranch =
|
|
1160
|
+
typeof args.branch === "string" ? args.branch.trim() : "";
|
|
1161
|
+
const currentBranch = await getCurrentBranch();
|
|
1162
|
+
const pushCommand = requestedBranch
|
|
1163
|
+
? `git push origin ${shellEscape(requestedBranch)}`
|
|
1164
|
+
: "git push";
|
|
1159
1165
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1166
|
+
try {
|
|
1167
|
+
await exec(pushCommand);
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
return {
|
|
1170
|
+
content: [
|
|
1171
|
+
{
|
|
1172
|
+
type: "text",
|
|
1173
|
+
text: `โ git push failed:\n\n${error.stderr || error.stdout || error.message}`,
|
|
1174
|
+
},
|
|
1175
|
+
],
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1169
1178
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
],
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1179
|
+
workflowState.state.commitAndPushCompleted = true;
|
|
1180
|
+
workflowState.state.lastCommitMessage = generatedSummary;
|
|
1181
|
+
workflowState.state.lastPushBranch =
|
|
1182
|
+
requestedBranch || currentBranch || "";
|
|
1183
|
+
workflowState.state.currentPhase = workflowState.state.released
|
|
1184
|
+
? "ready_to_complete"
|
|
1185
|
+
: "release";
|
|
1186
|
+
await workflowState.save();
|
|
1181
1187
|
|
|
1182
|
-
if (!workflowState.state.readyCheckCompleted) {
|
|
1183
1188
|
return {
|
|
1184
1189
|
content: [
|
|
1185
1190
|
{
|
|
1186
1191
|
type: "text",
|
|
1187
|
-
text:
|
|
1192
|
+
text: `โ
Commit & push completed!\n\nCommit message: ${generatedSummary}\nPushed to: ${
|
|
1193
|
+
requestedBranch || currentBranch || "(default upstream)"
|
|
1194
|
+
}\n\nNext: Run 'perform_release' to record the release.`,
|
|
1188
1195
|
},
|
|
1189
1196
|
],
|
|
1190
1197
|
};
|
|
1191
1198
|
}
|
|
1192
1199
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1200
|
+
case "perform_release": {
|
|
1201
|
+
if (workflowState.state.currentPhase === "idle") {
|
|
1202
|
+
return {
|
|
1203
|
+
content: [
|
|
1204
|
+
{
|
|
1205
|
+
type: "text",
|
|
1206
|
+
text: "โ ๏ธ Please start a task first using 'start_task'!",
|
|
1207
|
+
},
|
|
1208
|
+
],
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1203
1211
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1212
|
+
if (!workflowState.state.commitAndPushCompleted) {
|
|
1213
|
+
return {
|
|
1214
|
+
content: [
|
|
1215
|
+
{
|
|
1216
|
+
type: "text",
|
|
1217
|
+
text: "โ ๏ธ Please run 'commit_and_push' after the ready check before recording a release!",
|
|
1218
|
+
},
|
|
1219
|
+
],
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1214
1222
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1223
|
+
if (!workflowState.state.readyCheckCompleted) {
|
|
1224
|
+
return {
|
|
1225
|
+
content: [
|
|
1226
|
+
{
|
|
1227
|
+
type: "text",
|
|
1228
|
+
text: "โ ๏ธ Please run 'check_ready_to_commit' and ensure all checks pass before releasing!",
|
|
1229
|
+
},
|
|
1230
|
+
],
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1225
1233
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
taskType: workflowState.state.taskType,
|
|
1229
|
-
fixSummary: workflowState.state.fixSummary,
|
|
1230
|
-
testCommand: workflowState.state.testCommand,
|
|
1231
|
-
documentationType: workflowState.state.documentationType,
|
|
1232
|
-
commitMessage: args.commitMessage,
|
|
1233
|
-
releaseCommand: workflowState.state.releaseCommand,
|
|
1234
|
-
releaseNotes: workflowState.state.releaseNotes,
|
|
1235
|
-
});
|
|
1234
|
+
const releaseCommand =
|
|
1235
|
+
typeof args.command === "string" ? args.command.trim() : "";
|
|
1236
1236
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1237
|
+
if (!releaseCommand) {
|
|
1238
|
+
return {
|
|
1239
|
+
content: [
|
|
1240
|
+
{
|
|
1241
|
+
type: "text",
|
|
1242
|
+
text: "โ ๏ธ Please provide a non-empty 'command' when using 'perform_release'.",
|
|
1243
|
+
},
|
|
1244
|
+
],
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1241
1247
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1248
|
+
if (await hasWorkingChanges()) {
|
|
1249
|
+
return {
|
|
1250
|
+
content: [
|
|
1251
|
+
{
|
|
1252
|
+
type: "text",
|
|
1253
|
+
text: "โ ๏ธ Working tree not clean! Please commit or stash all changes before running 'perform_release'.",
|
|
1254
|
+
},
|
|
1255
|
+
],
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1251
1258
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1259
|
+
const lastCommitMessage = await getLastCommitMessage();
|
|
1260
|
+
const releaseType = determineReleaseTypeFromCommit(
|
|
1261
|
+
lastCommitMessage || workflowState.state.lastCommitMessage
|
|
1262
|
+
);
|
|
1254
1263
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
{
|
|
1259
|
-
type: "text",
|
|
1260
|
-
text: "๐ No active task.\n\nUse 'start_task' to begin a new coding session.",
|
|
1261
|
-
},
|
|
1262
|
-
],
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1264
|
+
const finalCommand = releaseCommand.includes("--release-as")
|
|
1265
|
+
? releaseCommand
|
|
1266
|
+
: `${releaseCommand} -- --release-as ${releaseType}`;
|
|
1265
1267
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1268
|
+
try {
|
|
1269
|
+
await exec(finalCommand);
|
|
1270
|
+
} catch (error) {
|
|
1271
|
+
return {
|
|
1272
|
+
content: [
|
|
1273
|
+
{
|
|
1274
|
+
type: "text",
|
|
1275
|
+
text: `โ Release command failed:\n\n${error.stderr || error.stdout || error.message}`,
|
|
1276
|
+
},
|
|
1277
|
+
],
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1275
1280
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
],
|
|
1283
|
-
};
|
|
1284
|
-
}
|
|
1281
|
+
workflowState.state.released = true;
|
|
1282
|
+
workflowState.state.releaseCommand = finalCommand;
|
|
1283
|
+
workflowState.state.releaseNotes =
|
|
1284
|
+
typeof args.notes === "string" ? args.notes : "";
|
|
1285
|
+
workflowState.state.currentPhase = "ready_to_complete";
|
|
1286
|
+
await workflowState.save();
|
|
1285
1287
|
|
|
1286
|
-
case "view_history": {
|
|
1287
1288
|
const limit = args.limit || 10;
|
|
1288
1289
|
const history = workflowState.state.history.slice(-limit).reverse();
|
|
1289
1290
|
|
package/package.json
CHANGED
|
@@ -38,6 +38,8 @@ test("WorkflowState persists data across save/load", async () => {
|
|
|
38
38
|
state.state.commitAndPushCompleted = true;
|
|
39
39
|
state.state.lastCommitMessage = "test: persistence";
|
|
40
40
|
state.state.lastPushBranch = "main";
|
|
41
|
+
state.state.testsSkipped = true;
|
|
42
|
+
state.state.testsSkippedReason = "Legacy app uses manual QA";
|
|
41
43
|
await state.save();
|
|
42
44
|
|
|
43
45
|
const reloaded = new WorkflowState(state.stateFile);
|
|
@@ -54,6 +56,11 @@ test("WorkflowState persists data across save/load", async () => {
|
|
|
54
56
|
assert.equal(reloaded.state.commitAndPushCompleted, true);
|
|
55
57
|
assert.equal(reloaded.state.lastCommitMessage, "test: persistence");
|
|
56
58
|
assert.equal(reloaded.state.lastPushBranch, "main");
|
|
59
|
+
assert.equal(reloaded.state.testsSkipped, true);
|
|
60
|
+
assert.equal(
|
|
61
|
+
reloaded.state.testsSkippedReason,
|
|
62
|
+
"Legacy app uses manual QA"
|
|
63
|
+
);
|
|
57
64
|
});
|
|
58
65
|
});
|
|
59
66
|
|
|
@@ -66,6 +73,8 @@ test("WorkflowState reset keeps history but clears progress", async () => {
|
|
|
66
73
|
state.state.readyCheckCompleted = true;
|
|
67
74
|
state.state.released = true;
|
|
68
75
|
state.state.commitAndPushCompleted = true;
|
|
76
|
+
state.state.testsSkipped = true;
|
|
77
|
+
state.state.testsSkippedReason = "Manual QA";
|
|
69
78
|
state.addToHistory({ taskDescription: "Sample task" });
|
|
70
79
|
|
|
71
80
|
state.reset();
|
|
@@ -77,11 +86,29 @@ test("WorkflowState reset keeps history but clears progress", async () => {
|
|
|
77
86
|
assert.equal(state.state.readyCheckCompleted, false);
|
|
78
87
|
assert.equal(state.state.released, false);
|
|
79
88
|
assert.equal(state.state.commitAndPushCompleted, false);
|
|
89
|
+
assert.equal(state.state.testsSkipped, false);
|
|
90
|
+
assert.equal(state.state.testsSkippedReason, "");
|
|
80
91
|
assert.equal(state.state.history.length, 1);
|
|
81
92
|
assert.equal(state.state.history[0].taskDescription, "Sample task");
|
|
82
93
|
});
|
|
83
94
|
});
|
|
84
95
|
|
|
96
|
+
test("getNextStep treats skipped tests as satisfied", () => {
|
|
97
|
+
const skippedState = {
|
|
98
|
+
bugFixed: true,
|
|
99
|
+
testsCreated: true,
|
|
100
|
+
testsPassed: true,
|
|
101
|
+
testsSkipped: true,
|
|
102
|
+
testsSkippedReason: "Legacy system",
|
|
103
|
+
documentationCreated: false,
|
|
104
|
+
readyCheckCompleted: false,
|
|
105
|
+
commitAndPushCompleted: false,
|
|
106
|
+
released: false,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
assert.equal(getNextStep(skippedState), "Create documentation");
|
|
110
|
+
});
|
|
111
|
+
|
|
85
112
|
test("getNextStep guides workflow progression", () => {
|
|
86
113
|
const baseState = {
|
|
87
114
|
bugFixed: false,
|