github-issue-tower-defence-management 1.142.2 → 1.143.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 (29) hide show
  1. package/.github/workflows/umino-project.yml +2 -8
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +2 -2
  4. package/bin/adapter/entry-points/console/ui-dist/assets/{index-BaGbcbYI.css → index-Bp-p-XOs.css} +1 -1
  5. package/bin/adapter/entry-points/console/ui-dist/assets/index-C1KKZ_a1.js +81 -0
  6. package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
  7. package/bin/domain/usecases/OauthTokenSelectUseCase.js +2 -2
  8. package/bin/domain/usecases/OauthTokenSelectUseCase.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleCopyCodeButton.stories.tsx +28 -0
  11. package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleCopyCodeButton.test.tsx +65 -0
  12. package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleCopyCodeButton.tsx +19 -0
  13. package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleMarkdownContent.test.tsx +103 -1
  14. package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleMarkdownContent.tsx +41 -5
  15. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCopyUrlButton.tsx +10 -42
  16. package/src/adapter/entry-points/console/ui/src/features/console/components/shared/ConsoleClipboardCopyButton.stories.tsx +32 -0
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/shared/ConsoleClipboardCopyButton.test.tsx +67 -0
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/shared/ConsoleClipboardCopyButton.tsx +57 -0
  19. package/src/adapter/entry-points/console/ui/src/index.css +31 -0
  20. package/src/adapter/entry-points/console/ui-dist/assets/{index-BaGbcbYI.css → index-Bp-p-XOs.css} +1 -1
  21. package/src/adapter/entry-points/console/ui-dist/assets/index-C1KKZ_a1.js +81 -0
  22. package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
  23. package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.test.ts +2 -2
  24. package/src/domain/usecases/OauthTokenSelectUseCase.test.ts +33 -11
  25. package/src/domain/usecases/OauthTokenSelectUseCase.ts +2 -2
  26. package/types/domain/usecases/OauthTokenSelectUseCase.d.ts +2 -2
  27. package/types/domain/usecases/OauthTokenSelectUseCase.d.ts.map +1 -1
  28. package/bin/adapter/entry-points/console/ui-dist/assets/index-2c5E3tdu.js +0 -81
  29. package/src/adapter/entry-points/console/ui-dist/assets/index-2c5E3tdu.js +0 -81
@@ -4,8 +4,8 @@
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-2c5E3tdu.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-BaGbcbYI.css">
7
+ <script type="module" crossorigin src="/assets/index-C1KKZ_a1.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-Bp-p-XOs.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -308,8 +308,8 @@ describe('LiveSessionOauthTokenSelectHandler', () => {
308
308
  expect(output.selectedName).toBeNull();
309
309
  const diagnostics = output.diagnostics.join('\n');
310
310
  expect(diagnostics).toContain('No eligible token');
311
- expect(diagnostics).toContain('5h >= 60% free');
312
- expect(diagnostics).toContain('7d >= 7% free');
311
+ expect(diagnostics).toContain('5h >= 25% free');
312
+ expect(diagnostics).toContain('7d >= 3% free');
313
313
  expect(diagnostics).not.toContain('fake-busy');
314
314
  });
315
315
 
@@ -59,11 +59,11 @@ describe('OauthTokenSelectUseCase', () => {
59
59
  expect(result.selected?.token).toBe('fake-token-soon');
60
60
  });
61
61
 
