@quenty/nevermore-cli 4.22.0 → 4.23.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 (75) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/commands/batch-command/batch-deploy-command.js +1 -2
  3. package/dist/commands/batch-command/batch-deploy-command.js.map +1 -1
  4. package/dist/commands/batch-command/batch-test-command.d.ts.map +1 -1
  5. package/dist/commands/batch-command/batch-test-command.js +35 -7
  6. package/dist/commands/batch-command/batch-test-command.js.map +1 -1
  7. package/dist/commands/deploy-command/index.js +1 -1
  8. package/dist/commands/deploy-command/index.js.map +1 -1
  9. package/dist/commands/test-command/test-command.d.ts.map +1 -1
  10. package/dist/commands/test-command/test-command.js +6 -3
  11. package/dist/commands/test-command/test-command.js.map +1 -1
  12. package/dist/utils/batch/batch-runner.d.ts +2 -1
  13. package/dist/utils/batch/batch-runner.d.ts.map +1 -1
  14. package/dist/utils/batch/batch-runner.js +8 -3
  15. package/dist/utils/batch/batch-runner.js.map +1 -1
  16. package/dist/utils/build/upload.d.ts.map +1 -1
  17. package/dist/utils/build/upload.js +10 -1
  18. package/dist/utils/build/upload.js.map +1 -1
  19. package/dist/utils/job-context/base-job-context.d.ts +4 -3
  20. package/dist/utils/job-context/base-job-context.d.ts.map +1 -1
  21. package/dist/utils/job-context/base-job-context.js +6 -4
  22. package/dist/utils/job-context/base-job-context.js.map +1 -1
  23. package/dist/utils/job-context/batch-script-job-context.d.ts +4 -2
  24. package/dist/utils/job-context/batch-script-job-context.d.ts.map +1 -1
  25. package/dist/utils/job-context/batch-script-job-context.js +39 -19
  26. package/dist/utils/job-context/batch-script-job-context.js.map +1 -1
  27. package/dist/utils/job-context/cloud-job-context.d.ts +3 -3
  28. package/dist/utils/job-context/cloud-job-context.d.ts.map +1 -1
  29. package/dist/utils/job-context/cloud-job-context.js +23 -8
  30. package/dist/utils/job-context/cloud-job-context.js.map +1 -1
  31. package/dist/utils/job-context/job-context.d.ts +2 -3
  32. package/dist/utils/job-context/job-context.d.ts.map +1 -1
  33. package/dist/utils/job-context/local-job-context.d.ts +3 -3
  34. package/dist/utils/job-context/local-job-context.d.ts.map +1 -1
  35. package/dist/utils/job-context/local-job-context.js +6 -6
  36. package/dist/utils/job-context/local-job-context.js.map +1 -1
  37. package/dist/utils/open-cloud/open-cloud-client.d.ts +1 -1
  38. package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
  39. package/dist/utils/open-cloud/open-cloud-client.js +40 -11
  40. package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
  41. package/dist/utils/testing/parsers/batch-log-parser.d.ts +2 -0
  42. package/dist/utils/testing/parsers/batch-log-parser.d.ts.map +1 -1
  43. package/dist/utils/testing/parsers/batch-log-parser.js +3 -1
  44. package/dist/utils/testing/parsers/batch-log-parser.js.map +1 -1
  45. package/dist/utils/testing/runner/combined-project-generator.d.ts +9 -0
  46. package/dist/utils/testing/runner/combined-project-generator.d.ts.map +1 -1
  47. package/dist/utils/testing/runner/combined-project-generator.js +17 -1
  48. package/dist/utils/testing/runner/combined-project-generator.js.map +1 -1
  49. package/dist/utils/testing/runner/test-runner.d.ts +3 -2
  50. package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
  51. package/dist/utils/testing/runner/test-runner.js +5 -5
  52. package/dist/utils/testing/runner/test-runner.js.map +1 -1
  53. package/dist/utils/testing/test-log-parser.d.ts +11 -0
  54. package/dist/utils/testing/test-log-parser.d.ts.map +1 -1
  55. package/dist/utils/testing/test-log-parser.js +22 -0
  56. package/dist/utils/testing/test-log-parser.js.map +1 -1
  57. package/package.json +6 -6
  58. package/src/commands/batch-command/batch-deploy-command.ts +1 -2
  59. package/src/commands/batch-command/batch-test-command.ts +42 -10
  60. package/src/commands/deploy-command/index.ts +1 -1
  61. package/src/commands/test-command/test-command.ts +6 -2
  62. package/src/utils/batch/batch-runner.ts +12 -2
  63. package/src/utils/build/upload.ts +13 -1
  64. package/src/utils/job-context/base-job-context.ts +8 -6
  65. package/src/utils/job-context/batch-script-job-context.ts +40 -21
  66. package/src/utils/job-context/cloud-job-context.ts +24 -8
  67. package/src/utils/job-context/job-context.ts +2 -3
  68. package/src/utils/job-context/local-job-context.ts +4 -6
  69. package/src/utils/open-cloud/open-cloud-client.ts +43 -11
  70. package/src/utils/testing/parsers/batch-log-parser.ts +4 -1
  71. package/src/utils/testing/runner/combined-project-generator.ts +28 -1
  72. package/src/utils/testing/runner/test-runner.ts +5 -6
  73. package/src/utils/testing/test-log-parser.ts +33 -0
  74. package/templates/batch-test-runner.luau +9 -9
  75. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"combined-project-generator.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"combined-project-generator.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import { type Reporter } from '@quenty/cli-output-helpers/reporting';
