github-issue-tower-defence-management 1.93.0 → 1.94.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.
@@ -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-BSNMvjcB.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-BJixkRxv.css">
7
+ <script type="module" crossorigin src="/assets/index-DoJ05EuW.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-C5nxEEOu.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.93.0",
3
+ "version": "1.94.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -0,0 +1,96 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const repoRoot = path.resolve(__dirname, '..');
7
+
8
+ const sourceDir = path.join(
9
+ repoRoot,
10
+ 'src',
11
+ 'adapter',
12
+ 'entry-points',
13
+ 'console',
14
+ 'ui-dist',
15
+ );
16
+ const targetDir = path.join(
17
+ repoRoot,
18
+ 'bin',
19
+ 'adapter',
20
+ 'entry-points',
21
+ 'console',
22
+ 'ui-dist',
23
+ );
24
+
25
+ const collectRelativeFiles = (baseDir) => {
26
+ const walk = (currentDir) => {
27
+ const entries = readdirSync(currentDir);
28
+ return entries.flatMap((entry) => {
29
+ const absolutePath = path.join(currentDir, entry);
30
+ if (statSync(absolutePath).isDirectory()) {
31
+ return walk(absolutePath);
32
+ }
33
+ return [path.relative(baseDir, absolutePath)];
34
+ });
35
+ };
36
+ return walk(baseDir).sort();
37
+ };
38
+
39
+ if (!existsSync(sourceDir)) {
40
+ throw new Error(
41
+ `Console UI source build output not found at ${sourceDir}. Run "npm run build:console-ui" first.`,
42
+ );
43
+ }
44
+
45
+ if (!existsSync(targetDir)) {
46
+ throw new Error(
47
+ `Served console UI bundle not found at ${targetDir}. Run "node scripts/copyConsoleUiDist.mjs" to regenerate it.`,
48
+ );
49
+ }
50
+
51
+ const sourceFiles = collectRelativeFiles(sourceDir);
52
+ const targetFiles = collectRelativeFiles(targetDir);
53
+
54
+ const mismatches = [];
55
+
56
+ const sourceFileSet = new Set(sourceFiles);
57
+ const targetFileSet = new Set(targetFiles);
58
+
59
+ for (const relativePath of sourceFiles) {
60
+ if (!targetFileSet.has(relativePath)) {
61
+ mismatches.push(`missing in served bundle: ${relativePath}`);
62
+ }
63
+ }
64
+
65
+ for (const relativePath of targetFiles) {
66
+ if (!sourceFileSet.has(relativePath)) {
67
+ mismatches.push(`unexpected in served bundle: ${relativePath}`);
68
+ }
69
+ }
70
+
71
+ for (const relativePath of sourceFiles) {
72
+ if (!targetFileSet.has(relativePath)) {
73
+ continue;
74
+ }
75
+ const sourceContent = readFileSync(path.join(sourceDir, relativePath));
76
+ const targetContent = readFileSync(path.join(targetDir, relativePath));
77
+ if (!sourceContent.equals(targetContent)) {
78
+ mismatches.push(`content differs: ${relativePath}`);
79
+ }
80
+ }
81
+
82
+ if (mismatches.length > 0) {
83
+ throw new Error(
84
+ [
85
+ 'Served console UI bundle is stale and does not match the source build.',
86
+ `Source: ${sourceDir}`,
87
+ `Served: ${targetDir}`,
88
+ 'Run "npm run build:console-ui && node scripts/copyConsoleUiDist.mjs" and commit the result.',
89
+ ...mismatches.map((entry) => ` - ${entry}`),
90
+ ].join('\n'),
91
+ );
92
+ }
93
+
94
+ process.stdout.write(
95
+ `Served console UI bundle matches source build (${sourceFiles.length} files).\n`,
96
+ );
@@ -76,11 +76,14 @@ type ServeConsoleOptions = {
76
76
  port?: string;
77
77
  consoleDataOutputDir?: string;
78
78
  inTmuxDataDir?: string;
79
+ dashboardDir?: string;
79
80
  };
80
81
 
81
82
  const DEFAULT_IN_TMUX_DATA_DIR =
82
83
  '/home/hiromi/0_workspaces/workspace1/jsonpub/in-tmux-by-human';
83
84
 
