npm-cli-gh-issue-preparator 1.13.0 → 1.15.0

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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [1.15.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.14.0...v1.15.0) (2026-02-23)
2
+
3
+
4
+ ### Features
5
+
6
+ * **core:** skip aw command when issue nextActionDate is tomorrow or future ([610b6e7](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/610b6e74f7e31d3746943df1bcbc73754db9f3e7))
7
+
8
+ # [1.14.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.13.0...v1.14.0) (2026-02-23)
9
+
10
+
11
+ ### Features
12
+
13
+ * **core:** skip aw command for issues with dependency or future nextActionHour ([7d3adfb](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/7d3adfbfec6695aa01e572652ad15eda361a6f70)), closes [#59](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/issues/59)
14
+
1
15
  # [1.13.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.12.0...v1.13.0) (2026-02-18)
2
16
 
3
17
 
@@ -29,6 +29,10 @@ class StartPreparationUseCase {
29
29
  .filter((issue) => issue.status === params.awaitingWorkspaceStatus);
30
30
  const currentPreparationIssueCount = allIssues.filter((issue) => issue.status === params.preparationStatus).length;
31
31
  let updatedCurrentPreparationIssueCount = currentPreparationIssueCount;
32
+ const now = new Date();
33
+ const currentHour = now.getHours();
34
+ const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
35
+ const tomorrowStart = new Date(todayStart.getFullYear(), todayStart.getMonth(), todayStart.getDate() + 1);
32
36
  for (let i = 0; i < awaitingWorkspaceIssues.length &&
33
37
  updatedCurrentPreparationIssueCount < maximumPreparingIssuesCount; i++) {
34
38
  const issue = awaitingWorkspaceIssues[i];
@@ -37,6 +41,16 @@ class StartPreparationUseCase {
37
41
  !blockerIssueUrls.includes(issue.url)) {
38
42
  continue;
39
43
  }
44
+ if (issue.dependedIssueUrls.length > 0) {
45
+ continue;
46
+ }
47
+ if (issue.nextActionDate !== null &&
48
+ issue.nextActionDate >= tomorrowStart) {
49
+ continue;
50
+ }
51
+ if (issue.nextActionHour !== null && currentHour < issue.nextActionHour) {
52
+ continue;
53
+ }
40
54
  const agent = issue.labels
41
55
  .find((label) => label.startsWith('category:'))
42
56
  ?.replace('category:', '')
@@ -1 +1 @@
1
- {"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npm-cli-gh-issue-preparator",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -695,4 +695,297 @@ describe('StartPreparationUseCase', () => {
695
695
  expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
696
696
  expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
697
697
  });
698
+
699
+ it('should skip issues that have dependedIssueUrls', async () => {
700
+ const issueWithDependency = createMockIssue({
701
+ url: 'https://github.com/user/repo/issues/1',
702
+ title: 'Issue with dependency',
703
+ labels: [],
704
+ status: 'Awaiting Workspace',
705
+ dependedIssueUrls: ['https://github.com/user/repo/issues/2'],
706
+ });
707
+ const issueWithoutDependency = createMockIssue({
708
+ url: 'https://github.com/user/repo/issues/3',
709
+ title: 'Issue without dependency',
710
+ labels: [],
711
+ status: 'Awaiting Workspace',
712
+ dependedIssueUrls: [],
713
+ });
714
+
715
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
716
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
717
+ createMockStoryObjectMap([issueWithDependency, issueWithoutDependency]),
718
+ );
719
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce([
720
+ issueWithDependency,
721
+ issueWithoutDependency,
722
+ ]);
723
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
724
+ stdout: '',
725
+ stderr: '',
726
+ exitCode: 0,
727
+ });
728
+
729
+ await useCase.run({
730
+ projectUrl: 'https://github.com/user/repo',
731
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
732
+ preparationStatus: 'Preparation',
733
+ defaultAgentName: 'agent1',
734
+ maximumPreparingIssuesCount: null,
735
+ });
736
+
737
+ expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
738
+ expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
739
+ url: 'https://github.com/user/repo/issues/3',
740
+ status: 'Preparation',
741
+ });
742
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
743
+ });
744
+
745
+ it('should skip issues where nextActionHour is in the future', async () => {
746
+ jest.useFakeTimers();
747
+ try {
748
+ jest.setSystemTime(new Date('2024-01-01T10:00:00'));
749
+
750
+ const issueWithFutureNextActionHour = createMockIssue({
751
+ url: 'https://github.com/user/repo/issues/1',
752
+ title: 'Issue with future next action hour',
753
+ labels: [],
754
+ status: 'Awaiting Workspace',
755
+ nextActionHour: 15,
756
+ });
757
+ const issueWithoutNextActionHour = createMockIssue({
758
+ url: 'https://github.com/user/repo/issues/2',
759
+ title: 'Issue without next action hour',
760
+ labels: [],
761
+ status: 'Awaiting Workspace',
762
+ nextActionHour: null,
763
+ });
764
+
765
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
766
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
767
+ createMockStoryObjectMap([
768
+ issueWithFutureNextActionHour,
769
+ issueWithoutNextActionHour,
770
+ ]),
771
+ );
772
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce([
773
+ issueWithFutureNextActionHour,
774
+ issueWithoutNextActionHour,
775
+ ]);
776
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
777
+ stdout: '',
778
+ stderr: '',
779
+ exitCode: 0,
780
+ });
781
+
782
+ await useCase.run({
783
+ projectUrl: 'https://github.com/user/repo',
784
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
785
+ preparationStatus: 'Preparation',
786
+ defaultAgentName: 'agent1',
787
+ maximumPreparingIssuesCount: null,
788
+ });
789
+
790
+ expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
791
+ expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
792
+ url: 'https://github.com/user/repo/issues/2',
793
+ status: 'Preparation',
794
+ });
795
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
796
+ } finally {
797
+ jest.useRealTimers();
798
+ }
799
+ });
800
+
801
+ it('should skip issues where nextActionDate is tomorrow or more future', async () => {
802
+ jest.useFakeTimers();
803
+ try {
804
+ jest.setSystemTime(new Date('2024-01-15T10:00:00'));
805
+
806
+ const issueWithFutureNextActionDate = createMockIssue({
807
+ url: 'https://github.com/user/repo/issues/1',
808
+ title: 'Issue with future next action date',
809
+ labels: [],
810
+ status: 'Awaiting Workspace',
811
+ nextActionDate: new Date('2024-01-16'),
812
+ });
813
+ const issueWithoutNextActionDate = createMockIssue({
814
+ url: 'https://github.com/user/repo/issues/2',
815
+ title: 'Issue without next action date',
816
+ labels: [],
817
+ status: 'Awaiting Workspace',
818
+ nextActionDate: null,
819
+ });
820
+
821
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
822
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
823
+ createMockStoryObjectMap([
824
+ issueWithFutureNextActionDate,
825
+ issueWithoutNextActionDate,
826
+ ]),
827
+ );
828
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce([
829
+ issueWithFutureNextActionDate,
830
+ issueWithoutNextActionDate,
831
+ ]);
832
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
833
+ stdout: '',
834
+ stderr: '',
835
+ exitCode: 0,
836
+ });
837
+
838
+ await useCase.run({
839
+ projectUrl: 'https://github.com/user/repo',
840
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
841
+ preparationStatus: 'Preparation',
842
+ defaultAgentName: 'agent1',
843
+ maximumPreparingIssuesCount: null,
844
+ });
845
+
846
+ expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
847
+ expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
848
+ url: 'https://github.com/user/repo/issues/2',
849
+ status: 'Preparation',
850
+ });
851
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
852
+ } finally {
853
+ jest.useRealTimers();
854
+ }
855
+ });
856
+
857
+ it('should not skip issues where nextActionDate is today', async () => {
858
+ jest.useFakeTimers();
859
+ try {
860
+ jest.setSystemTime(new Date('2024-01-15T10:00:00'));
861
+
862
+ const issueWithTodayNextActionDate = createMockIssue({
863
+ url: 'https://github.com/user/repo/issues/1',
864
+ title: 'Issue with today next action date',
865
+ labels: [],
866
+ status: 'Awaiting Workspace',
867
+ nextActionDate: new Date('2024-01-15'),
868
+ });
869
+
870
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
871
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
872
+ createMockStoryObjectMap([issueWithTodayNextActionDate]),
873
+ );
874
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce([
875
+ issueWithTodayNextActionDate,
876
+ ]);
877
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
878
+ stdout: '',
879
+ stderr: '',
880
+ exitCode: 0,
881
+ });
882
+
883
+ await useCase.run({
884
+ projectUrl: 'https://github.com/user/repo',
885
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
886
+ preparationStatus: 'Preparation',
887
+ defaultAgentName: 'agent1',
888
+ maximumPreparingIssuesCount: null,
889
+ });
890
+
891
+ expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
892
+ expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
893
+ url: 'https://github.com/user/repo/issues/1',
894
+ status: 'Preparation',
895
+ });
896
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
897
+ } finally {
898
+ jest.useRealTimers();
899
+ }
900
+ });
901
+
902
+ it('should not skip issues where nextActionDate is in the past', async () => {
903
+ jest.useFakeTimers();
904
+ try {
905
+ jest.setSystemTime(new Date('2024-01-15T10:00:00'));
906
+
907
+ const issueWithPastNextActionDate = createMockIssue({
908
+ url: 'https://github.com/user/repo/issues/1',
909
+ title: 'Issue with past next action date',
910
+ labels: [],
911
+ status: 'Awaiting Workspace',
912
+ nextActionDate: new Date('2024-01-14'),
913
+ });
914
+
915
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
916
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
917
+ createMockStoryObjectMap([issueWithPastNextActionDate]),
918
+ );
919
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce([
920
+ issueWithPastNextActionDate,
921
+ ]);
922
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
923
+ stdout: '',
924
+ stderr: '',
925
+ exitCode: 0,
926
+ });
927
+
928
+ await useCase.run({
929
+ projectUrl: 'https://github.com/user/repo',
930
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
931
+ preparationStatus: 'Preparation',
932
+ defaultAgentName: 'agent1',
933
+ maximumPreparingIssuesCount: null,
934
+ });
935
+
936
+ expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
937
+ expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
938
+ url: 'https://github.com/user/repo/issues/1',
939
+ status: 'Preparation',
940
+ });
941
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
942
+ } finally {
943
+ jest.useRealTimers();
944
+ }
945
+ });
946
+
947
+ it('should not skip issues where nextActionHour is in the past or current hour', async () => {
948
+ jest.useFakeTimers();
949
+ try {
950
+ jest.setSystemTime(new Date('2024-01-01T15:00:00'));
951
+
952
+ const issueWithPastNextActionHour = createMockIssue({
953
+ url: 'https://github.com/user/repo/issues/1',
954
+ title: 'Issue with past next action hour',
955
+ labels: [],
956
+ status: 'Awaiting Workspace',
957
+ nextActionHour: 10,
958
+ });
959
+
960
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
961
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
962
+ createMockStoryObjectMap([issueWithPastNextActionHour]),
963
+ );
964
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce([
965
+ issueWithPastNextActionHour,
966
+ ]);
967
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
968
+ stdout: '',
969
+ stderr: '',
970
+ exitCode: 0,
971
+ });
972
+
973
+ await useCase.run({
974
+ projectUrl: 'https://github.com/user/repo',
975
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
976
+ preparationStatus: 'Preparation',
977
+ defaultAgentName: 'agent1',
978
+ maximumPreparingIssuesCount: null,
979
+ });
980
+
981
+ expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
982
+ expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
983
+ url: 'https://github.com/user/repo/issues/1',
984
+ status: 'Preparation',
985
+ });
986
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
987
+ } finally {
988
+ jest.useRealTimers();
989
+ }
990
+ });
698
991
  });