2
1
  import { type JobContext } from '../../job-context/job-context.js';
2
+ import { type ParsedTestCounts } from '../test-log-parser.js';
3
3
  export interface SingleTestResult {
4
4
  success: boolean;
5
5
  logs: string;
6
+ testCounts?: ParsedTestCounts;
6
7
  }
7
8
  export interface SingleTestOptions {
8
9
  packagePath: string;
@@ -17,7 +18,7 @@ export interface SingleTestOptions {
17
18
  *
18
19
  * Creates and releases its own deployment handle — the caller owns the context lifetime.
19
20
  */
20
- export declare function runSingleTestAsync(context: JobContext, reporter: Reporter, options: SingleTestOptions): Promise<SingleTestResult>;
21
+ export declare function runSingleTestAsync(context: JobContext, options: SingleTestOptions): Promise<SingleTestResult>;
21
22
  /**
22
23
  * Read a test script from the deploy target's configured script path.
23
24
  */
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAGnE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA2C3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,MAAM,CAAC,CAajB"}
1
+ {"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,KAAK,gBAAgB,EAAkC,MAAM,uBAAuB,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA2C3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,MAAM,CAAC,CAajB"}
@@ -1,31 +1,30 @@
1
1
  import * as fs from 'fs/promises';
2
2
  import * as path from 'path';
3
3
  import { randomUUID } from 'crypto';
4
- import { parseTestLogs } from '../test-log-parser.js';
4
+ import { parseTestLogs, parseTestCounts } from '../test-log-parser.js';
5
5
  /**
6
6
  * Build, deploy, and run a test for a single package using the provided
7
7
  * JobContext. The context determines the execution environment (cloud or local).
8
8
  *
9
9
  * Creates and releases its own deployment handle — the caller owns the context lifetime.
10
10
  */
11
- export async function runSingleTestAsync(context, reporter, options) {
11
+ export async function runSingleTestAsync(context, options) {
12
12
  const { packagePath, packageName, timeoutMs = 120_000, scriptText, } = options;
13
13
  const sessionId = randomUUID();
14
14
  const builtPlace = await context.buildPlaceAsync({
15
15
  targetName: 'test',
16
16
  outputFileName: `test-${sessionId}.rbxl`,
17
17
  packagePath,
18
- reporter,
19
18
  packageName,
20
19
  });
21
20
  const scriptContent = scriptText ?? (await readTestScriptAsync(packagePath, builtPlace.target.scriptTemplate));
22
- const deployment = await context.deployBuiltPlaceAsync(reporter, {
21
+ const deployment = await context.deployBuiltPlaceAsync({
23
22
  builtPlace,
24
23
  packageName,
25
24
  packagePath,
26
25
  });
27
26
  try {
28
- const result = await context.runScriptAsync(deployment, reporter, {
27
+ const result = await context.runScriptAsync(deployment, {
29
28
  scriptContent,
30
29
  packageName,
31
30
  timeoutMs,
@@ -35,6 +34,7 @@ export async function runSingleTestAsync(context, reporter, options) {
35
34
  return {
36
35
  success: result.success && parsed.success,
37
36
  logs: parsed.logs,
37
+ testCounts: parseTestCounts(parsed.logs),
38
38
  };
39
39
  }
40
40
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAetD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAmB,EACnB,QAAkB,EAClB,OAA0B;IAE1B,MAAM,EACJ,WAAW,EACX,WAAW,EACX,SAAS,GAAG,OAAO,EACnB,UAAU,GACX,GAAG,OAAO,CAAC;IAEZ,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC;QAC/C,UAAU,EAAE,MAAM;QAClB,cAAc,EAAE,QAAQ,SAAS,OAAO;QACxC,WAAW;QACX,QAAQ;QACR,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,aAAa,GACjB,UAAU,IAAI,CAAC,MAAM,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAE3F,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,QAAQ,EAAE;QAC/D,UAAU;QACV,WAAW;QACX,WAAW;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,EAAE;YAChE,aAAa;YACb,WAAW;YACX,SAAS;SACV,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAEtC,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO;YACzC,IAAI,EAAE,MAAM,CAAC,IAAI;SAClB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,UAA8B;IAE9B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,mDAAmD,WAAW,2EAA2E,CAC1I,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;IACxD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,EAAyB,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAgB9F;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAmB,EACnB,OAA0B;IAE1B,MAAM,EACJ,WAAW,EACX,WAAW,EACX,SAAS,GAAG,OAAO,EACnB,UAAU,GACX,GAAG,OAAO,CAAC;IAEZ,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC;QAC/C,UAAU,EAAE,MAAM;QAClB,cAAc,EAAE,QAAQ,SAAS,OAAO;QACxC,WAAW;QACX,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,aAAa,GACjB,UAAU,IAAI,CAAC,MAAM,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAE3F,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC;QACrD,UAAU;QACV,WAAW;QACX,WAAW;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,UAAU,EAAE;YACtD,aAAa;YACb,WAAW;YACX,SAAS;SACV,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAEtC,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO;YACzC,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC;SACzC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,UAA8B;IAE9B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,mDAAmD,WAAW,2EAA2E,CAC1I,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;IACxD,CAAC;AACH,CAAC"}
@@ -1,10 +1,21 @@
1
+ export interface ParsedTestCounts {
2
+ passed: number;
3
+ failed: number;
4
+ total: number;
5
+ }
1
6
  export interface ParsedTestLogs {
2
7
  success: boolean;
3
8
  logs: string;
9
+ testCounts?: ParsedTestCounts;
4
10
  }
5
11
  /**
6
12
  * Analyze test output for Jest failures and Luau runtime errors.
7
13
  * Shared by both Open Cloud log fetching and local run-in-roblox output.
8
14
  */
9
15
  export declare function parseTestLogs(rawOutput: string): ParsedTestLogs;
16
+ /**
17
+ * Parse Jest "Tests: N failed, N passed, N total" line into structured counts.
18
+ * Returns undefined if no test summary line is found.
19
+ */
20
+ export declare function parseTestCounts(rawOutput: string): ParsedTestCounts | undefined;
10
21
  //# sourceMappingURL=test-log-parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-log-parser.d.ts","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAiB/D"}
1
+ {"version":3,"file":"test-log-parser.d.ts","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAkB/D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAmB/E"}
@@ -15,6 +15,28 @@ export function parseTestLogs(rawOutput) {
15
15
  return {
16
16
  success: !hasJestFailures && !hasRuntimeError,
17
17
  logs: rawOutput,
18
+ testCounts: parseTestCounts(rawOutput),
18
19
  };
19
20
  }
21
+ /**
22
+ * Parse Jest "Tests: N failed, N passed, N total" line into structured counts.
23
+ * Returns undefined if no test summary line is found.
24
+ */
25
+ export function parseTestCounts(rawOutput) {
26
+ const clean = OutputHelper.stripAnsi(rawOutput);
27
+ // Match "Tests: 2 failed, 23 passed, 25 total" or "Tests: 25 passed, 25 total"
28
+ const match = clean.match(/Tests:\s+(.+?)\s+total/);
29
+ if (!match)
30
+ return undefined;
31
+ const prefix = match[1];
32
+ const totalMatch = clean.match(/Tests:\s+.+?(\d+)\s+total/);
33
+ if (!totalMatch)
34
+ return undefined;
35
+ const total = parseInt(totalMatch[1], 10);
36
+ const passedMatch = prefix.match(/(\d+)\s+passed/);
37
+ const failedMatch = prefix.match(/(\d+)\s+failed/);
38
+ const passed = passedMatch ? parseInt(passedMatch[1], 10) : 0;
39
+ const failed = failedMatch ? parseInt(failedMatch[1], 10) : 0;
40
+ return { passed, failed, total };
41
+ }
20
42
  //# sourceMappingURL=test-log-parser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-log-parser.js","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAO1D;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAEpD,qCAAqC;IACrC,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/D,MAAM,eAAe,GACnB,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACnD,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEpD,+CAA+C;IAC/C,MAAM,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAExD,OAAO;QACL,OAAO,EAAE,CAAC,eAAe,IAAI,CAAC,eAAe;QAC7C,IAAI,EAAE,SAAS;KAChB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"test-log-parser.js","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAc1D;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAEpD,qCAAqC;IACrC,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/D,MAAM,eAAe,GACnB,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACnD,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEpD,+CAA+C;IAC/C,MAAM,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAExD,OAAO;QACL,OAAO,EAAE,CAAC,eAAe,IAAI,CAAC,eAAe;QAC7C,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,eAAe,CAAC,SAAS,CAAC;KACvC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAEhD,iFAAiF;IACjF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAE7B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAElC,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAEnD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9D,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/nevermore-cli",
3
- "version": "4.22.0",
3
+ "version": "4.23.0",
4
4
  "description": "CLI interface for Nevermore",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -25,10 +25,10 @@
25
25
  "Quenty"
26
26
  ],
27
27
  "dependencies": {
28
- "@quenty/cli-output-helpers": "1.9.0",
29
- "@quenty/nevermore-cli-helpers": "1.7.0",
30
- "@quenty/nevermore-template-helpers": "1.10.0",
31
- "@quenty/studio-bridge": "0.6.0",
28
+ "@quenty/cli-output-helpers": "1.10.0",
29
+ "@quenty/nevermore-cli-helpers": "1.8.0",
30
+ "@quenty/nevermore-template-helpers": "1.11.0",
31
+ "@quenty/studio-bridge": "0.7.0",
32
32
  "execa": "^9.6.1",
33
33
  "find-git-root": "^1.0.4",
34
34
  "inquirer": "^13.2.0",
@@ -57,5 +57,5 @@
57
57
  "engines": {
58
58
  "node": ">=16"
59
59
  },
60
- "gitHead": "305e70aba3395b2f94f500c731327760984aeb4f"
60
+ "gitHead": "7f6f73dc51f43fa1050f76f86a5935f5a64ab99f"
61
61
  }
@@ -172,7 +172,7 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
172
172
  apiKey,
173
173
  rateLimiter: new RateLimiter(),
174
174
  });
175
- const context = new CloudJobContext(client);
175
+ const context = new CloudJobContext(reporter, client);
176
176
 
177
177
  await reporter.startAsync();
178
178
 
@@ -188,7 +188,6 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
188
188
  targetName,
189
189
  outputFileName: publish ? 'publish.rbxl' : 'deploy.rbxl',
190
190
  packagePath: pkg.path,
191
- reporter: pkgReporter,
192
191
  packageName: pkg.name,
193
192
  });
194
193
 
@@ -1,6 +1,10 @@
1
1
  import { CommandModule } from 'yargs';
2
2
  import { OutputHelper } from '@quenty/cli-output-helpers';
3
- import { type Reporter } from '@quenty/cli-output-helpers/reporting';
3
+ import {
4
+ type Reporter,
5
+ type JobPhase,
6
+ type ProgressSummary,
7
+ } from '@quenty/cli-output-helpers/reporting';
4
8
  import { NevermoreGlobalArgs } from '../../args/global-args.js';
5
9
  import { getApiKeyAsync } from '../../utils/auth/credential-store.js';
6
10
  import { runBatchAsync } from '../../utils/batch/batch-runner.js';
@@ -188,15 +192,22 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
188
192
 
189
193
  const timeoutMs = 120_000;
190
194
 
195
+ // In aggregated mode, the inner context gets a broadcast reporter that translates
196
+ // phase changes from the shared '_batch_' operation to all real packages
197
+ const innerReporter: Reporter = args.aggregated
198
+ ? _createBroadcastReporter(reporter, packageNames)
199
+ : reporter;
200
+
191
201
  const innerContext: JobContext = cloud
192
- ? new CloudJobContext(client)
193
- : new LocalJobContext(client);
202
+ ? new CloudJobContext(innerReporter, client)
203
+ : new LocalJobContext(innerReporter, client);
194
204
 
195
205
  const context: JobContext = args.aggregated
196
206
  ? new BatchScriptJobContext(innerContext, packages, {
197
207
  batchPlaceId: args.batchPlaceId,
198
208
  batchUniverseId: args.batchUniverseId,
199
209
  perPackageTimeoutMs: timeoutMs,
210
+ reporter,
200
211
  })
201
212
  : innerContext;
202
213
 
@@ -208,12 +219,12 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
208
219
  concurrency,
209
220
  reporter,
210
221
  bufferOutput: isGrouped,
211
- executeAsync: async (pkg, pkgReporter) => {
222
+ stateTracker: reporter.state,
223
+ executeAsync: async (pkg) => {
212
224
  const result = await _runWithRetryAsync(
213
225
  pkg,
214
226
  context,
215
- timeoutMs,
216
- pkgReporter
227
+ timeoutMs
217
228
  );
218
229
 
219
230
  return {
@@ -221,6 +232,9 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
221
232
  placeId: pkg.target.placeId,
222
233
  success: result.success,
223
234
  logs: result.logs,
235
+ progressSummary: result.testCounts
236
+ ? { kind: 'test-counts' as const, ...result.testCounts }
237
+ : undefined,
224
238
  };
225
239
  },
226
240
  });
@@ -238,8 +252,7 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
238
252
  async function _runWithRetryAsync(
239
253
  pkg: TargetPackage,
240
254
  context: JobContext,
241
- timeoutMs: number,
242
- reporter: Reporter
255
+ timeoutMs: number
243
256
  ): Promise<SingleTestResult> {
244
257
  const opts = {
245
258
  packagePath: pkg.path,
@@ -248,15 +261,34 @@ async function _runWithRetryAsync(
248
261
  };
249
262
 
250
263
  try {
251
- return await runSingleTestAsync(context, reporter, opts);
264
+ return await runSingleTestAsync(context, opts);
252
265
  } catch (err) {
253
266
  const message = err instanceof Error ? err.message : String(err);
254
267
 
255
268
  if (message.includes('timed out') || message.includes('fetch failed')) {
256
269
  OutputHelper.warn(`${pkg.name}: transient failure, retrying...`);
257
- return await runSingleTestAsync(context, reporter, opts);
270
+ return await runSingleTestAsync(context, opts);
258
271
  }
259
272
 
260
273
  throw err;
261
274
  }
262
275
  }
276
+
277
+ function _createBroadcastReporter(target: Reporter, packageNames: string[]): Reporter {
278
+ return {
279
+ startAsync: async () => {},
280
+ stopAsync: async () => {},
281
+ onPackageStart: () => {},
282
+ onPackageResult: () => {},
283
+ onPackagePhaseChange: (_name: string, phase: JobPhase) => {
284
+ for (const name of packageNames) {
285
+ target.onPackagePhaseChange(name, phase);
286
+ }
287
+ },
288
+ onPackageProgressUpdate: (_name: string, progress: ProgressSummary) => {
289
+ for (const name of packageNames) {
290
+ target.onPackageProgressUpdate(name, progress);
291
+ }
292
+ },
293
+ };
294
+ }
@@ -168,7 +168,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
168
168
 
169
169
  const apiKey = await getApiKeyAsync(args);
170
170
  const client = new OpenCloudClient({ apiKey, rateLimiter: new RateLimiter() });
171
- const context = new CloudJobContext(client);
171
+ const context = new CloudJobContext(reporter, client);
172
172
 
173
173
  await reporter.startAsync();
174
174
 
@@ -105,16 +105,17 @@ export class TestProjectCommand<T>
105
105
 
106
106
  const context = args.cloud
107
107
  ? new CloudJobContext(
108
+ reporter,
108
109
  new OpenCloudClient({
109
110
  apiKey: await getApiKeyAsync(args),
110
111
  rateLimiter: new RateLimiter(),
111
112
  })
112
113
  )
113
- : new LocalJobContext();
114
+ : new LocalJobContext(reporter);
114
115
 
115
116
  let result;
116
117
  try {
117
- result = await runSingleTestAsync(context, reporter, {
118
+ result = await runSingleTestAsync(context, {
118
119
  packagePath: cwd,
119
120
  packageName,
120
121
  scriptText: args.scriptText,
@@ -128,6 +129,9 @@ export class TestProjectCommand<T>
128
129
  success: result.success,
129
130
  logs: result.logs,
130
131
  durationMs: 0,
132
+ progressSummary: result.testCounts
133
+ ? { kind: 'test-counts', ...result.testCounts }
134
+ : undefined,
131
135
  });
132
136
 
133
137
  await reporter.stopAsync();
@@ -3,6 +3,7 @@ import {
3
3
  type Reporter,
4
4
  type PackageResult,
5
5
  type BatchSummary,
6
+ type IStateTracker,
6
7
  } from '@quenty/cli-output-helpers/reporting';
7
8
  import { type TargetPackage } from './changed-packages-utils.js';
8
9
 
@@ -11,6 +12,7 @@ export interface BatchOptions<TResult extends PackageResult> {
11
12
  concurrency?: number;
12
13
  reporter: Reporter;
13
14
  bufferOutput?: boolean;
15
+ stateTracker?: IStateTracker;
14
16
  executeAsync: (
15
17
  pkg: TargetPackage,
16
18
  reporter: Reporter
@@ -25,6 +27,7 @@ export async function runBatchAsync<TResult extends PackageResult>(
25
27
  concurrency = Infinity,
26
28
  reporter,
27
29
  bufferOutput = false,
30
+ stateTracker,
28
31
  executeAsync,
29
32
  } = options;
30
33
 
@@ -39,7 +42,7 @@ export async function runBatchAsync<TResult extends PackageResult>(
39
42
  const pkg = packages[nextIndex++];
40
43
  runningCount++;
41
44
 
42
- _runOneAsync<TResult>(pkg, executeAsync, reporter, bufferOutput)
45
+ _runOneAsync<TResult>(pkg, executeAsync, reporter, bufferOutput, stateTracker)
43
46
  .then((result) => {
44
47
  results.push(result);
45
48
  })
@@ -78,7 +81,8 @@ async function _runOneAsync<TResult extends PackageResult>(
78
81
  reporter: Reporter
79
82
  ) => Promise<Omit<TResult, 'durationMs'>>,
80
83
  reporter: Reporter,
81
- bufferOutput: boolean
84
+ bufferOutput: boolean,
85
+ stateTracker?: IStateTracker
82
86
  ): Promise<TResult> {
83
87
  reporter.onPackageStart(pkg.name);
84
88
  const startMs = Date.now();
@@ -89,12 +93,18 @@ async function _runOneAsync<TResult extends PackageResult>(
89
93
  return { ...partial, durationMs: Date.now() - startMs } as TResult;
90
94
  } catch (err) {
91
95
  const errorMessage = err instanceof Error ? err.message : String(err);
96
+ const currentPhase = stateTracker?.getCurrentPhase(pkg.name);
97
+ const failedPhase =
98
+ currentPhase && currentPhase !== 'pending' && currentPhase !== 'passed' && currentPhase !== 'failed'
99
+ ? currentPhase
100
+ : undefined;
92
101
  return {
93
102
  packageName: pkg.name,
94
103
  success: false,
95
104
  logs: '',
96
105
  durationMs: Date.now() - startMs,
97
106
  error: errorMessage,
107
+ failedPhase,
98
108
  } as TResult;
99
109
  }
100
110
  };
@@ -33,11 +33,23 @@ export async function uploadPlaceAsync(
33
33
  const apiKey = await getApiKeyAsync(args);
34
34
 
35
35
  reporter?.onPackagePhaseChange(packageName ?? '', 'uploading');
36
+
37
+ const onProgress = reporter && packageName
38
+ ? (transferred: number, total: number) => {
39
+ reporter.onPackageProgressUpdate(packageName, {
40
+ kind: 'bytes',
41
+ transferredBytes: transferred,
42
+ totalBytes: total,
43
+ });
44
+ }
45
+ : undefined;
46
+
36
47
  const version = await client.uploadPlaceAsync(
37
48
  target.universeId,
38
49
  target.placeId,
39
50
  rbxlPath,
40
- args.publish
51
+ args.publish,
52
+ onProgress
41
53
  );
42
54
 
43
55
  return { client, apiKey, target, version };
@@ -44,15 +44,17 @@ class TrackedBuiltPlace implements BuiltPlace {
44
44
  * — even when individual deployments fail.
45
45
  */
46
46
  export abstract class BaseJobContext implements JobContext {
47
+ protected _reporter: Reporter;
47
48
  protected _openCloudClient: OpenCloudClient | undefined;
48
49
  private _builtPlaces = new Set<TrackedBuiltPlace>();
49
50
 
50
- constructor(openCloudClient?: OpenCloudClient) {
51
+ constructor(reporter: Reporter, openCloudClient?: OpenCloudClient) {
52
+ this._reporter = reporter;
51
53
  this._openCloudClient = openCloudClient;
52
54
  }
53
55
 
54
56
  async buildPlaceAsync(options: BuildPlaceOptions): Promise<BuiltPlace> {
55
- const result = await buildPlaceAsync(options);
57
+ const result = await buildPlaceAsync({ ...options, reporter: this._reporter });
56
58
  const tracked = new TrackedBuiltPlace(result.rbxlPath, result.target, result.buildContext);
57
59
  this._builtPlaces.add(tracked);
58
60
 
@@ -76,7 +78,7 @@ export abstract class BaseJobContext implements JobContext {
76
78
 
77
79
  const resolvedName = options.packageName ?? '';
78
80
 
79
- options.reporter?.onPackagePhaseChange(resolvedName, 'downloading');
81
+ this._reporter.onPackagePhaseChange(resolvedName, 'downloading');
80
82
  OutputHelper.verbose('Downloading base place for merge...');
81
83
  const buffer = await this._openCloudClient.downloadPlaceAsync(
82
84
  basePlace.universeId,
@@ -85,7 +87,7 @@ export abstract class BaseJobContext implements JobContext {
85
87
  const basePath = buildContext.resolvePath('base.rbxl');
86
88
  await fs.writeFile(basePath, buffer);
87
89
 
88
- options.reporter?.onPackagePhaseChange(resolvedName, 'merging');
90
+ this._reporter.onPackagePhaseChange(resolvedName, 'merging');
89
91
  const packagePath = options.packagePath ?? process.cwd();
90
92
  const projectPath = path.resolve(packagePath, tracked.target.project);
91
93
  const mergedPath = buildContext.resolvePath('merged.rbxl');
@@ -111,8 +113,8 @@ export abstract class BaseJobContext implements JobContext {
111
113
  this._builtPlaces.delete(tracked);
112
114
  }
113
115
 
114
- abstract deployBuiltPlaceAsync(reporter: Reporter, options: DeployPlaceOptions): Promise<Deployment>;
115
- abstract runScriptAsync(deployment: Deployment, reporter: Reporter, options: RunScriptOptions): Promise<ScriptRunResult>;
116
+ abstract deployBuiltPlaceAsync(options: DeployPlaceOptions): Promise<Deployment>;
117
+ abstract runScriptAsync(deployment: Deployment, options: RunScriptOptions): Promise<ScriptRunResult>;
116
118
  abstract getLogsAsync(deployment: Deployment): Promise<string>;
117
119
  abstract releaseAsync(deployment: Deployment): Promise<void>;
118
120
 
@@ -23,6 +23,7 @@ import {
23
23
  } from '../build/deploy-config.js';
24
24
  import { type TargetPackage } from '../batch/changed-packages-utils.js';
25
25
  import {
26
+ type CombinedBuildProgress,
26
27
  type CombinedProjectResult,
27
28
  generateCombinedProjectAsync,
28
29
  } from '../testing/runner/combined-project-generator.js';
@@ -57,6 +58,7 @@ export class BatchScriptJobContext implements JobContext {
57
58
  private _batchPlaceId?: number;
58
59
  private _batchUniverseId?: number;
59
60
  private _perPackageTimeoutMs: number;
61
+ private _reporter?: Reporter;
60
62
 
61
63
  // Lazy-promise state
62
64
  private _combinedBuildPromise?: Promise<CombinedBuildState>;
@@ -76,6 +78,7 @@ export class BatchScriptJobContext implements JobContext {
76
78
  batchPlaceId?: number;
77
79
  batchUniverseId?: number;
78
80
  perPackageTimeoutMs?: number;
81
+ reporter?: Reporter;
79
82
  }
80
83
  ) {
81
84
  this._inner = inner;
@@ -84,6 +87,7 @@ export class BatchScriptJobContext implements JobContext {
84
87
  this._batchPlaceId = options?.batchPlaceId;
85
88
  this._batchUniverseId = options?.batchUniverseId;
86
89
  this._perPackageTimeoutMs = options?.perPackageTimeoutMs ?? 120_000;
90
+ this._reporter = options?.reporter;
87
91
  }
88
92
 
89
93
  async buildPlaceAsync(options: BuildPlaceOptions): Promise<BuiltPlace> {
@@ -109,17 +113,15 @@ export class BatchScriptJobContext implements JobContext {
109
113
  }
110
114
 
111
115
  async deployBuiltPlaceAsync(
112
- reporter: Reporter,
113
116
  options: DeployPlaceOptions
114
117
  ): Promise<Deployment> {
115
- const innerDeployment = await this._getSharedDeploymentAsync(reporter);
118
+ const innerDeployment = await this._getSharedDeploymentAsync();
116
119
 
117
120
  return new BatchDeployment(options.packageName, innerDeployment);
118
121
  }
119
122
 
120
123
  async runScriptAsync(
121
124
  deployment: Deployment,
122
- _reporter: Reporter,
123
125
  options: RunScriptOptions
124
126
  ): Promise<ScriptRunResult> {
125
127
  const batchDeployment = deployment as BatchDeployment;
@@ -183,11 +185,42 @@ export class BatchScriptJobContext implements JobContext {
183
185
  private async _doCombinedBuildAsync(): Promise<CombinedBuildState> {
184
186
  OutputHelper.verbose('Building combined batch place...');
185
187
 
188
+ // Set all packages to "waiting" — they're queued for building
189
+ if (this._reporter) {
190
+ for (const pkg of this._packages) {
191
+ this._reporter.onPackagePhaseChange(pkg.name, 'waiting');
192
+ }
193
+ }
194
+
195
+ const progress: CombinedBuildProgress = {
196
+ onPackageBuildStart: (name) => {
197
+ this._reporter?.onPackagePhaseChange(name, 'building');
198
+ },
199
+ onPackageBuildComplete: (name) => {
200
+ this._reporter?.onPackagePhaseChange(name, 'waiting');
201
+ },
202
+ onCombineStart: () => {
203
+ if (this._reporter) {
204
+ for (const pkg of this._packages) {
205
+ this._reporter.onPackagePhaseChange(pkg.name, 'combining');
206
+ }
207
+ }
208
+ },
209
+ onStepProgress: (stepProgress) => {
210
+ if (this._reporter) {
211
+ for (const pkg of this._packages) {
212
+ this._reporter.onPackageProgressUpdate(pkg.name, stepProgress);
213
+ }
214
+ }
215
+ },
216
+ };
217
+
186
218
  const combinedResult = await generateCombinedProjectAsync({
187
219
  packages: this._packages,
188
220
  repoRoot: this._repoRoot,
189
221
  batchPlaceId: this._batchPlaceId,
190
222
  batchUniverseId: this._batchUniverseId,
223
+ progress,
191
224
  });
192
225
 
193
226
  this._combinedBuildContext = combinedResult.buildContext;
@@ -195,26 +228,23 @@ export class BatchScriptJobContext implements JobContext {
195
228
  return { combinedResult, rbxlPath: combinedResult.rbxlPath };
196
229
  }
197
230
 
198
- private _getSharedDeploymentAsync(reporter?: Reporter): Promise<Deployment> {
231
+ private _getSharedDeploymentAsync(): Promise<Deployment> {
199
232
  if (!this._deployPromise) {
200
- this._deployPromise = this._doSharedDeployAsync(reporter);
233
+ this._deployPromise = this._doSharedDeployAsync();
201
234
  }
202
235
  return this._deployPromise;
203
236
  }
204
237
 
205
- private async _doSharedDeployAsync(reporter?: Reporter): Promise<Deployment> {
238
+ private async _doSharedDeployAsync(): Promise<Deployment> {
206
239
  const buildState = await this._getCombinedBuildAsync();
207
240
  const { primaryTarget } = buildState.combinedResult;
208
241
 
209
- // Create a minimal reporter that doesn't emit per-package phases
210
- const batchReporter = reporter ?? _noopReporter();
211
-
212
242
  const builtPlace: BuiltPlace = {
213
243
  rbxlPath: buildState.rbxlPath,
214
244
  target: primaryTarget,
215
245
  };
216
246
 
217
- const deployment = await this._inner.deployBuiltPlaceAsync(batchReporter, {
247
+ const deployment = await this._inner.deployBuiltPlaceAsync({
218
248
  builtPlace,
219
249
  packageName: '_batch_',
220
250
  packagePath: this._repoRoot,
@@ -265,7 +295,6 @@ export class BatchScriptJobContext implements JobContext {
265
295
 
266
296
  const result = await this._inner.runScriptAsync(
267
297
  deployment,
268
- _noopReporter(),
269
298
  {
270
299
  scriptContent: batchScript,
271
300
  packageName: '_batch_',
@@ -287,13 +316,3 @@ export class BatchScriptJobContext implements JobContext {
287
316
  return parseBatchTestLogs(rawLogs, slugMap);
288
317
  }
289
318
  }
290
-
291
- function _noopReporter(): Reporter {
292
- return {
293
- onPackageStart: () => {},
294
- onPackagePhaseChange: () => {},
295
- onPackageResult: () => {},
296
- startAsync: async () => {},
297
- stopAsync: async () => {},
298
- };
299
- }