github-issue-tower-defence-management 1.180.1 → 1.181.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/adapter/entry-points/console/ui-dist/assets/index-BUFcVUVD.js +86 -0
  3. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  4. package/bin/adapter/repositories/GoogleSpreadsheetRepository.js +41 -12
  5. package/bin/adapter/repositories/GoogleSpreadsheetRepository.js.map +1 -1
  6. package/bin/domain/usecases/extractFencedJsonBlocks.js +18 -0
  7. package/bin/domain/usecases/extractFencedJsonBlocks.js.map +1 -0
  8. package/bin/domain/usecases/extractNextStepAgent.js +14 -23
  9. package/bin/domain/usecases/extractNextStepAgent.js.map +1 -1
  10. package/bin/domain/usecases/isPullRequestDeclaredUnnecessary.js +10 -17
  11. package/bin/domain/usecases/isPullRequestDeclaredUnnecessary.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +1 -1
  14. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +1 -0
  15. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.stories.tsx +25 -0
  16. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.test.tsx +50 -0
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.tsx +41 -0
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.stories.tsx +1 -0
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.test.tsx +1 -0
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.tsx +5 -0
  21. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +70 -0
  22. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +29 -0
  23. package/src/adapter/entry-points/console/ui/src/features/console/logic/actionToast.test.ts +14 -0
  24. package/src/adapter/entry-points/console/ui/src/features/console/logic/actionToast.ts +5 -1
  25. package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.ts +1 -0
  26. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +1 -0
  27. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +7 -0
  28. package/src/adapter/entry-points/console/ui-dist/assets/index-BUFcVUVD.js +86 -0
  29. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  30. package/src/adapter/repositories/GoogleSpreadsheetRepository.test.ts +47 -0
  31. package/src/adapter/repositories/GoogleSpreadsheetRepository.ts +76 -36
  32. package/src/domain/usecases/extractFencedJsonBlocks.test.ts +40 -0
  33. package/src/domain/usecases/extractFencedJsonBlocks.ts +21 -0
  34. package/src/domain/usecases/extractNextStepAgent.test.ts +19 -0
  35. package/src/domain/usecases/extractNextStepAgent.ts +15 -27
  36. package/src/domain/usecases/isPullRequestDeclaredUnnecessary.test.ts +33 -0
  37. package/src/domain/usecases/isPullRequestDeclaredUnnecessary.ts +13 -21
  38. package/types/adapter/repositories/GoogleSpreadsheetRepository.d.ts +3 -1
  39. package/types/adapter/repositories/GoogleSpreadsheetRepository.d.ts.map +1 -1
  40. package/types/domain/usecases/extractFencedJsonBlocks.d.ts +2 -0
  41. package/types/domain/usecases/extractFencedJsonBlocks.d.ts.map +1 -0
  42. package/types/domain/usecases/extractNextStepAgent.d.ts.map +1 -1
  43. package/types/domain/usecases/isPullRequestDeclaredUnnecessary.d.ts.map +1 -1
  44. package/bin/adapter/entry-points/console/ui-dist/assets/index-I_2Yu8fM.js +0 -86
  45. package/src/adapter/entry-points/console/ui-dist/assets/index-I_2Yu8fM.js +0 -86
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>TDPM Console</title>
7
- <script type="module" crossorigin src="/assets/index-I_2Yu8fM.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-BUFcVUVD.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-DeZcPNCr.css">
9
9
  </head>
10
10
  <body>
@@ -9,9 +9,37 @@ const dotenv_1 = __importDefault(require("dotenv"));
9
9
  dotenv_1.default.config();