85
+ const DEFAULT_DASHBOARD_DIR = '/home/hiromi/0_workspaces/workspace1/jsonpub';
86
+
84
87
  type SelectOauthTokenOptions = {
85
88
  tokenListJsonPath?: string;
86
89
  cacheDir?: string;
@@ -599,6 +602,10 @@ program
599
602
  '--inTmuxDataDir <path>',
600
603
  `Directory containing the flat in-tmux-by-human static JSON files served at /in-tmux-by-human/*.json (default: ${DEFAULT_IN_TMUX_DATA_DIR})`,
601
604
  )
605
+ .option(
606
+ '--dashboardDir <path>',
607
+ `Directory containing the dashboard HTML fragment tdpm.txt served unauthenticated at /tdpm.txt (default: ${DEFAULT_DASHBOARD_DIR})`,
608
+ )
602
609
  .action(async (options: ServeConsoleOptions) => {
603
610
  const config = loadConfigFile(options.configFilePath);
604
611
 
@@ -701,12 +708,14 @@ program
701
708
  const uiDistDir = path.join(__dirname, '..', 'console', 'ui-dist');
702
709
  const consoleDataOutputDir = options.consoleDataOutputDir ?? null;
703
710
  const inTmuxDataDir = options.inTmuxDataDir ?? DEFAULT_IN_TMUX_DATA_DIR;
711
+ const dashboardDir = options.dashboardDir ?? DEFAULT_DASHBOARD_DIR;
704
712
 
705
713
  await startConsoleServer({
706
714
  accessToken,
707
715
  uiDistDir,
708
716
  consoleDataOutputDir,
709
717
  inTmuxDataDir,
718
+ dashboardDir,
710
719
  issueRepository,
711
720
  resolveProject,
712
721
  issueTitleStateCache: new IssueTitleStateCache(),
@@ -12,6 +12,7 @@ import {
12
12
  isConsoleAppRoute,
13
13
  extractProvidedToken,
14
14
  resolveFlatInTmuxFilePath,
15
+ resolveDashboardFilePath,
15
16
  startConsoleServer,
16
17
  } from './consoleServer';
17
18
  import { IssueTitleStateCache } from './consoleReadApi';
@@ -177,6 +178,7 @@ describe('consoleServer integration', () => {
177
178
  uiDistDir: path.join(tmpDir, 'ui-dist'),
178
179
  consoleDataOutputDir: null,
179
180
  inTmuxDataDir: null,
181
+ dashboardDir: null,
180
182
  port: 0,
181
183
  });
182
184
  const address = server.address();
@@ -193,6 +195,7 @@ describe('consoleServer integration', () => {
193
195
  uiDistDir: path.join(tmpDir, 'missing-ui-dist'),
194
196
  consoleDataOutputDir: null,
195
197
  inTmuxDataDir: null,
198
+ dashboardDir: null,
196
199
  port: 0,
197
200
  });
198
201
  try {
@@ -218,6 +221,7 @@ describe('consoleServer integration', () => {
218
221
  uiDistDir: path.join(tmpDir, 'missing-ui-dist'),
219
222
  consoleDataOutputDir: null,
220
223
  inTmuxDataDir: null,
224
+ dashboardDir: null,
221
225
  port: 0,
222
226
  });
223
227
  try {
@@ -247,6 +251,7 @@ describe('consoleServer integration', () => {
247
251
  uiDistDir,
248
252
  consoleDataOutputDir: null,
249
253
  inTmuxDataDir: null,
254
+ dashboardDir: null,
250
255
  port: 0,
251
256
  });
252
257
  try {
@@ -278,6 +283,7 @@ describe('consoleServer integration', () => {
278
283
  uiDistDir,
279
284
  consoleDataOutputDir: null,
280
285
  inTmuxDataDir: null,
286
+ dashboardDir: null,
281
287
  port: 0,
282
288
  });
283
289
  try {
@@ -306,6 +312,7 @@ describe('consoleServer integration', () => {
306
312
  uiDistDir: path.join(tmpDir, 'missing-ui-dist'),
307
313
  consoleDataOutputDir: null,
308
314
  inTmuxDataDir: null,
315
+ dashboardDir: null,
309
316
  port: 0,
310
317
  });
311
318
  try {
@@ -328,6 +335,7 @@ describe('consoleServer integration', () => {
328
335
  uiDistDir,
329
336
  consoleDataOutputDir: null,
330
337
  inTmuxDataDir: null,
338
+ dashboardDir: null,
331
339
  port: 0,
332
340
  });
333
341
  try {
@@ -353,6 +361,7 @@ describe('consoleServer integration', () => {
353
361
  uiDistDir: path.join(tmpDir, 'ui-dist'),
354
362
  consoleDataOutputDir: null,
355
363
  inTmuxDataDir: null,
364
+ dashboardDir: null,
356
365
  port: 0,
357
366
  });
358
367
  try {
@@ -490,6 +499,7 @@ describe('consoleServer new routes integration', () => {
490
499
  uiDistDir: path.join(tmpDir, 'ui-dist'),
491
500
  consoleDataOutputDir: dataDir,
492
501
  inTmuxDataDir: null,
502
+ dashboardDir: null,
493
503
  port: 0,
494
504
  });
495
505
  try {
@@ -526,6 +536,7 @@ describe('consoleServer new routes integration', () => {
526
536
  uiDistDir: path.join(tmpDir, 'ui-dist'),
527
537
  consoleDataOutputDir: null,
528
538
  inTmuxDataDir: null,
539
+ dashboardDir: null,
529
540
  issueRepository,
530
541
  issueTitleStateCache: new IssueTitleStateCache(),
531
542
  port: 0,
@@ -559,6 +570,7 @@ describe('consoleServer new routes integration', () => {
559
570
  uiDistDir: path.join(tmpDir, 'ui-dist'),
560
571
  consoleDataOutputDir: null,
561
572
  inTmuxDataDir: null,
573
+ dashboardDir: null,
562
574
  issueRepository,
563
575
  resolveProject: async (pjcode) =>
564
576
  pjcode === 'umino' ? { pjcode, project: buildProject() } : null,
@@ -607,6 +619,7 @@ describe('consoleServer new routes integration', () => {
607
619
  uiDistDir: path.join(tmpDir, 'ui-dist'),
608
620
  consoleDataOutputDir: dataDir,
609
621
  inTmuxDataDir: null,
622
+ dashboardDir: null,
610
623
  issueRepository,
611
624
  resolveProject: async (pjcode) =>
612
625
  pjcode === 'umino' ? { pjcode, project: buildProject() } : null,
@@ -645,6 +658,7 @@ describe('consoleServer new routes integration', () => {
645
658
  uiDistDir: path.join(tmpDir, 'ui-dist'),
646
659
  consoleDataOutputDir: null,
647
660
  inTmuxDataDir: null,
661
+ dashboardDir: null,
648
662
  issueRepository,
649
663
  resolveProject: async (pjcode) =>
650
664
  pjcode === 'umino' ? { pjcode, project: buildProject() } : null,
@@ -695,6 +709,7 @@ describe('consoleServer new routes integration', () => {
695
709
  uiDistDir: path.join(tmpDir, 'ui-dist'),
696
710
  consoleDataOutputDir: null,
697
711
  inTmuxDataDir: null,
712
+ dashboardDir: null,
698
713
  port: 0,
699
714
  });
700
715
  try {
@@ -823,6 +838,7 @@ describe('consoleServer flat in-tmux-by-human route integration', () => {
823
838
  uiDistDir: path.join(tmpDir, 'ui-dist'),
824
839
  consoleDataOutputDir: null,
825
840
  inTmuxDataDir,
841
+ dashboardDir: null,
826
842
  port: 0,
827
843
  });
828
844
  return { server, tmpDir, inTmuxDataDir };
@@ -936,6 +952,7 @@ describe('consoleServer flat in-tmux-by-human route integration', () => {
936
952
  uiDistDir: path.join(tmpDir, 'ui-dist'),
937
953
  consoleDataOutputDir: null,
938
954
  inTmuxDataDir: null,
955
+ dashboardDir: null,
939
956
  port: 0,
940
957
  });
941
958
  try {
@@ -950,3 +967,167 @@ describe('consoleServer flat in-tmux-by-human route integration', () => {
950
967
  }
951
968
  });
952
969
  });
970
+
971
+ describe('resolveDashboardFilePath', () => {
972
+ const baseDir = path.join(os.tmpdir(), 'dashboard-data');
973
+
974
+ it('resolves /tdpm.txt under the dashboard dir', () => {
975
+ expect(resolveDashboardFilePath(baseDir, '/tdpm.txt')).toBe(
976
+ path.join(path.resolve(baseDir), 'tdpm.txt'),
977
+ );
978
+ });
979
+
980
+ it('returns null for any other path', () => {
981
+ expect(resolveDashboardFilePath(baseDir, '/tdpm.html')).toBeNull();
982
+ expect(resolveDashboardFilePath(baseDir, '/other.txt')).toBeNull();
983
+ expect(resolveDashboardFilePath(baseDir, '/')).toBeNull();
984
+ expect(resolveDashboardFilePath(baseDir, '/sub/tdpm.txt')).toBeNull();
985
+ });
986
+ });
987
+
988
+ describe('consoleServer dashboard /tdpm.txt route integration', () => {
989
+ const testToken = 'integration-test-token-value';
990
+
991
+ const requestServer = (
992
+ server: http.Server,
993
+ requestPath: string,
994
+ method = 'GET',
995
+ ): Promise<{
996
+ statusCode: number;
997
+ body: string;
998
+ cacheControl: string | undefined;
999
+ contentType: string | undefined;
1000
+ contentLength: string | undefined;
1001
+ transferEncoding: string | undefined;
1002
+ }> => {
1003
+ const address = server.address();
1004
+ if (address === null || typeof address === 'string') {
1005
+ throw new Error('server is not listening on a TCP port');
1006
+ }
1007
+ const port = address.port;
1008
+ return new Promise((resolve, reject) => {
1009
+ const httpRequest = http.request(
1010
+ { host: '127.0.0.1', port, path: requestPath, method },
1011
+ (response) => {
1012
+ const chunks: Uint8Array[] = [];
1013
+ response.on('data', (chunk: Uint8Array) => chunks.push(chunk));
1014
+ response.on('end', () => {
1015
+ resolve({
1016
+ statusCode: response.statusCode ?? 0,
1017
+ body: Buffer.concat(chunks).toString('utf-8'),
1018
+ cacheControl: response.headers['cache-control'],
1019
+ contentType: response.headers['content-type'],
1020
+ contentLength: response.headers['content-length'],
1021
+ transferEncoding: response.headers['transfer-encoding'],
1022
+ });
1023
+ });
1024
+ },
1025
+ );
1026
+ httpRequest.on('error', reject);
1027
+ httpRequest.end();
1028
+ });
1029
+ };
1030
+
1031
+ const closeServer = (server: http.Server): Promise<void> =>
1032
+ new Promise((resolve, reject) => {
1033
+ server.close((error) => {
1034
+ if (error) {
1035
+ reject(error);
1036
+ return;
1037
+ }
1038
+ resolve();
1039
+ });
1040
+ });
1041
+
1042
+ const dashboardRaw =
1043
+ '<tt>MEM&nbsp;30%</tt><br>\n<tt>pj&nbsp;unr&nbsp;tdo</tt><br>\n';
1044
+
1045
+ const startWithDashboard = async (): Promise<{
1046
+ server: http.Server;
1047
+ tmpDir: string;
1048
+ }> => {
1049
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1050
+ fs.writeFileSync(path.join(tmpDir, 'tdpm.txt'), dashboardRaw);
1051
+ fs.writeFileSync(path.join(tmpDir, 'secret.txt'), 'secret content');
1052
+ const server = await startConsoleServer({
1053
+ accessToken: testToken,
1054
+ uiDistDir: path.join(tmpDir, 'ui-dist'),
1055
+ consoleDataOutputDir: null,
1056
+ inTmuxDataDir: null,
1057
+ dashboardDir: tmpDir,
1058
+ port: 0,
1059
+ });
1060
+ return { server, tmpDir };
1061
+ };
1062
+
1063
+ it('serves /tdpm.txt without a token, byte-identical, as text/html with an explicit Content-Length and no chunked encoding', async () => {
1064
+ const { server, tmpDir } = await startWithDashboard();
1065
+ try {
1066
+ const response = await requestServer(server, '/tdpm.txt');
1067
+ expect(response.statusCode).toBe(200);
1068
+ expect(response.body).toBe(dashboardRaw);
1069
+ expect(response.contentType).toBe('text/html; charset=utf-8');
1070
+ expect(response.contentLength).toBe(
1071
+ String(Buffer.byteLength(dashboardRaw)),
1072
+ );
1073
+ expect(response.transferEncoding).toBeUndefined();
1074
+ expect(response.cacheControl).toBe('no-store');
1075
+ } finally {
1076
+ await closeServer(server);
1077
+ fs.rmSync(tmpDir, { recursive: true, force: true });
1078
+ }
1079
+ });
1080
+
1081
+ it('returns 404 for /tdpm.txt when the file is absent', async () => {
1082
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1083
+ const server = await startConsoleServer({
1084
+ accessToken: testToken,
1085
+ uiDistDir: path.join(tmpDir, 'ui-dist'),
1086
+ consoleDataOutputDir: null,
1087
+ inTmuxDataDir: null,
1088
+ dashboardDir: tmpDir,
1089
+ port: 0,
1090
+ });
1091
+ try {
1092
+ const response = await requestServer(server, '/tdpm.txt');
1093
+ expect(response.statusCode).toBe(404);
1094
+ } finally {
1095
+ await closeServer(server);
1096
+ fs.rmSync(tmpDir, { recursive: true, force: true });
1097
+ }
1098
+ });
1099
+
1100
+ it('returns 404 for /tdpm.txt when dashboardDir is null', async () => {
1101
+ const { server, tmpDir } = await (async () => {
1102
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1103
+ fs.writeFileSync(path.join(dir, 'tdpm.txt'), dashboardRaw);
1104
+ const srv = await startConsoleServer({
1105
+ accessToken: testToken,
1106
+ uiDistDir: path.join(dir, 'ui-dist'),
1107
+ consoleDataOutputDir: null,
1108
+ inTmuxDataDir: null,
1109
+ dashboardDir: null,
1110
+ port: 0,
1111
+ });
1112
+ return { server: srv, tmpDir: dir };
1113
+ })();
1114
+ try {
1115
+ const response = await requestServer(server, '/tdpm.txt');
1116
+ expect(response.statusCode).toBe(404);
1117
+ } finally {
1118
+ await closeServer(server);
1119
+ fs.rmSync(tmpDir, { recursive: true, force: true });
1120
+ }
1121
+ });
1122
+
1123
+ it('rejects a non-GET method on /tdpm.txt with 404', async () => {
1124
+ const { server, tmpDir } = await startWithDashboard();
1125
+ try {
1126
+ const response = await requestServer(server, '/tdpm.txt', 'POST');
1127
+ expect(response.statusCode).toBe(404);
1128
+ } finally {
1129
+ await closeServer(server);
1130
+ fs.rmSync(tmpDir, { recursive: true, force: true });
1131
+ }
1132
+ });
1133
+ });
@@ -155,6 +155,7 @@ export type ConsoleServerOptions = {
155
155
  uiDistDir: string;
156
156
  consoleDataOutputDir: string | null;
157
157
  inTmuxDataDir: string | null;
158
+ dashboardDir: string | null;
158
159
  issueRepository?: IssueRepository | null;
159
160
  resolveProject?: ConsoleProjectResolver | null;
160
161
  issueTitleStateCache?: IssueTitleStateCache | null;
@@ -164,6 +165,26 @@ const FLAT_IN_TMUX_PREFIX = '/in-tmux-by-human/';
164
165
 
165
166
  const FLAT_IN_TMUX_FILE = /^[A-Za-z0-9._-]+\.json$/;
166
167
 
168
+ export const DASHBOARD_REQUEST_PATH = '/tdpm.txt';
169
+
170
+ const DASHBOARD_FILE_NAME = 'tdpm.txt';
171
+
172
+ export const resolveDashboardFilePath = (
173
+ dashboardDir: string,
174
+ requestPath: string,
175
+ ): string | null => {
176
+ if (requestPath !== DASHBOARD_REQUEST_PATH) {
177
+ return null;
178
+ }
179
+ const candidate = path.join(dashboardDir, DASHBOARD_FILE_NAME);
180
+ const resolvedRoot = path.resolve(dashboardDir);
181
+ const resolvedCandidate = path.resolve(candidate);
182
+ if (resolvedCandidate !== path.join(resolvedRoot, DASHBOARD_FILE_NAME)) {
183
+ return null;
184
+ }
185
+ return resolvedCandidate;
186
+ };
187
+
167
188
  export const resolveFlatInTmuxFilePath = (
168
189
  inTmuxDataDir: string,
169
190
  requestPath: string,
@@ -442,6 +463,35 @@ export const handleConsoleRequest = async (
442
463
  return;
443
464
  }
444
465
 
466
+ if (requestPath === DASHBOARD_REQUEST_PATH) {
467
+ const method = (request.method ?? 'GET').toUpperCase();
468
+ if (method !== 'GET') {
469
+ sendNotFound(response);
470
+ return;
471
+ }
472
+ if (options.dashboardDir === null) {
473
+ sendNotFound(response);
474
+ return;
475
+ }
476
+ const dashboardFilePath = resolveDashboardFilePath(
477
+ options.dashboardDir,
478
+ requestPath,
479
+ );
480
+ const dashboardContent =
481
+ dashboardFilePath === null ? null : readStaticFile(dashboardFilePath);
482
+ if (dashboardContent === null) {
483
+ sendNotFound(response);
484
+ return;
485
+ }
486
+ response.writeHead(200, {
487
+ 'Content-Type': 'text/html; charset=utf-8',
488
+ 'Cache-Control': 'no-store',
489
+ 'Content-Length': String(dashboardContent.length),
490
+ });
491
+ response.end(dashboardContent);
492
+ return;
493
+ }
494
+
445
495
  if (requiresToken(requestPath)) {
446
496
  const providedToken = extractProvidedToken(
447
497
  requestUrl.searchParams.get('k'),
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AA+FzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAkGzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
@@ -14,10 +14,13 @@ export type ConsoleServerOptions = {
14
14
  uiDistDir: string;
15
15
  consoleDataOutputDir: string | null;
16
16
  inTmuxDataDir: string | null;
17
+ dashboardDir: string | null;
17
18
  issueRepository?: IssueRepository | null;
18
19
  resolveProject?: ConsoleProjectResolver | null;
19
20
  issueTitleStateCache?: IssueTitleStateCache | null;
20
21
  };
22
+ export declare const DASHBOARD_REQUEST_PATH = "/tdpm.txt";
23
+ export declare const resolveDashboardFilePath: (dashboardDir: string, requestPath: string) => string | null;
21
24
  export declare const resolveFlatInTmuxFilePath: (inTmuxDataDir: string, requestPath: string) => string | null;
22
25
  export declare const handleConsoleRequest: (options: ConsoleServerOptions, request: http.IncomingMessage, response: http.ServerResponse) => Promise<void>;
23
26
  export declare const createConsoleServer: (options: ConsoleServerOptions) => http.Server;
@@ -1 +1 @@
1
- {"version":3,"file":"consoleServer.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,6DAA6D,CAAC;AAM9F,OAAO,EACL,oBAAoB,EAOrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,sBAAsB,EAKvB,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAmCjD,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,OAGiB,CAAC;AAEtE,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,OAGrB,CAAC;AAIhC,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,KAAG,OAmBvD,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,eAAe,MAAM,EACrB,eAAe,MAAM,GAAG,IAAI,KAC3B,OAAoE,CAAC;AAExE,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EACpC,aAAa,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KACzC,MAAM,GAAG,IAQX,CAAC;AAuCF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,cAAc,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC/C,oBAAoB,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACpD,CAAC;AAMF,eAAO,MAAM,yBAAyB,GACpC,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,MAAM,GAAG,IAeX,CAAC;AAuPF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,oBAAoB,EAC7B,SAAS,IAAI,CAAC,eAAe,EAC7B,UAAU,IAAI,CAAC,cAAc,KAC5B,OAAO,CAAC,IAAI,CAoDd,CAAC;AAcF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,oBAAoB,KAC5B,IAAI,CAAC,MAMJ,CAAC;AAEL,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,GAAG;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,yBAAyB,KACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAQlB,CAAC"}
1
+ {"version":3,"file":"consoleServer.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,6DAA6D,CAAC;AAM9F,OAAO,EACL,oBAAoB,EAOrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,sBAAsB,EAKvB,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAmCjD,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,OAGiB,CAAC;AAEtE,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,OAGrB,CAAC;AAIhC,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,KAAG,OAmBvD,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,eAAe,MAAM,EACrB,eAAe,MAAM,GAAG,IAAI,KAC3B,OAAoE,CAAC;AAExE,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EACpC,aAAa,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KACzC,MAAM,GAAG,IAQX,CAAC;AAuCF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,cAAc,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC/C,oBAAoB,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACpD,CAAC;AAMF,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAIlD,eAAO,MAAM,wBAAwB,GACnC,cAAc,MAAM,EACpB,aAAa,MAAM,KAClB,MAAM,GAAG,IAWX,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,MAAM,GAAG,IAeX,CAAC;AAuPF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,oBAAoB,EAC7B,SAAS,IAAI,CAAC,eAAe,EAC7B,UAAU,IAAI,CAAC,cAAc,KAC5B,OAAO,CAAC,IAAI,CAiFd,CAAC;AAcF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,oBAAoB,KAC5B,IAAI,CAAC,MAMJ,CAAC;AAEL,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,GAAG;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,yBAAyB,KACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAQlB,CAAC"}
@@ -1 +0,0 @@
1
- /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-input:#e5e5e5;--color-ring:#0a0a0a;--color-background:#fff;--color-foreground:#0a0a0a;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary:#f5f5f5;--color-secondary-foreground:#171717;--color-accent:#f5f5f5;--color-accent-foreground:#171717}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.inline-flex{display:inline-flex}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-input{border-color:var(--color-input)}.border-transparent{border-color:#0000}.bg-background{background-color:var(--color-background)}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-foreground{color:var(--color-foreground)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.lowercase{text-transform:lowercase}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-primary\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary) 90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:#f5f5f5cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--color-secondary) 80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}}body{color:#e6edf3;background-color:#0d1117;margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}.console-app{flex-direction:column;max-width:920px;margin:0 auto;display:flex}.console-tabbar{background:#161b22;border-bottom:2px solid #30363d;align-items:stretch;gap:0;min-height:42px;padding:0 8px;display:flex}.console-tab{color:#8b949e;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;margin-bottom:-2px;padding:10px 14px;font-size:13px;font-weight:500;line-height:1.2;text-decoration:none;display:inline-flex}.console-tab:hover{color:#e6edf3}.console-tab[data-active=true]{color:#e6edf3;border-bottom-color:#2f81f7;font-weight:700}.console-tab-badge{text-align:center;color:#e6edf3;background:#484f58;border-radius:20px;min-width:20px;padding:1px 7px;font-size:11px;font-weight:700;line-height:1.5}.console-tab-badge[data-zero=true]{color:#8b949e;background:#30363d}.console-tab-pjname{color:#8b949e;align-self:center;margin-left:auto;padding:0 8px;font-size:11.5px}.console-tab-geninfo{color:#8b949e;align-self:center;padding:0 4px;font-size:11px}.console-tab-count-heading{color:#8b949e;margin:0;padding:12px 18px 0;font-size:13px}.console-list{margin:0;padding:12px 18px 18px;list-style:none}.console-list-group{list-style:none}.console-item-row .console-item-icon{flex:none;margin-top:3px}.console-group-header{background:#0b0f14;border-bottom:1px solid #21262d;justify-content:space-between;align-items:center;padding:6px 12px;display:flex}.console-storytag{align-items:center;gap:8px;font-size:13px;font-weight:700;display:inline-flex}.console-story-dot{border-radius:999px;width:10px;height:10px;display:inline-block}.console-group-count{color:#8b949e;font-size:12px}.console-item-row{color:#e6edf3;text-align:left;cursor:pointer;background:#161b22;border:1px solid #30363d;border-radius:8px;align-items:flex-start;gap:14px;width:100%;margin-bottom:10px;padding:12px 16px;display:flex}.console-item-row:hover{background:#1a2029;border-color:#484f58}.console-item-row[data-active=true]{background:#1a2029;border-color:#4493f8}.console-item-meta{flex:1;min-width:0}.console-item-title{font-size:14.5px;font-weight:600;display:block}.console-item-sub{color:#8b949e;margin-top:3px;font-size:12.5px;display:block}.console-item-pill{color:#8b949e;border:1px solid #30363d;border-radius:20px;margin-right:6px;padding:1px 8px;font-size:11px;display:inline-block}.console-item-createdat{color:#8b949e;cursor:help}.console-list-message{color:#8b949e;padding:16px;font-size:14px}.console-list-empty{text-align:center;color:#8b949e;padding:40px;font-size:14px}.console-list-error,.console-comment-error,.console-files-error,.console-commits-error,.console-detail-body-error{color:#f85149}.console-detail{flex-direction:column;gap:12px;padding:16px;display:flex}.console-detail-title{align-items:center;gap:8px;margin:0;font-size:20px;display:flex}.console-detail-title-text{flex:1}.console-detail-number{color:#8b949e;font-weight:400}.console-detail-closed-label{color:#a371f7;font-size:13px}.console-detail-subbar{align-items:center;gap:12px;font-size:13px;display:flex}.console-detail-link{color:#4493f8}.console-detail-repo{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-detail-pill,.console-label-chip,.console-detail-status-chip{border:1px solid #30363d;border-radius:999px;padding:2px 8px;font-size:12px;display:inline-block}.console-detail-labels{flex-wrap:wrap;gap:6px;display:flex}.console-detail-createdat{color:#8b949e;font-size:12px}.console-panel{border:1px solid #30363d;border-radius:8px;overflow:hidden}.console-panel-header{background:#161b22;justify-content:space-between;align-items:center;padding:6px 12px;display:flex}.console-panel-toggle{color:#e6edf3;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;font-size:14px;font-weight:600;display:inline-flex}.console-panel-body{padding:12px}.console-markdown{word-break:break-word;font-size:14px;line-height:1.5}.console-mermaid-error{color:#f85149;font-size:13px}.console-comment{border-top:1px solid #21262d;padding-top:8px}.console-comment-header{color:#8b949e;gap:8px;font-size:12px;display:flex}.console-comment-author{color:#e6edf3;font-weight:600}.console-files,.console-commits{margin:0;padding:0;list-style:none}.console-file,.console-commit{align-items:center;gap:8px;padding:4px 0;font-size:13px;display:flex}.console-file-badge{text-align:center;border:1px solid;border-radius:4px;width:18px;font-size:11px}.console-file-path,.console-commit-message{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-add,.console-pr-add{color:#3fb950}.console-file-del,.console-pr-del{color:#f85149}.console-commit-sha{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-actionbar{z-index:100;background:#161b22;border-top:2px solid #30363d;padding:10px 16px;position:fixed;bottom:0;left:0;right:0}.console-operation-bar{flex-direction:column;gap:8px;max-width:920px;margin:0 auto;display:flex}.console-op-group{flex-wrap:wrap;gap:8px;display:flex}.console-op-group-review{justify-content:flex-end;align-items:center;gap:10px}.console-op-button{color:#e6edf3;white-space:nowrap;cursor:pointer;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:7px 16px;font-size:13px;font-weight:600}.console-op-button:hover{border-color:#484f58}.console-op-button-approve{color:#fff;background:#238636;border-color:#2ea043}.console-op-button-reject{color:#ffd166;background:#7d5000;border-color:#a06800}.console-op-button-wrong{color:#f85149;background:#3a1518;border-color:#f85149}.console-op-button-unneeded{color:#aab0b8;background:#2a2d31;border-color:#6e7681}.console-op-button-snooze{color:#79c0ff;background:#1c2b4a;border-color:#4493f8}.console-pr-section{border:1px solid #30363d;border-radius:8px;flex-direction:column;gap:10px;padding:12px;display:flex}.console-pr-statbar{color:#8b949e;gap:12px;font-size:12px;display:flex}.console-detail-screen{padding-bottom:140px}.console-panel-open-link{color:#4493f8;font-size:13px;font-weight:400}.console-composer{margin-top:4px}.console-composer-toggle{color:#8b949e;cursor:pointer;background:0 0;border:none;padding:2px 0;font-size:12.5px}.console-composer-toggle:hover{color:#e6edf3}.console-composer-posted{flex-direction:column;gap:8px;margin-top:8px;display:flex}.console-composer-form{margin-top:8px}.console-composer-input{box-sizing:border-box;color:#e6edf3;width:100%;font:inherit;resize:vertical;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:8px;font-size:14px}.console-composer-row{align-items:center;gap:8px;margin-top:6px;display:flex}.console-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #2ea043;border-radius:6px;padding:7px 16px;font-size:13px;font-weight:600}.console-composer-submit:disabled{opacity:.6;cursor:default}.console-composer-status{color:#8b949e;font-size:12px}.console-composer-error{color:#f85149}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}