github-issue-tower-defence-management 1.104.3 → 1.105.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 (80) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +8 -7
  3. package/bin/adapter/entry-points/cli/index.js +21 -13
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/console/{consoleServer.js → webServer.js} +11 -11
  6. package/bin/adapter/entry-points/console/webServer.js.map +1 -0
  7. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +41 -2
  8. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  9. package/bin/adapter/entry-points/handlers/dashboardRowWriter.js +34 -0
  10. package/bin/adapter/entry-points/handlers/dashboardRowWriter.js.map +1 -0
  11. package/bin/adapter/entry-points/handlers/machineStatusWriter.js +60 -0
  12. package/bin/adapter/entry-points/handlers/machineStatusWriter.js.map +1 -0
  13. package/bin/adapter/entry-points/handlers/tokenStatusWriter.js +98 -0
  14. package/bin/adapter/entry-points/handlers/tokenStatusWriter.js.map +1 -0
  15. package/bin/adapter/proxy/RateLimitCache.js +3 -0
  16. package/bin/adapter/proxy/RateLimitCache.js.map +1 -1
  17. package/bin/adapter/repositories/ProcHostMetricsRepository.js +136 -0
  18. package/bin/adapter/repositories/ProcHostMetricsRepository.js.map +1 -0
  19. package/bin/adapter/repositories/ProcTakeOwnershipSpawnRepository.js +131 -0
  20. package/bin/adapter/repositories/ProcTakeOwnershipSpawnRepository.js.map +1 -0
  21. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +93 -8
  22. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
  23. package/bin/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.js +3 -0
  24. package/bin/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.js.map +1 -0
  25. package/bin/domain/usecases/dashboard/GenerateDashboardRowUseCase.js +38 -0
  26. package/bin/domain/usecases/dashboard/GenerateDashboardRowUseCase.js.map +1 -0
  27. package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js +115 -0
  28. package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js.map +1 -0
  29. package/package.json +1 -1
  30. package/src/adapter/entry-points/cli/index.test.ts +74 -21
  31. package/src/adapter/entry-points/cli/index.ts +146 -136
  32. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +2 -2
  33. package/src/adapter/entry-points/console/{consoleServer.test.ts → webServer.test.ts} +32 -32
  34. package/src/adapter/entry-points/console/{consoleServer.ts → webServer.ts} +15 -17
  35. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +52 -0
  36. package/src/adapter/entry-points/handlers/dashboardRowWriter.test.ts +111 -0
  37. package/src/adapter/entry-points/handlers/dashboardRowWriter.ts +51 -0
  38. package/src/adapter/entry-points/handlers/machineStatusWriter.test.ts +100 -0
  39. package/src/adapter/entry-points/handlers/machineStatusWriter.ts +79 -0
  40. package/src/adapter/entry-points/handlers/tokenStatusWriter.test.ts +176 -0
  41. package/src/adapter/entry-points/handlers/tokenStatusWriter.ts +139 -0
  42. package/src/adapter/proxy/RateLimitCache.test.ts +32 -0
  43. package/src/adapter/proxy/RateLimitCache.ts +6 -0
  44. package/src/adapter/repositories/ProcHostMetricsRepository.test.ts +135 -0
  45. package/src/adapter/repositories/ProcHostMetricsRepository.ts +136 -0
  46. package/src/adapter/repositories/ProcTakeOwnershipSpawnRepository.test.ts +130 -0
  47. package/src/adapter/repositories/ProcTakeOwnershipSpawnRepository.ts +118 -0
  48. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +267 -13
  49. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +140 -47
  50. package/src/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.ts +8 -0
  51. package/src/domain/usecases/dashboard/GenerateDashboardRowUseCase.test.ts +159 -0
  52. package/src/domain/usecases/dashboard/GenerateDashboardRowUseCase.ts +72 -0
  53. package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.test.ts +209 -0
  54. package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts +195 -0
  55. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  56. package/types/adapter/entry-points/console/{consoleServer.d.ts → webServer.d.ts} +7 -7
  57. package/types/adapter/entry-points/console/webServer.d.ts.map +1 -0
  58. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  59. package/types/adapter/entry-points/handlers/dashboardRowWriter.d.ts +15 -0
  60. package/types/adapter/entry-points/handlers/dashboardRowWriter.d.ts.map +1 -0
  61. package/types/adapter/entry-points/handlers/machineStatusWriter.d.ts +16 -0
  62. package/types/adapter/entry-points/handlers/machineStatusWriter.d.ts.map +1 -0
  63. package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts +21 -0
  64. package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts.map +1 -0
  65. package/types/adapter/proxy/RateLimitCache.d.ts +2 -0
  66. package/types/adapter/proxy/RateLimitCache.d.ts.map +1 -1
  67. package/types/adapter/repositories/ProcHostMetricsRepository.d.ts +23 -0
  68. package/types/adapter/repositories/ProcHostMetricsRepository.d.ts.map +1 -0
  69. package/types/adapter/repositories/ProcTakeOwnershipSpawnRepository.d.ts +11 -0
  70. package/types/adapter/repositories/ProcTakeOwnershipSpawnRepository.d.ts.map +1 -0
  71. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts +6 -1
  72. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
  73. package/types/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.d.ts +8 -0
  74. package/types/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.d.ts.map +1 -0
  75. package/types/domain/usecases/dashboard/GenerateDashboardRowUseCase.d.ts +19 -0
  76. package/types/domain/usecases/dashboard/GenerateDashboardRowUseCase.d.ts.map +1 -0
  77. package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts +53 -0
  78. package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts.map +1 -0
  79. package/bin/adapter/entry-points/console/consoleServer.js.map +0 -1
  80. package/types/adapter/entry-points/console/consoleServer.d.ts.map +0 -1