10
10
  class GoogleSpreadsheetRepository {
11
11
  constructor(localStorageRepository, serviceAccountKey = process.env.GOOGLE_SERVICE_ACCOUNT_KEY ||
12
- 'dummy', sheetsClientFactory) {
12
+ 'dummy', sheetsClientFactory, sleepFn = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
13
13
  this.localStorageRepository = localStorageRepository;
14
14
  this.keyFile = './tmp/service-account-key.json';
15
+ this.callWithRetry = async (fn) => {
16
+ const backoffMs = [1000, 2000, 4000];
17
+ let lastError;
18
+ for (let attempt = 0; attempt <= backoffMs.length; attempt++) {
19
+ try {
20
+ return await fn();
21
+ }
22
+ catch (error) {
23
+ lastError = error;
24
+ const isQuotaError = (() => {
25
+ if (!(error instanceof Error))
26
+ return false;
27
+ if (error.message.includes('Quota exceeded'))
28
+ return true;
29
+ if ('status' in error && error.status === 429)
30
+ return true;
31
+ if ('code' in error && error.code === 429)
32
+ return true;
33
+ return false;
34
+ })();
35
+ if (!isQuotaError || attempt === backoffMs.length) {
36
+ throw error;
37
+ }
38
+ await this.sleepFn(backoffMs[attempt]);
39
+ }
40
+ }
41
+ throw lastError;
42
+ };
15
43
  this.getSpreadsheetId = (spreadsheetUrl) => {
16
44
  const url = new URL(spreadsheetUrl);
17
45
  return url.pathname.split('/')[3];
@@ -19,9 +47,9 @@ class GoogleSpreadsheetRepository {
19
47
  this.getSheet = async (spreadsheetUrl, sheetName) => {
20
48
  const sheets = this.sheetsClient;
21
49
  const spreadsheetId = this.getSpreadsheetId(spreadsheetUrl);
22
- const responseSheet = await sheets.spreadsheets.get({
50
+ const responseSheet = await this.callWithRetry(() => sheets.spreadsheets.get({
23
51
  spreadsheetId,
24
- });
52
+ }));
25
53
  if (responseSheet.status !== 200) {
26
54
  throw new Error(`Failed to get sheet: ${responseSheet.status}. ${JSON.stringify(responseSheet.data)}`);
27
55
  }
@@ -29,10 +57,10 @@ class GoogleSpreadsheetRepository {
29
57
  if (!sheet) {
30
58
  return null;
31
59
  }
32
- const response = await sheets.spreadsheets.values.get({
60
+ const response = await this.callWithRetry(() => sheets.spreadsheets.values.get({
33
61
  spreadsheetId,
34
62
  range: sheetName,
35
- });
63
+ }));
36
64
  if (response.status !== 200) {
37
65
  throw new Error(`Failed to get sheet: ${response.status}. ${JSON.stringify(response.data)}`);
38
66
  }
@@ -45,14 +73,14 @@ class GoogleSpreadsheetRepository {
45
73
  const sheets = this.sheetsClient;
46
74
  const spreadsheetId = this.getSpreadsheetId(spreadsheetUrl);
47
75
  await this.createNewSheetIfNotExists(spreadsheetUrl, sheetName);
48
- const response = await sheets.spreadsheets.values.update({
76
+ const response = await this.callWithRetry(() => sheets.spreadsheets.values.update({
49
77
  spreadsheetId,
50
78
  range: `${sheetName}!${String.fromCharCode(65 + column)}${row + 1}`,
51
79
  valueInputOption: 'RAW',
52
80
  requestBody: {
53
81
  values: [[value]],
54
82
  },
55
- });
83
+ }));
56
84
  if (response.status !== 200) {
57
85
  throw new Error(`Failed to update cell: ${response.status}. ${JSON.stringify(response.data)}`);
58
86
  }
@@ -60,7 +88,7 @@ class GoogleSpreadsheetRepository {
60
88
  this.sheetExists = async (spreadsheetUrl, sheetName) => {
61
89
  const sheets = this.sheetsClient;
62
90
  const spreadsheetId = this.getSpreadsheetId(spreadsheetUrl);
63
- const response = await sheets.spreadsheets.get({ spreadsheetId });
91
+ const response = await this.callWithRetry(() => sheets.spreadsheets.get({ spreadsheetId }));
64
92
  if (response.status !== 200) {
65
93
  throw new Error(`Failed to get sheet: ${response.status}. ${JSON.stringify(response.data)}`);
66
94
  }
@@ -72,7 +100,7 @@ class GoogleSpreadsheetRepository {
72
100
  if (await this.sheetExists(spreadsheetUrl, sheetName)) {
73
101
  return;
74
102
  }
75
- const response = await sheets.spreadsheets.batchUpdate({
103
+ const response = await this.callWithRetry(() => sheets.spreadsheets.batchUpdate({
76
104
  spreadsheetId,
77
105
  requestBody: {
78
106
  requests: [
@@ -85,7 +113,7 @@ class GoogleSpreadsheetRepository {
85
113
  },
86
114
  ],
87
115
  },
88
- });
116
+ }));
89
117
  if (response.status !== 200) {
90
118
  throw new Error(`Failed to create sheet: ${response.status}. ${JSON.stringify(response.data)}`);
91
119
  }
@@ -96,18 +124,19 @@ class GoogleSpreadsheetRepository {
96
124
  await this.createNewSheetIfNotExists(spreadsheetUrl, sheetName);
97
125
  const sheet = await this.getSheet(spreadsheetUrl, sheetName);
98
126
  const range = `${sheetName}!A${sheet ? sheet.length + 1 : 1}:A`;
99
- const response = await sheets.spreadsheets.values.append({
127
+ const response = await this.callWithRetry(() => sheets.spreadsheets.values.append({
100
128
  spreadsheetId,
101
129
  range: range,
102
130
  valueInputOption: 'RAW',
103
131
  requestBody: {
104
132
  values,
105
133
  },
106
- });
134
+ }));
107
135
  if (response.status !== 200) {
108
136
  throw new Error(`Failed to append values: ${response.status}. ${JSON.stringify(response.data)}`);
109
137
  }
110
138
  };
139
+ this.sleepFn = sleepFn;
111
140
  this.localStorageRepository.write(this.keyFile, serviceAccountKey);
112
141
  this.sheetsClient = sheetsClientFactory
113
142
  ? sheetsClientFactory()
@@ -1 +1 @@
1
- {"version":3,"file":"GoogleSpreadsheetRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/GoogleSpreadsheetRepository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GoogleSpreadsheetRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/GoogleSpreadsheetRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractFencedJsonBlocks = void 0;
4
+ const normalizeReportBody_1 = require("./normalizeReportBody");
5
+ const extractFencedJsonBlocks = (body, context) => {
6
+ const blocks = [];
7
+ for (const match of (0, normalizeReportBody_1.normalizeReportBody)(body).matchAll(/```json\n([\s\S]*?)\n```/g)) {
8
+ try {
9
+ blocks.push(JSON.parse(match[1]));
10
+ }
11
+ catch (error) {
12
+ console.warn(`Invalid JSON in report body while checking ${context}:`, error);
13
+ }
14
+ }
15
+ return blocks;
16
+ };
17
+ exports.extractFencedJsonBlocks = extractFencedJsonBlocks;
18
+ //# sourceMappingURL=extractFencedJsonBlocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractFencedJsonBlocks.js","sourceRoot":"","sources":["../../../src/domain/usecases/extractFencedJsonBlocks.ts"],"names":[],"mappings":";;;AAAA,+DAA4D;AAErD,MAAM,uBAAuB,GAAG,CACrC,IAAY,EACZ,OAAe,EACJ,EAAE;IACb,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,IAAA,yCAAmB,EAAC,IAAI,CAAC,CAAC,QAAQ,CACpD,2BAA2B,CAC5B,EAAE,CAAC;QACF,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,8CAA8C,OAAO,GAAG,EACxD,KAAK,CACN,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAlBW,QAAA,uBAAuB,2BAkBlC"}
@@ -1,31 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractNextStepAgent = void 0;
4
- const normalizeReportBody_1 = require("./normalizeReportBody");
4
+ const extractFencedJsonBlocks_1 = require("./extractFencedJsonBlocks");
5
5
  const extractNextStepAgent = (body) => {
6
- const reportMatch = (0, normalizeReportBody_1.normalizeReportBody)(body).match(/```json\n([\s\S]*?)\n```/);
7
- if (!reportMatch || reportMatch.length < 2) {
8
- return null;
6
+ for (const block of (0, extractFencedJsonBlocks_1.extractFencedJsonBlocks)(body, 'nextStepAgent')) {
7
+ if (typeof block !== 'object' || block === null) {
8
+ continue;
9
+ }
10
+ if (!('nextStepAgent' in block)) {
11
+ continue;
12
+ }
13
+ const value = Reflect.get(block, 'nextStepAgent');
14
+ if (typeof value !== 'string' || value.trim() === '') {
15
+ continue;
16
+ }
17
+ return value.trim();
9
18
  }
10
- let reportJson;
11
- try {
12
- reportJson = JSON.parse(reportMatch[1]);
13
- }
14
- catch (error) {
15
- console.warn('Invalid JSON in report body while checking nextStepAgent:', error);
16
- return null;
17
- }
18
- if (typeof reportJson !== 'object' || reportJson === null) {
19
- return null;
20
- }
21
- if (!('nextStepAgent' in reportJson)) {
22
- return null;
23
- }
24
- const value = Reflect.get(reportJson, 'nextStepAgent');
25
- if (typeof value !== 'string' || value.trim() === '') {
26
- return null;
27
- }
28
- return value.trim();
19
+ return null;
29
20
  };
30
21
  exports.extractNextStepAgent = extractNextStepAgent;
31
22
  //# sourceMappingURL=extractNextStepAgent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extractNextStepAgent.js","sourceRoot":"","sources":["../../../src/domain/usecases/extractNextStepAgent.ts"],"names":[],"mappings":";;;AAAA,+DAA4D;AACrD,MAAM,oBAAoB,GAAG,CAAC,IAAY,EAAiB,EAAE;IAClE,MAAM,WAAW,GAAG,IAAA,yCAAmB,EAAC,IAAI,CAAC,CAAC,KAAK,CACjD,0BAA0B,CAC3B,CAAC;IACF,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CACV,2DAA2D,EAC3D,KAAK,CACN,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,CAAC,eAAe,IAAI,UAAU,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC,CAAC;AA5BW,QAAA,oBAAoB,wBA4B/B"}
1
+ {"version":3,"file":"extractNextStepAgent.js","sourceRoot":"","sources":["../../../src/domain/usecases/extractNextStepAgent.ts"],"names":[],"mappings":";;;AAAA,uEAAoE;AAE7D,MAAM,oBAAoB,GAAG,CAAC,IAAY,EAAiB,EAAE;IAClE,KAAK,MAAM,KAAK,IAAI,IAAA,iDAAuB,EAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;QACnE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAChD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,eAAe,IAAI,KAAK,CAAC,EAAE,CAAC;YAChC,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACrD,SAAS;QACX,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAfW,QAAA,oBAAoB,wBAe/B"}
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isPullRequestDeclaredUnnecessary = void 0;
4
+ const extractFencedJsonBlocks_1 = require("./extractFencedJsonBlocks");
4
5
  const isAgentReportBody_1 = require("./isAgentReportBody");
5
- const normalizeReportBody_1 = require("./normalizeReportBody");
6
6
  const isPullRequestDeclaredUnnecessary = (comments, isTrustedAuthor) => {
7
7
  const lastComment = comments[comments.length - 1];
8
8
  if (!lastComment ||
@@ -10,23 +10,16 @@ const isPullRequestDeclaredUnnecessary = (comments, isTrustedAuthor) => {
10
10
  !(0, isAgentReportBody_1.isAgentReportBody)(lastComment.content)) {
11
11
  return false;
12
12
  }
13
- const reportMatch = (0, normalizeReportBody_1.normalizeReportBody)(lastComment.content).match(/```json\n([\s\S]*?)\n```/);
14
- if (!reportMatch || reportMatch.length < 2) {
15
- return false;
16
- }
17
- let reportJson;
18
- try {
19
- reportJson = JSON.parse(reportMatch[1]);
20
- }
21
- catch (error) {
22
- console.warn('Invalid JSON in report body while checking pullRequestRequired:', error);
23
- return false;
24
- }
25
- if (typeof reportJson !== 'object' || reportJson === null) {
26
- return false;
13
+ for (const block of (0, extractFencedJsonBlocks_1.extractFencedJsonBlocks)(lastComment.content, 'pullRequestRequired')) {
14
+ if (typeof block !== 'object' || block === null) {
15
+ continue;
16
+ }
17
+ const report = { ...block };
18
+ if (report.pullRequestRequired === false) {
19
+ return true;
20
+ }
27
21
  }
28
- const report = { ...reportJson };
29
- return report.pullRequestRequired === false;
22
+ return false;
30
23
  };
31
24
  exports.isPullRequestDeclaredUnnecessary = isPullRequestDeclaredUnnecessary;
32
25
  //# sourceMappingURL=isPullRequestDeclaredUnnecessary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"isPullRequestDeclaredUnnecessary.js","sourceRoot":"","sources":["../../../src/domain/usecases/isPullRequestDeclaredUnnecessary.ts"],"names":[],"mappings":";;;AAAA,2DAAwD;AACxD,+DAA4D;AAErD,MAAM,gCAAgC,GAAG,CAC9C,QAA+C,EAC/C,eAA4C,EACnC,EAAE;IACX,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,IACE,CAAC,WAAW;QACZ,CAAC,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC;QACpC,CAAC,IAAA,qCAAiB,EAAC,WAAW,CAAC,OAAO,CAAC,EACvC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,WAAW,GAAG,IAAA,yCAAmB,EAAC,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,CAChE,0BAA0B,CAC3B,CAAC;IACF,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CACV,iEAAiE,EACjE,KAAK,CACN,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAA4B,EAAE,GAAG,UAAU,EAAE,CAAC;IAC1D,OAAO,MAAM,CAAC,mBAAmB,KAAK,KAAK,CAAC;AAC9C,CAAC,CAAC;AAjCW,QAAA,gCAAgC,oCAiC3C"}
1
+ {"version":3,"file":"isPullRequestDeclaredUnnecessary.js","sourceRoot":"","sources":["../../../src/domain/usecases/isPullRequestDeclaredUnnecessary.ts"],"names":[],"mappings":";;;AAAA,uEAAoE;AACpE,2DAAwD;AAEjD,MAAM,gCAAgC,GAAG,CAC9C,QAA+C,EAC/C,eAA4C,EACnC,EAAE;IACX,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,IACE,CAAC,WAAW;QACZ,CAAC,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC;QACpC,CAAC,IAAA,qCAAiB,EAAC,WAAW,CAAC,OAAO,CAAC,EACvC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAA,iDAAuB,EACzC,WAAW,CAAC,OAAO,EACnB,qBAAqB,CACtB,EAAE,CAAC;QACF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAChD,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAA4B,EAAE,GAAG,KAAK,EAAE,CAAC;QACrD,IAAI,MAAM,CAAC,mBAAmB,KAAK,KAAK,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAzBW,QAAA,gCAAgC,oCAyB3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.180.1",
3
+ "version": "1.181.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -112,7 +112,7 @@ test('renders the Workflow Blocker tab leftmost and shows its detail operations'
112
112
  ).click();
113
113
 
114
114
  await expect(
115
- page.locator('.console-op-button', { hasText: 'Awaiting Workspace' }),
115
+ page.locator('.console-op-button', { hasText: /^Awaiting Workspace$/ }),
116
116
  ).toBeVisible();
117
117
  await expect(
118
118
  page.locator('.console-op-button', { hasText: 'Close as not planned' }),
@@ -20,6 +20,7 @@ const noopOperationHandlers: ConsoleOperationHandlers = {
20
20
  onSetStatus: () => {},
21
21
  onSetInTmuxByHuman: () => {},
22
22
  onClose: () => {},
23
+ onOkAndAwaitingWorkspace: () => {},
23
24
  };
24
25
 
25
26
  const richMarkdownBody = [
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { consoleStatusOptionsFixture } from '../../testing/fixtures';
3
+ import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
4
+
5
+ const meta: Meta<typeof ConsoleOkAndAwaitingWorkspaceActions> = {
6
+ title: 'Console/ConsoleOkAndAwaitingWorkspaceActions',
7
+ component: ConsoleOkAndAwaitingWorkspaceActions,
8
+ args: { onOkAndAwaitingWorkspace: () => {} },
9
+ };
10
+
11
+ export default meta;
12
+
13
+ type Story = StoryObj<typeof ConsoleOkAndAwaitingWorkspaceActions>;
14
+
15
+ export const WithAwaitingWorkspaceOption: Story = {
16
+ args: { statusOptions: consoleStatusOptionsFixture },
17
+ };
18
+
19
+ export const WithoutAwaitingWorkspaceOption: Story = {
20
+ args: {
21
+ statusOptions: consoleStatusOptionsFixture.filter(
22
+ (o) => o.name.toLowerCase() !== 'awaiting workspace',
23
+ ),
24
+ },
25
+ };
@@ -0,0 +1,50 @@
1
+ import { fireEvent, render } from '@testing-library/react';
2
+ import { consoleStatusOptionsFixture } from '../../testing/fixtures';
3
+ import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
4
+
5
+ const [awaitingWorkspaceOption] = consoleStatusOptionsFixture.filter(
6
+ (o) => o.name.toLowerCase() === 'awaiting workspace',
7
+ );
8
+
9
+ const statusOptionsWithoutAwaitingWorkspace =
10
+ consoleStatusOptionsFixture.filter(
11
+ (o) => o.name.toLowerCase() !== 'awaiting workspace',
12
+ );
13
+
14
+ describe('ConsoleOkAndAwaitingWorkspaceActions', () => {
15
+ it('renders the button when the awaiting workspace option is present', () => {
16
+ const { getByRole } = render(
17
+ <ConsoleOkAndAwaitingWorkspaceActions
18
+ statusOptions={consoleStatusOptionsFixture}
19
+ onOkAndAwaitingWorkspace={() => {}}
20
+ />,
21
+ );
22
+ expect(
23
+ getByRole('button', { name: 'ok & Awaiting Workspace' }),
24
+ ).toBeInTheDocument();
25
+ });
26
+
27
+ it('returns null when the awaiting workspace option is absent', () => {
28
+ const { container } = render(
29
+ <ConsoleOkAndAwaitingWorkspaceActions
30
+ statusOptions={statusOptionsWithoutAwaitingWorkspace}
31
+ onOkAndAwaitingWorkspace={() => {}}
32
+ />,
33
+ );
34
+ expect(container.firstChild).toBeNull();
35
+ });
36
+
37
+ it('calls the callback with the awaiting workspace option on click', () => {
38
+ const onOkAndAwaitingWorkspace = jest.fn();
39
+ const { getByRole } = render(
40
+ <ConsoleOkAndAwaitingWorkspaceActions
41
+ statusOptions={consoleStatusOptionsFixture}
42
+ onOkAndAwaitingWorkspace={onOkAndAwaitingWorkspace}
43
+ />,
44
+ );
45
+ fireEvent.click(getByRole('button', { name: 'ok & Awaiting Workspace' }));
46
+ expect(onOkAndAwaitingWorkspace).toHaveBeenCalledWith(
47
+ awaitingWorkspaceOption,
48
+ );
49
+ });
50
+ });
@@ -0,0 +1,41 @@
1
+ import { colorFromEnum } from '../../logic/colors';
2
+ import type { ConsoleFieldOption } from '../../logic/types';
3
+
4
+ export type ConsoleOkAndAwaitingWorkspaceActionsProps = {
5
+ statusOptions: ConsoleFieldOption[];
6
+ onOkAndAwaitingWorkspace: (option: ConsoleFieldOption) => void;
7
+ };
8
+
9
+ const AWAITING_WORKSPACE_NAME = 'awaiting workspace';
10
+
11
+ export const ConsoleOkAndAwaitingWorkspaceActions = ({
12
+ statusOptions,
13
+ onOkAndAwaitingWorkspace,
14
+ }: ConsoleOkAndAwaitingWorkspaceActionsProps) => {
15
+ const option = statusOptions.find(
16
+ (o) => o.name.toLowerCase() === AWAITING_WORKSPACE_NAME,
17
+ );
18
+
19
+ if (option === undefined) {
20
+ return null;
21
+ }
22
+
23
+ const palette = colorFromEnum(option.color);
24
+
25
+ return (
26
+ <div className="console-op-group">
27
+ <button
28
+ type="button"
29
+ className="console-op-button"
30
+ style={{
31
+ color: palette.fg,
32
+ borderColor: palette.border,
33
+ backgroundColor: palette.bg,
34
+ }}
35
+ onClick={() => onOkAndAwaitingWorkspace(option)}
36
+ >
37
+ ok &amp; Awaiting Workspace
38
+ </button>
39
+ </div>
40
+ );
41
+ };
@@ -14,6 +14,7 @@ const handlers: ConsoleOperationHandlers = {
14
14
  onSetStatus: () => {},
15
15
  onSetInTmuxByHuman: () => {},
16
16
  onClose: () => {},
17
+ onOkAndAwaitingWorkspace: () => {},
17
18
  };
18
19
 
19
20
  const meta: Meta<typeof ConsoleOperationMenu> = {
@@ -14,6 +14,7 @@ const handlers: ConsoleOperationHandlers = {
14
14
  onSetStatus: jest.fn(),
15
15
  onSetInTmuxByHuman: jest.fn(),
16
16
  onClose: jest.fn(),
17
+ onOkAndAwaitingWorkspace: jest.fn(),
17
18
  };
18
19
 
19
20
  const prItem = consoleListItemsFixture[0];
@@ -9,6 +9,7 @@ import type {
9
9
  } from '../../logic/types';
10
10
  import { ConsoleCloseActions } from './ConsoleCloseActions';
11
11
  import { ConsoleNextActionDateActions } from './ConsoleNextActionDateActions';
12
+ import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
12
13
  import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActions';
13
14
  import { ConsoleStatusActions } from './ConsoleStatusActions';
14
15
  import { ConsoleStoryActions } from './ConsoleStoryActions';
@@ -34,6 +35,10 @@ export const ConsoleOperationMenu = ({
34
35
  const showStory = tab === 'triage';
35
36
  return (
36
37
  <div className="console-operation-bar">
38
+ <ConsoleOkAndAwaitingWorkspaceActions
39
+ statusOptions={statusOptions}
40
+ onOkAndAwaitingWorkspace={handlers.onOkAndAwaitingWorkspace}
41
+ />
37
42
  {hasPullRequest && (
38
43
  <ConsolePullRequestReviewActions
39
44
  onReview={handlers.onReview}
@@ -415,4 +415,74 @@ describe('useConsoleOperations', () => {
415
415
  ).rejects.toThrow('No project specified in the URL path.');
416
416
  expect(fetchMock).not.toHaveBeenCalled();
417
417
  });
418
+
419
+ it('posts an ok comment then sets status to awaiting workspace in order', async () => {
420
+ let callCount = 0;
421
+ const calls: Array<[string, unknown]> = [];
422
+ global.fetch = jest.fn(async (url: unknown, opts: unknown) => {
423
+ calls.push([url as string, opts]);
424
+ callCount += 1;
425
+ if (callCount === 1) {
426
+ return {
427
+ ok: true,
428
+ status: 200,
429
+ json: async () => ({
430
+ comment: {
431
+ author: 'bot',
432
+ body: 'ok',
433
+ createdAt: '2026-01-01T00:00:00Z',
434
+ },
435
+ }),
436
+ };
437
+ }
438
+ return { ok: true, status: 200, json: async () => ({ ok: true }) };
439
+ }) as unknown as typeof fetch;
440
+ const { result } = setup();
441
+ const [option] = consoleStatusOptionsFixture.filter(
442
+ (o) => o.name.toLowerCase() === 'awaiting workspace',
443
+ );
444
+ await act(async () => {
445
+ await result.current.operations.okAndMoveToAwaitingWorkspace(
446
+ issueItem,
447
+ option,
448
+ );
449
+ });
450
+ expect(calls[0][0]).toBe('/api/comment');
451
+ expect(JSON.parse((calls[0][1] as { body: string }).body)).toMatchObject({
452
+ pjcode: 'acme',
453
+ url: issueItem.url,
454
+ body: 'ok',
455
+ });
456
+ expect(calls[1][0]).toBe('/api/triage');
457
+ expect(JSON.parse((calls[1][1] as { body: string }).body)).toMatchObject({
458
+ pjcode: 'acme',
459
+ action: 'set_status',
460
+ issueUrl: issueItem.url,
461
+ statusName: option.name,
462
+ });
463
+ });
464
+
465
+ it('does not call the status endpoint when the comment post fails', async () => {
466
+ let callCount = 0;
467
+ global.fetch = jest.fn(async () => {
468
+ callCount += 1;
469
+ if (callCount === 1) {
470
+ return { ok: false, status: 500, text: async () => 'error' };
471
+ }
472
+ return { ok: true, status: 200, json: async () => ({ ok: true }) };
473
+ }) as unknown as typeof fetch;
474
+ const { result } = setup();
475
+ const [option] = consoleStatusOptionsFixture.filter(
476
+ (o) => o.name.toLowerCase() === 'awaiting workspace',
477
+ );
478
+ await expect(
479
+ act(async () => {
480
+ await result.current.operations.okAndMoveToAwaitingWorkspace(
481
+ issueItem,
482
+ option,
483
+ );
484
+ }),
485
+ ).rejects.toThrow();
486
+ expect(callCount).toBe(1);
487
+ });
418
488
  });
@@ -61,6 +61,10 @@ export type ConsoleOperationsApi = {
61
61
  item: ConsoleListItem,
62
62
  action: ConsoleCloseAction,
63
63
  ) => Promise<void>;
64
+ okAndMoveToAwaitingWorkspace: (
65
+ item: ConsoleListItem,
66
+ option: ConsoleFieldOption,
67
+ ) => Promise<void>;
64
68
  addComment: (item: ConsoleListItem, body: string) => Promise<ConsoleComment>;
65
69
  uploadAttachment: (item: ConsoleListItem, file: File) => Promise<string>;
66
70
  addInlineReviewComment: (
@@ -276,6 +280,30 @@ export const useConsoleOperations = (
276
280
  [pjcode, markDone],
277
281
  );
278
282
 
283
+ const okAndMoveToAwaitingWorkspace = useCallback(
284
+ async (item: ConsoleListItem, option: ConsoleFieldOption) => {
285
+ if (pjcode === null) {
286
+ throw missingPjcodeError();
287
+ }
288
+ await postConsoleComment({ pjcode, url: item.url, body: 'ok' });
289
+ const request: ConsoleTriageRequest = {
290
+ pjcode,
291
+ action: 'set_status',
292
+ issueUrl: item.url,
293
+ projectItemId: item.projectItemId,
294
+ statusName: option.name,
295
+ };
296
+ await postConsoleOperation(TRIAGE_OPERATION_PATH, request);
297
+ invalidateItemContent(item);
298
+ patchOverlay(
299
+ overlayKeyForItem(item),
300
+ { done: true, status: { name: option.name, color: option.color } },
301
+ mode,
302
+ );
303
+ },
304
+ [pjcode, invalidateItemContent, patchOverlay, mode],
305
+ );
306
+
279
307
  const addComment = useCallback(
280
308
  async (item: ConsoleListItem, body: string) => {
281
309
  if (pjcode === null) {
@@ -340,6 +368,7 @@ export const useConsoleOperations = (
340
368
  setStatus,
341
369
  setInTmuxByHuman,
342
370
  closeIssue,
371
+ okAndMoveToAwaitingWorkspace,
343
372
  addComment,
344
373
  uploadAttachment,
345
374
  addInlineReviewComment,
@@ -127,6 +127,17 @@ describe('actionToastColor', () => {
127
127
  actionToastColor({ type: 'next_action_date', action: 'snooze_1day' }),
128
128
  ).toBe('amber');
129
129
  expect(actionToastColor({ type: 'close', action: 'close' })).toBe('red');
130
+ expect(actionToastColor({ type: 'ok_and_awaiting_workspace' })).toBe(
131
+ 'blue',
132
+ );
133
+ });
134
+ });
135
+
136
+ describe('actionToastMessage for ok_and_awaiting_workspace', () => {
137
+ it('returns the composite label', () => {
138
+ expect(
139
+ actionToastMessage({ type: 'ok_and_awaiting_workspace' }, 'prs'),
140
+ ).toBe('ok → Awaiting Workspace');
130
141
  });
131
142
  });
132
143
 
@@ -138,6 +149,9 @@ describe('actionAdvances', () => {
138
149
  expect(actionAdvances({ type: 'set_status', optionName: 'x' }, 'prs')).toBe(
139
150
  true,
140
151
  );
152
+ expect(actionAdvances({ type: 'ok_and_awaiting_workspace' }, 'prs')).toBe(
153
+ true,
154
+ );
141
155
  });
142
156
 
143
157
  it('does not advance a snooze except on the manual triage tabs', () => {