62
- it('excludes a token whose 5h window is less than 60% free', () => {
62
+ it('excludes a token whose 5h window is less than 25% free', () => {
63
63
  const result = useCase.run(
64
64
  [
65
- candidate('busy5h', snapshot({ fiveHourUtilization: 0.41 })),
66
- candidate('ok', snapshot({ fiveHourUtilization: 0.4 })),
65
+ candidate('busy5h', snapshot({ fiveHourUtilization: 0.76 })),
66
+ candidate('ok', snapshot({ fiveHourUtilization: 0.75 })),
67
67
  ],
68
68
  NOW,
69
69
  );
@@ -74,20 +74,22 @@ describe('OauthTokenSelectUseCase', () => {
74
74
  expect(busy?.exclusionReason).toContain('5h window');
75
75
  });
76
76
 
77
- it('treats exactly 40% used 5h utilization as eligible (boundary)', () => {
77
+ it('treats exactly 75% used 5h utilization as eligible (boundary)', () => {
78
78
  const result = useCase.run(
79
- [candidate('boundary', snapshot({ fiveHourUtilization: 0.4 }))],
79
+ [candidate('boundary', snapshot({ fiveHourUtilization: 0.75 }))],
80
80
  NOW,
81
81
  );
82
82
 
83
83
  expect(result.selected?.name).toBe('boundary');
84
+ const boundary = result.metrics.find((m) => m.name === 'boundary');
85
+ expect(boundary?.fiveHourFreeRatio).toBe(0.25);
84
86
  });
85
87
 
86
- it('excludes a token whose 7d window is less than 7% free', () => {
88
+ it('excludes a token whose 7d window is less than 3% free', () => {
87
89
  const result = useCase.run(
88
90
  [
89
- candidate('busy7d', snapshot({ sevenDayUtilization: 0.94 })),
90
- candidate('ok', snapshot({ sevenDayUtilization: 0.92 })),
91
+ candidate('busy7d', snapshot({ sevenDayUtilization: 0.98 })),
92
+ candidate('ok', snapshot({ sevenDayUtilization: 0.97 })),
91
93
  ],
92
94
  NOW,
93
95
  );
@@ -98,13 +100,33 @@ describe('OauthTokenSelectUseCase', () => {
98
100
  expect(busy?.exclusionReason).toContain('7d window');
99
101
  });
100
102
 
101
- it('treats a 7d window with at least 7% free as eligible (boundary)', () => {
103
+ it('treats exactly 97% used 7d utilization as eligible (boundary)', () => {
102
104
  const result = useCase.run(
103
- [candidate('boundary', snapshot({ sevenDayUtilization: 0.92 }))],
105
+ [candidate('boundary', snapshot({ sevenDayUtilization: 0.97 }))],
104
106
  NOW,
105
107
  );
106
108
 
107
109
  expect(result.selected?.name).toBe('boundary');
110
+ const boundary = result.metrics.find((m) => m.name === 'boundary');
111
+ expect(boundary?.sevenDayFreeRatio).toBeCloseTo(0.03, 9);
112
+ });
113
+
114
+ it('proceeds when 5h is exactly 25% free and 7d is exactly 3% free (combined boundary)', () => {
115
+ const result = useCase.run(
116
+ [
117
+ candidate(
118
+ 'boundary',
119
+ snapshot({ fiveHourUtilization: 0.75, sevenDayUtilization: 0.97 }),
120
+ ),
121
+ ],
122
+ NOW,
123
+ );
124
+
125
+ expect(result.selected?.name).toBe('boundary');
126
+ const boundary = result.metrics.find((m) => m.name === 'boundary');
127
+ expect(boundary?.eligible).toBe(true);
128
+ expect(boundary?.fiveHourFreeRatio).toBe(0.25);
129
+ expect(boundary?.sevenDayFreeRatio).toBeCloseTo(0.03, 9);
108
130
  });
109
131
 
110
132
  it('treats a token with no snapshot as fully free', () => {
@@ -165,7 +187,7 @@ describe('OauthTokenSelectUseCase', () => {
165
187
  const result = useCase.run(
166
188
  [
167
189
  candidate('busy', snapshot({ fiveHourUtilization: 0.9 })),
168
- candidate('alsoBusy', snapshot({ sevenDayUtilization: 0.95 })),
190
+ candidate('alsoBusy', snapshot({ sevenDayUtilization: 0.98 })),
169
191
  ],
170
192
  NOW,
171
193
  );
@@ -41,8 +41,8 @@ export type OauthTokenSelectResult = {
41
41
  const SECONDS_PER_DAY = 86400;
42
42
  const SEVEN_DAYS_IN_SECONDS = 7 * SECONDS_PER_DAY;
43
43
 
44
- export const FIVE_HOUR_MIN_FREE_RATIO = 0.6;
45
- export const SEVEN_DAY_MIN_FREE_RATIO = 0.07;
44
+ export const FIVE_HOUR_MIN_FREE_RATIO = 0.25;
45
+ export const SEVEN_DAY_MIN_FREE_RATIO = 0.03;
46
46
 
47
47
  export const selectWeightedCandidate = <Entry>(
48
48
  eligible: Entry[],
@@ -28,8 +28,8 @@ export type OauthTokenSelectResult = {
28
28
  selected: OauthTokenCandidate | null;
29
29
  metrics: OauthTokenCandidateMetrics[];
30
30
  };
31
- export declare const FIVE_HOUR_MIN_FREE_RATIO = 0.6;
32
- export declare const SEVEN_DAY_MIN_FREE_RATIO = 0.07;
31
+ export declare const FIVE_HOUR_MIN_FREE_RATIO = 0.25;
32
+ export declare const SEVEN_DAY_MIN_FREE_RATIO = 0.03;
33
33
  export declare const selectWeightedCandidate: <Entry>(eligible: Entry[], candidateOf: (entry: Entry) => OauthTokenCandidate, deterministicBest: Entry, random: SelectionRandom) => Entry;
34
34
  export declare class OauthTokenSelectUseCase {
35
35
  run: (candidates: OauthTokenCandidate[], nowEpochSeconds: number, random?: SelectionRandom) => OauthTokenSelectResult;
@@ -1 +1 @@
1
- {"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAC3C,UAAU,KAAK,EAAE,EACjB,aAAa,CAAC,KAAK,EAAE,KAAK,KAAK,mBAAmB,EAClD,mBAAmB,KAAK,EACxB,QAAQ,eAAe,KACtB,KAoBF,CAAC;AAEF,qBAAa,uBAAuB;IAClC,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,sBAAsB,CA2BvB;IAEF,OAAO,CAAC,QAAQ,CAiCd;IAEF,OAAO,CAAC,eAAe,CAuBrB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,gBAAgB,CActB;IAEF,OAAO,CAAC,aAAa,CAGwC;IAE7D,OAAO,CAAC,wBAAwB,CAG9B;IAEF,OAAO,CAAC,SAAS,CAAsD;CACxE"}
1
+ {"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAC3C,UAAU,KAAK,EAAE,EACjB,aAAa,CAAC,KAAK,EAAE,KAAK,KAAK,mBAAmB,EAClD,mBAAmB,KAAK,EACxB,QAAQ,eAAe,KACtB,KAoBF,CAAC;AAEF,qBAAa,uBAAuB;IAClC,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,sBAAsB,CA2BvB;IAEF,OAAO,CAAC,QAAQ,CAiCd;IAEF,OAAO,CAAC,eAAe,CAuBrB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,gBAAgB,CActB;IAEF,OAAO,CAAC,aAAa,CAGwC;IAE7D,OAAO,CAAC,wBAAwB,CAG9B;IAEF,OAAO,CAAC,SAAS,CAAsD;CACxE"}