@@ -32,10 +32,7 @@ import { GitHubIssueCommentRepository } from '../../repositories/GitHubIssueComm
32
32
  import { FetchWebhookRepository } from '../../repositories/FetchWebhookRepository';
33
33
  import { RevertOrphanedPreparationUseCase } from '../../../domain/usecases/RevertOrphanedPreparationUseCase';
34
34
  import * as path from 'path';
35
- import {
36
- DEFAULT_CONSOLE_PORT,
37
- startConsoleServer,
38
- } from '../console/consoleServer';
35
+ import { DEFAULT_WEB_PORT, startWebServer } from '../console/webServer';
39
36
  import { IssueTitleStateCache } from '../console/consoleReadApi';
40
37
  import {
41
38
  buildPjcodeToProjectUrl,
@@ -73,7 +70,7 @@ type CheckIssueReviewReadinessOptions = {
73
70
  configFilePath: string;
74
71
  };
75
72
 
76
- type ServeConsoleOptions = {
73
+ type ServeWebOptions = {
77
74
  configFilePath: string;
78
75
  port?: string;
79
76
  consoleDataOutputDir?: string;
@@ -596,146 +593,159 @@ program
596
593
  process.stdout.write(`${JSON.stringify(result)}\n`);
597
594
  });
598
595
 
599
- program
600
- .command('serveConsole')
601
- .description('Start the local TDPM Console HTTP server')
602
- .requiredOption(
603
- '--configFilePath <path>',
604
- 'Path to config file for tower defence management',
605
- )
606
- .option(
607
- '--port <number>',
608
- `Port for the console HTTP server (default: ${DEFAULT_CONSOLE_PORT})`,
609
- )
610
- .option(
611
- '--consoleDataOutputDir <path>',
612
- 'Directory where console data files are written and served from',
613
- )
614
- .option(
615
- '--inTmuxDataDir <path>',
616
- `Directory containing the flat in-tmux-by-human static JSON files served at /in-tmux-by-human/*.json (default: ${DEFAULT_IN_TMUX_DATA_DIR})`,
617
- )
618
- .option(
619
- '--dashboardDir <path>',
620
- `Directory containing the dashboard HTML fragment tdpm.txt served unauthenticated at /tdpm.txt (default: ${DEFAULT_DASHBOARD_DIR})`,
621
- )
622
- .action(async (options: ServeConsoleOptions) => {
623
- const config = loadConfigFile(options.configFilePath);
624
-
625
- const accessToken = config.consoleAccessToken;
626
- if (!accessToken) {
596
+ const runServeWeb = async (options: ServeWebOptions): Promise<void> => {
597
+ const config = loadConfigFile(options.configFilePath);
598
+
599
+ const accessToken = config.consoleAccessToken;
600
+ if (!accessToken) {
601
+ console.error(
602
+ 'consoleAccessToken is required. Provide it via the config file.',
603
+ );
604
+ process.exit(1);
605
+ }
606
+
607
+ let port = DEFAULT_WEB_PORT;
608
+ if (options.port !== undefined) {
609
+ const parsedPort = Number(options.port);
610
+ if (
611
+ !Number.isFinite(parsedPort) ||
612
+ !Number.isInteger(parsedPort) ||
613
+ parsedPort <= 0 ||
614
+ parsedPort > 65535
615
+ ) {
627
616
  console.error(
628
- 'consoleAccessToken is required. Provide it via the config file.',
617
+ 'Invalid value for --port. It must be a positive integer between 1 and 65535.',
629
618
  );
630
619
  process.exit(1);
631
620
  }
632
-
633
- let port = DEFAULT_CONSOLE_PORT;
634
- if (options.port !== undefined) {
635
- const parsedPort = Number(options.port);
636
- if (
637
- !Number.isFinite(parsedPort) ||
638
- !Number.isInteger(parsedPort) ||
639
- parsedPort <= 0 ||
640
- parsedPort > 65535
641
- ) {
621
+ port = parsedPort;
622
+ }
623
+
624
+ const token = process.env.GH_TOKEN;
625
+ if (!token) {
626
+ console.error('GH_TOKEN environment variable is required');
627
+ process.exit(1);
628
+ }
629
+
630
+ const projectUrl = config.projectUrl;
631
+ if (!projectUrl) {
632
+ console.error(
633
+ 'projectUrl is required. Provide it via the config file or project README.',
634
+ );
635
+ process.exit(1);
636
+ }
637
+
638
+ const projectName = config.projectName ?? 'default';
639
+ const localStorageRepository = new LocalStorageRepository();
640
+ const cachePath = `./tmp/cache/${projectName}`;
641
+ const localStorageCacheRepository = new LocalStorageCacheRepository(
642
+ localStorageRepository,
643
+ cachePath,
644
+ );
645
+ const githubRepositoryParams = buildGithubRepositoryParams(
646
+ localStorageRepository,
647
+ token,
648
+ );
649
+ const projectRepository = new GraphqlProjectRepository(
650
+ ...githubRepositoryParams,
651
+ );
652
+ const apiV3IssueRepository = new ApiV3IssueRepository(
653
+ ...githubRepositoryParams,
654
+ );
655
+ const restIssueRepository = new RestIssueRepository(
656
+ ...githubRepositoryParams,
657
+ );
658
+ const graphqlProjectItemRepository = new GraphqlProjectItemRepository(
659
+ ...githubRepositoryParams,
660
+ );
661
+ const issueRepository = new ApiV3CheerioRestIssueRepository(
662
+ apiV3IssueRepository,
663
+ restIssueRepository,
664
+ graphqlProjectItemRepository,
665
+ localStorageCacheRepository,
666
+ ...githubRepositoryParams,
667
+ );
668
+
669
+ const pjcodeToProjectUrl = buildPjcodeToProjectUrl(
670
+ projectName,
671
+ projectUrl,
672
+ config.consoleProjects ?? null,
673
+ );
674
+ const resolveProject = createConsoleProjectResolver(
675
+ pjcodeToProjectUrl,
676
+ async (targetProjectUrl: string) => {
677
+ const targetProjectId =
678
+ await projectRepository.findProjectIdByUrl(targetProjectUrl);
679
+ if (!targetProjectId) {
680
+ console.error(`No project found for projectUrl ${targetProjectUrl}`);
681
+ return null;
682
+ }
683
+ const loadedProject = await projectRepository.getProject(targetProjectId);
684
+ if (!loadedProject) {
642
685
  console.error(
643
- 'Invalid value for --port. It must be a positive integer between 1 and 65535.',
686
+ `Failed to load project for projectUrl ${targetProjectUrl}`,
644
687
  );
645
- process.exit(1);
688
+ return null;
646
689
  }
647
- port = parsedPort;
648
- }
649
-
650
- const token = process.env.GH_TOKEN;
651
- if (!token) {
652
- console.error('GH_TOKEN environment variable is required');
653
- process.exit(1);
654
- }
655
-
656
- const projectUrl = config.projectUrl;
657
- if (!projectUrl) {
658
- console.error(
659
- 'projectUrl is required. Provide it via the config file or project README.',
660
- );
661
- process.exit(1);
662
- }
690
+ return loadedProject;
691
+ },
692
+ );
693
+
694
+ const uiDistDir = path.join(__dirname, '..', 'console', 'ui-dist');
695
+ const consoleDataOutputDir = options.consoleDataOutputDir ?? null;
696
+ const inTmuxDataDir = options.inTmuxDataDir ?? DEFAULT_IN_TMUX_DATA_DIR;
697
+ const dashboardDir = options.dashboardDir ?? DEFAULT_DASHBOARD_DIR;
698
+
699
+ await startWebServer({
700
+ accessToken,
701
+ uiDistDir,
702
+ consoleDataOutputDir,
703
+ inTmuxDataDir,
704
+ dashboardDir,
705
+ githubToken: token,
706
+ issueRepository,
707
+ resolveProject,
708
+ issueTitleStateCache: new IssueTitleStateCache(),
709
+ port,
710
+ });
711
+ console.log(`TDPM web server listening on port ${port}`);
712
+ };
663
713
 
664
- const projectName = config.projectName ?? 'default';
665
- const localStorageRepository = new LocalStorageRepository();
666
- const cachePath = `./tmp/cache/${projectName}`;
667
- const localStorageCacheRepository = new LocalStorageCacheRepository(
668
- localStorageRepository,
669
- cachePath,
670
- );
671
- const githubRepositoryParams = buildGithubRepositoryParams(
672
- localStorageRepository,
673
- token,
674
- );
675
- const projectRepository = new GraphqlProjectRepository(
676
- ...githubRepositoryParams,
677
- );
678
- const apiV3IssueRepository = new ApiV3IssueRepository(
679
- ...githubRepositoryParams,
680
- );
681
- const restIssueRepository = new RestIssueRepository(
682
- ...githubRepositoryParams,
683
- );
684
- const graphqlProjectItemRepository = new GraphqlProjectItemRepository(
685
- ...githubRepositoryParams,
686
- );
687
- const issueRepository = new ApiV3CheerioRestIssueRepository(
688
- apiV3IssueRepository,
689
- restIssueRepository,
690
- graphqlProjectItemRepository,
691
- localStorageCacheRepository,
692
- ...githubRepositoryParams,
693
- );
714
+ const addServeWebOptions = (command: Command): Command =>
715
+ command
716
+ .requiredOption(
717
+ '--configFilePath <path>',
718
+ 'Path to config file for tower defence management',
719
+ )
720
+ .option(
721
+ '--port <number>',
722
+ `Port for the web HTTP server (default: ${DEFAULT_WEB_PORT})`,
723
+ )
724
+ .option(
725
+ '--consoleDataOutputDir <path>',
726
+ 'Directory where console data files are written and served from',
727
+ )
728
+ .option(
729
+ '--inTmuxDataDir <path>',
730
+ `Directory containing the flat in-tmux-by-human static JSON files served at /in-tmux-by-human/*.json (default: ${DEFAULT_IN_TMUX_DATA_DIR})`,
731
+ )
732
+ .option(
733
+ '--dashboardDir <path>',
734
+ `Directory containing the dashboard HTML fragment tdpm.txt served unauthenticated at /tdpm.txt (default: ${DEFAULT_DASHBOARD_DIR})`,
735
+ );
736
+
737
+ addServeWebOptions(program.command('serveWeb'))
738
+ .description(
739
+ 'Start the local TDPM web server (console tabs, dashboard, and in-tmux session list)',
740
+ )
741
+ .action(async (options: ServeWebOptions) => {
742
+ await runServeWeb(options);
743
+ });
694
744
 
695
- const pjcodeToProjectUrl = buildPjcodeToProjectUrl(
696
- projectName,
697
- projectUrl,
698
- config.consoleProjects ?? null,
699
- );
700
- const resolveProject = createConsoleProjectResolver(
701
- pjcodeToProjectUrl,
702
- async (targetProjectUrl: string) => {
703
- const targetProjectId =
704
- await projectRepository.findProjectIdByUrl(targetProjectUrl);
705
- if (!targetProjectId) {
706
- console.error(`No project found for projectUrl ${targetProjectUrl}`);
707
- return null;
708
- }
709
- const loadedProject =
710
- await projectRepository.getProject(targetProjectId);
711
- if (!loadedProject) {
712
- console.error(
713
- `Failed to load project for projectUrl ${targetProjectUrl}`,
714
- );
715
- return null;
716
- }
717
- return loadedProject;
718
- },
719
- );
720
-
721
- const uiDistDir = path.join(__dirname, '..', 'console', 'ui-dist');
722
- const consoleDataOutputDir = options.consoleDataOutputDir ?? null;
723
- const inTmuxDataDir = options.inTmuxDataDir ?? DEFAULT_IN_TMUX_DATA_DIR;
724
- const dashboardDir = options.dashboardDir ?? DEFAULT_DASHBOARD_DIR;
725
-
726
- await startConsoleServer({
727
- accessToken,
728
- uiDistDir,
729
- consoleDataOutputDir,
730
- inTmuxDataDir,
731
- dashboardDir,
732
- githubToken: token,
733
- issueRepository,
734
- resolveProject,
735
- issueTitleStateCache: new IssueTitleStateCache(),
736
- port,
737
- });
738
- console.log(`TDPM Console server listening on port ${port}`);
745
+ addServeWebOptions(program.command('serveConsole'))
746
+ .description('Deprecated alias for serveWeb. Use serveWeb instead.')
747
+ .action(async (options: ServeWebOptions) => {
748
+ await runServeWeb(options);
739
749
  });
740
750
 
741
751
  program
@@ -13,7 +13,7 @@ import type {
13
13
  } from '../../../../../domain/usecases/adapter-interfaces/IssueRepository';
14
14
  import type { ConsoleProjectBinding } from '../../consoleOperationApi';
15
15
  import { IssueTitleStateCache } from '../../consoleReadApi';
16
- import { startConsoleServer } from '../../consoleServer';
16
+ import { startWebServer } from '../../webServer';
17
17
 
18
18
  export const CONSOLE_E2E_PJCODE = 'umino';
19
19
  export const CONSOLE_E2E_TOKEN = 'console-e2e-fixture-token-3f9c1a';
@@ -362,7 +362,7 @@ export const startConsoleE2eHarness = async (): Promise<ConsoleE2eHarness> => {
362
362
  ): Promise<ConsoleProjectBinding | null> =>
363
363
  pjcode === CONSOLE_E2E_PJCODE ? { pjcode, project } : null;
364
364
 
365
- const server = await startConsoleServer({
365
+ const server = await startWebServer({
366
366
  accessToken: CONSOLE_E2E_TOKEN,
367
367
  uiDistDir,
368
368
  consoleDataOutputDir,
@@ -4,7 +4,7 @@ import * as os from 'os';
4
4
  import * as path from 'path';
5
5
  import { mock } from 'jest-mock-extended';
6
6
  import {
7
- DEFAULT_CONSOLE_PORT,
7
+ DEFAULT_WEB_PORT,
8
8
  CONSOLE_TOKEN_HEADER,
9
9
  hasDotSegment,
10
10
  requiresToken,
@@ -13,8 +13,8 @@ import {
13
13
  extractProvidedToken,
14
14
  resolveFlatInTmuxFilePath,
15
15
  resolveDashboardFilePath,
16
- startConsoleServer,
17
- } from './consoleServer';
16
+ startWebServer,
17
+ } from './webServer';
18
18
  import type { ImageFetcher } from './consoleImageProxy';
19
19
  import { IssueTitleStateCache } from './consoleReadApi';
20
20
  import { readDoneProjectItemIds } from './consoleDoneStore';
@@ -22,10 +22,10 @@ import { IssueRepository } from '../../../domain/usecases/adapter-interfaces/Iss
22
22
  import { Project } from '../../../domain/entities/Project';
23
23
  import { Issue } from '../../../domain/entities/Issue';
24
24
 
25
- describe('consoleServer pure helpers', () => {
26
- describe('DEFAULT_CONSOLE_PORT', () => {
25
+ describe('webServer pure helpers', () => {
26
+ describe('DEFAULT_WEB_PORT', () => {
27
27
  it('is 9981', () => {
28
- expect(DEFAULT_CONSOLE_PORT).toBe(9981);
28
+ expect(DEFAULT_WEB_PORT).toBe(9981);
29
29
  });
30
30
  });
31
31
 
@@ -123,7 +123,7 @@ describe('consoleServer pure helpers', () => {
123
123
  });
124
124
  });
125
125
 
126
- describe('consoleServer integration', () => {
126
+ describe('webServer integration', () => {
127
127
  const testToken = 'integration-test-token-value';
128
128
 
129
129
  const requestServer = (
@@ -175,7 +175,7 @@ describe('consoleServer integration', () => {
175
175
 
176
176
  it('starts on an ephemeral port and closes gracefully', async () => {
177
177
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
178
- const server = await startConsoleServer({
178
+ const server = await startWebServer({
179
179
  accessToken: testToken,
180
180
  uiDistDir: path.join(tmpDir, 'ui-dist'),
181
181
  consoleDataOutputDir: null,
@@ -192,7 +192,7 @@ describe('consoleServer integration', () => {
192
192
 
193
193
  it('serves the placeholder index without a token when ui-dist is absent', async () => {
194
194
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
195
- const server = await startConsoleServer({
195
+ const server = await startWebServer({
196
196
  accessToken: testToken,
197
197
  uiDistDir: path.join(tmpDir, 'missing-ui-dist'),
198
198
  consoleDataOutputDir: null,
@@ -218,7 +218,7 @@ describe('consoleServer integration', () => {
218
218
 
219
219
  it('returns 404 for a missing non-index file when ui-dist is absent', async () => {
220
220
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
221
- const server = await startConsoleServer({
221
+ const server = await startWebServer({
222
222
  accessToken: testToken,
223
223
  uiDistDir: path.join(tmpDir, 'missing-ui-dist'),
224
224
  consoleDataOutputDir: null,
@@ -248,7 +248,7 @@ describe('consoleServer integration', () => {
248
248
  path.join(uiDistDir, 'assets', 'app.js'),
249
249
  'console.log("app");',
250
250
  );
251
- const server = await startConsoleServer({
251
+ const server = await startWebServer({
252
252
  accessToken: testToken,
253
253
  uiDistDir,
254
254
  consoleDataOutputDir: null,
@@ -280,7 +280,7 @@ describe('consoleServer integration', () => {
280
280
  path.join(uiDistDir, 'index.html'),
281
281
  '<!DOCTYPE html><title>spa</title><div id="root"></div>',
282
282
  );
283
- const server = await startConsoleServer({
283
+ const server = await startWebServer({
284
284
  accessToken: testToken,
285
285
  uiDistDir,
286
286
  consoleDataOutputDir: null,
@@ -309,7 +309,7 @@ describe('consoleServer integration', () => {
309
309
 
310
310
  it('serves the placeholder index for per-project routes when ui-dist is absent', async () => {
311
311
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
312
- const server = await startConsoleServer({
312
+ const server = await startWebServer({
313
313
  accessToken: testToken,
314
314
  uiDistDir: path.join(tmpDir, 'missing-ui-dist'),
315
315
  consoleDataOutputDir: null,
@@ -332,7 +332,7 @@ describe('consoleServer integration', () => {
332
332
  const uiDistDir = path.join(tmpDir, 'ui-dist');
333
333
  fs.mkdirSync(uiDistDir, { recursive: true });
334
334
  fs.writeFileSync(path.join(uiDistDir, '.env'), 'SECRET=should-not-serve');
335
- const server = await startConsoleServer({
335
+ const server = await startWebServer({
336
336
  accessToken: testToken,
337
337
  uiDistDir,
338
338
  consoleDataOutputDir: null,
@@ -358,7 +358,7 @@ describe('consoleServer integration', () => {
358
358
 
359
359
  it('rejects .json and /api/* without a token and passes the gate with a valid token', async () => {
360
360
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
361
- const server = await startConsoleServer({
361
+ const server = await startWebServer({
362
362
  accessToken: testToken,
363
363
  uiDistDir: path.join(tmpDir, 'ui-dist'),
364
364
  consoleDataOutputDir: null,
@@ -403,7 +403,7 @@ describe('consoleServer integration', () => {
403
403
  });
404
404
  });
405
405
 
406
- describe('consoleServer new routes integration', () => {
406
+ describe('webServer new routes integration', () => {
407
407
  const testToken = 'integration-test-token-value';
408
408
 
409
409
  const closeServer = (server: http.Server): Promise<void> =>
@@ -496,7 +496,7 @@ describe('consoleServer new routes integration', () => {
496
496
  path.join(listDir, '.done.json'),
497
497
  JSON.stringify({ projectItemIds: ['PVTI_drop'] }),
498
498
  );
499
- const server = await startConsoleServer({
499
+ const server = await startWebServer({
500
500
  accessToken: testToken,
501
501
  uiDistDir: path.join(tmpDir, 'ui-dist'),
502
502
  consoleDataOutputDir: dataDir,
@@ -533,7 +533,7 @@ describe('consoleServer new routes integration', () => {
533
533
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
534
534
  const issueRepository = mock<IssueRepository>();
535
535
  issueRepository.getIssueOrPullRequestBody.mockResolvedValue('body text');
536
- const server = await startConsoleServer({
536
+ const server = await startWebServer({
537
537
  accessToken: testToken,
538
538
  uiDistDir: path.join(tmpDir, 'ui-dist'),
539
539
  consoleDataOutputDir: null,
@@ -567,7 +567,7 @@ describe('consoleServer new routes integration', () => {
567
567
  createdAt: new Date('2026-06-18T03:21:00.000Z'),
568
568
  },
569
569
  ]);
570
- const server = await startConsoleServer({
570
+ const server = await startWebServer({
571
571
  accessToken: testToken,
572
572
  uiDistDir: path.join(tmpDir, 'ui-dist'),
573
573
  consoleDataOutputDir: null,
@@ -616,7 +616,7 @@ describe('consoleServer new routes integration', () => {
616
616
  ...mock<Issue>(),
617
617
  itemId: 'PVTI_loaded',
618
618
  });
619
- const server = await startConsoleServer({
619
+ const server = await startWebServer({
620
620
  accessToken: testToken,
621
621
  uiDistDir: path.join(tmpDir, 'ui-dist'),
622
622
  consoleDataOutputDir: dataDir,
@@ -662,7 +662,7 @@ describe('consoleServer new routes integration', () => {
662
662
  issueRepository.approvePullRequest.mockRejectedValue(
663
663
  new Error('Failed to approve PR https://github.com/o/r/pull/1: HTTP 422'),
664
664
  );
665
- const server = await startConsoleServer({
665
+ const server = await startWebServer({
666
666
  accessToken: testToken,
667
667
  uiDistDir: path.join(tmpDir, 'ui-dist'),
668
668
  consoleDataOutputDir: null,
@@ -698,7 +698,7 @@ describe('consoleServer new routes integration', () => {
698
698
  it('rejects an operation api with a malformed json body', async () => {
699
699
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
700
700
  const issueRepository = mock<IssueRepository>();
701
- const server = await startConsoleServer({
701
+ const server = await startWebServer({
702
702
  accessToken: testToken,
703
703
  uiDistDir: path.join(tmpDir, 'ui-dist'),
704
704
  consoleDataOutputDir: null,
@@ -749,7 +749,7 @@ describe('consoleServer new routes integration', () => {
749
749
 
750
750
  it('returns 404 for a read api when no repository is injected', async () => {
751
751
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
752
- const server = await startConsoleServer({
752
+ const server = await startWebServer({
753
753
  accessToken: testToken,
754
754
  uiDistDir: path.join(tmpDir, 'ui-dist'),
755
755
  consoleDataOutputDir: null,
@@ -809,7 +809,7 @@ describe('resolveFlatInTmuxFilePath', () => {
809
809
  });
810
810
  });
811
811
 
812
- describe('consoleServer flat in-tmux-by-human route integration', () => {
812
+ describe('webServer flat in-tmux-by-human route integration', () => {
813
813
  const testToken = 'integration-test-token-value';
814
814
 
815
815
  const requestServer = (
@@ -878,7 +878,7 @@ describe('consoleServer flat in-tmux-by-human route integration', () => {
878
878
  fs.writeFileSync(path.join(inTmuxDataDir, 'index.v4.json'), indexV4Raw);
879
879
  fs.writeFileSync(path.join(inTmuxDataDir, 'index.v3.json'), indexV3Raw);
880
880
  fs.writeFileSync(path.join(tmpDir, 'secret.json'), '{"secret":true}');
881
- const server = await startConsoleServer({
881
+ const server = await startWebServer({
882
882
  accessToken: testToken,
883
883
  uiDistDir: path.join(tmpDir, 'ui-dist'),
884
884
  consoleDataOutputDir: null,
@@ -992,7 +992,7 @@ describe('consoleServer flat in-tmux-by-human route integration', () => {
992
992
 
993
993
  it('returns 404 for the flat route when inTmuxDataDir is null', async () => {
994
994
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
995
- const server = await startConsoleServer({
995
+ const server = await startWebServer({
996
996
  accessToken: testToken,
997
997
  uiDistDir: path.join(tmpDir, 'ui-dist'),
998
998
  consoleDataOutputDir: null,
@@ -1030,7 +1030,7 @@ describe('resolveDashboardFilePath', () => {
1030
1030
  });
1031
1031
  });
1032
1032
 
1033
- describe('consoleServer dashboard /tdpm.txt route integration', () => {
1033
+ describe('webServer dashboard /tdpm.txt route integration', () => {
1034
1034
  const testToken = 'integration-test-token-value';
1035
1035
 
1036
1036
  const requestServer = (
@@ -1094,7 +1094,7 @@ describe('consoleServer dashboard /tdpm.txt route integration', () => {
1094
1094
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1095
1095
  fs.writeFileSync(path.join(tmpDir, 'tdpm.txt'), dashboardRaw);
1096
1096
  fs.writeFileSync(path.join(tmpDir, 'secret.txt'), 'secret content');
1097
- const server = await startConsoleServer({
1097
+ const server = await startWebServer({
1098
1098
  accessToken: testToken,
1099
1099
  uiDistDir: path.join(tmpDir, 'ui-dist'),
1100
1100
  consoleDataOutputDir: null,
@@ -1125,7 +1125,7 @@ describe('consoleServer dashboard /tdpm.txt route integration', () => {
1125
1125
 
1126
1126
  it('returns 404 for /tdpm.txt when the file is absent', async () => {
1127
1127
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1128
- const server = await startConsoleServer({
1128
+ const server = await startWebServer({
1129
1129
  accessToken: testToken,
1130
1130
  uiDistDir: path.join(tmpDir, 'ui-dist'),
1131
1131
  consoleDataOutputDir: null,
@@ -1146,7 +1146,7 @@ describe('consoleServer dashboard /tdpm.txt route integration', () => {
1146
1146
  const { server, tmpDir } = await (async () => {
1147
1147
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1148
1148
  fs.writeFileSync(path.join(dir, 'tdpm.txt'), dashboardRaw);
1149
- const srv = await startConsoleServer({
1149
+ const srv = await startWebServer({
1150
1150
  accessToken: testToken,
1151
1151
  uiDistDir: path.join(dir, 'ui-dist'),
1152
1152
  consoleDataOutputDir: null,
@@ -1177,7 +1177,7 @@ describe('consoleServer dashboard /tdpm.txt route integration', () => {
1177
1177
  });
1178
1178
  });
1179
1179
 
1180
- describe('consoleServer image proxy', () => {
1180
+ describe('webServer image proxy', () => {
1181
1181
  const testToken = 'image-proxy-token-value';
1182
1182
  const githubToken = 'gh-token-value';
1183
1183
  const allowedUrl = 'https://github.com/user-attachments/assets/abc-123';
@@ -1244,7 +1244,7 @@ describe('consoleServer image proxy', () => {
1244
1244
  ): Promise<{ server: http.Server; tmpDir: string }> =>
1245
1245
  (async () => {
1246
1246
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-server-'));
1247
- const server = await startConsoleServer({
1247
+ const server = await startWebServer({
1248
1248
  accessToken: testToken,
1249
1249
  uiDistDir: path.join(tmpDir, 'ui-dist'),
1250
1250
  consoleDataOutputDir: null,