@@ -54,6 +54,19 @@ export class StartPreparationUseCase {
54
54
  ).length;
55
55
  let updatedCurrentPreparationIssueCount = currentPreparationIssueCount;
56
56
 
57
+ const now = new Date();
58
+ const currentHour = now.getHours();
59
+ const todayStart = new Date(
60
+ now.getFullYear(),
61
+ now.getMonth(),
62
+ now.getDate(),
63
+ );
64
+ const tomorrowStart = new Date(
65
+ todayStart.getFullYear(),
66
+ todayStart.getMonth(),
67
+ todayStart.getDate() + 1,
68
+ );
69
+
57
70
  for (
58
71
  let i = 0;
59
72
  i < awaitingWorkspaceIssues.length &&
@@ -71,6 +84,18 @@ export class StartPreparationUseCase {
71
84
  ) {
72
85
  continue;
73
86
  }
87
+ if (issue.dependedIssueUrls.length > 0) {
88
+ continue;
89
+ }
90
+ if (
91
+ issue.nextActionDate !== null &&
92
+ issue.nextActionDate >= tomorrowStart
93
+ ) {
94
+ continue;
95
+ }
96
+ if (issue.nextActionHour !== null && currentHour < issue.nextActionHour) {
97
+ continue;
98
+ }
74
99
  const agent =
75
100
  issue.labels
76
101
  .find((label) => label.startsWith('category:'))
@@ -1 +1 @@
1
- {"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAe,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAIhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBANlB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACf,cAAc,GAAG,mBAAmB,GAAG,QAAQ,CAChD,EACgB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EACpD,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,uBAAuB,EAAE,MAAM,CAAC;QAChC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5C,KAAG,OAAO,CAAC,IAAI,CAAC,CAgEf;IACF,yBAAyB,GACvB,gBAAgB,cAAc,KAC7B;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,EAAE,CAyBD;CACH"}
1
+ {"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAe,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAIhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBANlB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACf,cAAc,GAAG,mBAAmB,GAAG,QAAQ,CAChD,EACgB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EACpD,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,uBAAuB,EAAE,MAAM,CAAC;QAChC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5C,KAAG,OAAO,CAAC,IAAI,CAAC,CAyFf;IACF,yBAAyB,GACvB,gBAAgB,cAAc,KAC7B;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,EAAE,CAyBD;CACH"}