@quenty/nevermore-cli 4.40.0 → 4.41.1

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 (54) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/commands/batch-command/batch-deploy-command.d.ts.map +1 -1
  3. package/dist/commands/batch-command/batch-deploy-command.js +2 -1
  4. package/dist/commands/batch-command/batch-deploy-command.js.map +1 -1
  5. package/dist/commands/batch-command/batch-test-command.js +2 -0
  6. package/dist/commands/batch-command/batch-test-command.js.map +1 -1
  7. package/dist/commands/deploy-command/index.d.ts.map +1 -1
  8. package/dist/commands/deploy-command/index.js +3 -1
  9. package/dist/commands/deploy-command/index.js.map +1 -1
  10. package/dist/utils/deploy/deploy-metadata.d.ts +2 -0
  11. package/dist/utils/deploy/deploy-metadata.d.ts.map +1 -1
  12. package/dist/utils/deploy/deploy-metadata.js +2 -0
  13. package/dist/utils/deploy/deploy-metadata.js.map +1 -1
  14. package/dist/utils/deploy/deploy-metadata.test.js +8 -0
  15. package/dist/utils/deploy/deploy-metadata.test.js.map +1 -1
  16. package/dist/utils/job-context/batch-script-job-context.d.ts.map +1 -1
  17. package/dist/utils/job-context/batch-script-job-context.js +5 -1
  18. package/dist/utils/job-context/batch-script-job-context.js.map +1 -1
  19. package/dist/utils/nevermore-cli-utils.d.ts +1 -0
  20. package/dist/utils/nevermore-cli-utils.d.ts.map +1 -1
  21. package/dist/utils/nevermore-cli-utils.js +10 -0
  22. package/dist/utils/nevermore-cli-utils.js.map +1 -1
  23. package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
  24. package/dist/utils/open-cloud/open-cloud-client.js +20 -2
  25. package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
  26. package/dist/utils/testing/parsers/batch-log-parser.d.ts +16 -0
  27. package/dist/utils/testing/parsers/batch-log-parser.d.ts.map +1 -1
  28. package/dist/utils/testing/parsers/batch-log-parser.js +80 -7
  29. package/dist/utils/testing/parsers/batch-log-parser.js.map +1 -1
  30. package/dist/utils/testing/parsers/batch-log-parser.test.d.ts +2 -0
  31. package/dist/utils/testing/parsers/batch-log-parser.test.d.ts.map +1 -0
  32. package/dist/utils/testing/parsers/batch-log-parser.test.js +65 -0
  33. package/dist/utils/testing/parsers/batch-log-parser.test.js.map +1 -0
  34. package/dist/utils/testing/reporting/test-github-columns.d.ts.map +1 -1
  35. package/dist/utils/testing/reporting/test-github-columns.js +1 -0
  36. package/dist/utils/testing/reporting/test-github-columns.js.map +1 -1
  37. package/dist/utils/testing/runner/test-runner.d.ts +2 -0
  38. package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
  39. package/dist/utils/testing/runner/test-runner.js +3 -0
  40. package/dist/utils/testing/runner/test-runner.js.map +1 -1
  41. package/package.json +6 -6
  42. package/src/commands/batch-command/batch-deploy-command.ts +5 -1
  43. package/src/commands/batch-command/batch-test-command.ts +2 -0
  44. package/src/commands/deploy-command/index.ts +7 -1
  45. package/src/utils/deploy/deploy-metadata.test.ts +13 -0
  46. package/src/utils/deploy/deploy-metadata.ts +3 -0
  47. package/src/utils/job-context/batch-script-job-context.ts +5 -1
  48. package/src/utils/nevermore-cli-utils.ts +15 -0
  49. package/src/utils/open-cloud/open-cloud-client.ts +25 -2
  50. package/src/utils/testing/parsers/batch-log-parser.test.ts +85 -0
  51. package/src/utils/testing/parsers/batch-log-parser.ts +98 -7
  52. package/src/utils/testing/reporting/test-github-columns.ts +1 -0
  53. package/src/utils/testing/runner/test-runner.ts +5 -0
  54. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"batch-log-parser.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAmB,MAAM,uBAAuB,CAAC;AAE/E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAaD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAoJjC"}
1
+ {"version":3,"file":"batch-log-parser.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAmB,MAAM,uBAAuB,CAAC;AAE/E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB;AAaD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAwNjC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMzD"}
@@ -31,6 +31,8 @@ export function parseBatchTestLogs(rawLogs, slugMap) {
31
31
  let currentSlug = null;
32
32
  let currentLines = [];
33
33
  let summaryLineIndex = -1;
34
+ let beginMarkersSeen = 0;
35
+ let endMarkersSeen = 0;
34
36
  // Matches "<slug> PASS|FAIL [<durationMs>]" — slugs have no whitespace.
35
37
  const endInnerPattern = /^(\S+)\s+(?:PASS|FAIL)(?:\s+(\d+))?$/;
36
38
  for (let i = 0; i < lines.length; i++) {
@@ -38,10 +40,12 @@ export function parseBatchTestLogs(rawLogs, slugMap) {
38
40
  if (trimmed.startsWith(BEGIN_MARKER) && trimmed.endsWith('===')) {
39
41
  currentSlug = trimmed.slice(BEGIN_MARKER.length, -3);
40
42
  currentLines = [];
43
+ beginMarkersSeen++;
41
44
  continue;
42
45
  }
43
46
  if (trimmed.startsWith(END_MARKER) && trimmed.endsWith('===')) {
44
47
  const inner = trimmed.slice(END_MARKER.length, -3);
48
+ endMarkersSeen++;
45
49
  const match = endInnerPattern.exec(inner);
46
50
  const endSlug = match ? match[1] : inner;
47
51
  const durationStr = match?.[2];
@@ -98,26 +102,79 @@ export function parseBatchTestLogs(rawLogs, slugMap) {
98
102
  OutputHelper.warn(`[batch-log-parser] No batch markers or summary found in logs (${lines.length} lines, ${rawLogs.length} chars). ` +
99
103
  'The batch script may not have started or produced output.');
100
104
  }
105
+ // The summary is printed last, so it survives a log fetch that dropped the
106
+ // output above it. Summary present with no sections is exactly that case, and
107
+ // it is invisible to the check above — the results below would then be built
108
+ // from pcall exit status alone, knowing nothing about what actually ran.
109
+ const lostSectionOutput = logSections.size === 0 && summaryResults.size > 0;
110
+ if (lostSectionOutput) {
111
+ OutputHelper.warn(`[batch-log-parser] Received ${rawLogs.length} chars of output but could not ` +
112
+ `attribute any of it to a package section ` +
113
+ `(${beginMarkersSeen} BEGIN, ${endMarkersSeen} END markers; summary at line ` +
114
+ `${summaryLineIndex} of ${lines.length}). ` +
115
+ 'Test counts are not derived from unattributed output.');
116
+ // BEGIN is printed first and the summary last, so their positions separate
117
+ // the two ways this happens: a log window that dropped the head keeps the
118
+ // summary at the end, while reordered messages put it early.
119
+ OutputHelper.warn(summaryLineIndex >= lines.length - 2
120
+ ? '[batch-log-parser] Summary sits at the end of the log — consistent with the head being dropped by a log size/retention limit.'
121
+ : '[batch-log-parser] Summary sits early in the log — consistent with out-of-order messages ending the scan prematurely.');
122
+ }
101
123
  // ── Pass 3: Combine log sections with summary results ──
102
- // When the batch produced zero output, surface the raw error in every
103
- // package's logs so reporters show the actual failure instead of "(no output)".
104
- const fallbackLogs = noOutputAtAll ? rawLogs.trim() : '';
124
+ // Output that arrived but could not be split into sections is still output.
125
+ // Reporting "(no output)" over it hides the very thing needed to diagnose the
126
+ // parse failure, so it is shown verbatim instead. Only safe to hand to a
127
+ // single package: with several, there is no way to say whose output this is.
128
+ const fallbackLogs = noOutputAtAll || lostSectionOutput ? rawLogs.trim() : '';
129
+ // The unattributed stream is the same text for every package, so it is
130
+ // attached once rather than repeated per package across a large log.
131
+ let unattributedClaimed = false;
105
132
  for (const [packageName, slug] of slugMap) {
106
- const sectionLogs = logSections.get(slug) ?? fallbackLogs;
133
+ const attributedLogs = logSections.get(slug);
134
+ let sectionLogs = attributedLogs ?? '';
135
+ if (!attributedLogs && fallbackLogs && !unattributedClaimed) {
136
+ sectionLogs = fallbackLogs;
137
+ unattributedClaimed = true;
138
+ }
107
139
  const summarySuccess = summaryResults.get(slug);
108
140
  // The JSON summary (pcall result) is the primary success signal.
109
141
  // Jest failure detection provides a secondary override.
142
+ //
143
+ // Gate on attributed output only. Unattributed output is shown but not
144
+ // judged: whatever broke attribution is reason enough not to trust which
145
+ // package a failure line belongs to.
110
146
  let success = summarySuccess ?? false;
111
- if (success && sectionLogs) {
112
- const hasJestFailures = _hasJestFailuresInLogs(sectionLogs);
147
+ let error;
148
+ if (success && attributedLogs) {
149
+ const hasJestFailures = _hasJestFailuresInLogs(attributedLogs);
113
150
  if (hasJestFailures) {
114
151
  success = false;
152
+ error = 'Jest reported failing tests';
115
153
  }
116
154
  }
155
+ // A pass we cannot read is not a pass. The pcall only proves the script did
156
+ // not throw, which says nothing about whether any test ran or passed.
157
+ if (success && !attributedLogs) {
158
+ success = false;
159
+ error =
160
+ `No test output could be attributed to this package ` +
161
+ `(${rawLogs.length} chars received, ${beginMarkersSeen} BEGIN markers found). ` +
162
+ 'Unattributed output follows.';
163
+ }
117
164
  if (!success && !noOutputAtAll) {
118
165
  console.error(`[batch-log-parser] ${slug}: summarySuccess=${summarySuccess} hasLogs=${sectionLogs.length > 0} logsLen=${sectionLogs.length}`);
119
166
  }
120
- const testCounts = sectionLogs ? parseTestCounts(sectionLogs) : undefined;
167
+ // Deliberately not parsed from unattributed output: attribution is exactly
168
+ // what failed, so a count read from it could belong to anything. The logs
169
+ // are still shown, so the jest summary remains readable by eye.
170
+ const testCounts = attributedLogs
171
+ ? parseTestCounts(attributedLogs)
172
+ : undefined;
173
+ const tracebackCount = countTracebacks(sectionLogs);
174
+ if (tracebackCount > 0) {
175
+ OutputHelper.warn(`[batch-log-parser] ${slug}: ${tracebackCount} Luau traceback(s) in output. ` +
176
+ 'Jest does not count these — a deferred-callback crash fires outside any test.');
177
+ }
121
178
  // Prefer the JSON summary (authoritative, immune to log reordering);
122
179
  // fall back to the END-marker value if the summary was truncated.
123
180
  const durationMs = summaryDurations.get(slug) ?? markerDurations.get(slug);
@@ -127,10 +184,26 @@ export function parseBatchTestLogs(rawLogs, slugMap) {
127
184
  logs: sectionLogs,
128
185
  durationMs,
129
186
  testCounts,
187
+ tracebackCount,
188
+ error,
130
189
  });
131
190
  }
132
191
  return results;
133
192
  }
193
+ /**
194
+ * Count Luau tracebacks in log output.
195
+ *
196
+ * Reported separately from test counts because jest never sees these: a crash in
197
+ * a deferred callback fires outside any test, so a run can print
198
+ * "Tests: 155 passed, 0 failed" while something is genuinely broken.
199
+ */
200
+ export function countTracebacks(rawOutput) {
201
+ if (!rawOutput) {
202
+ return 0;
203
+ }
204
+ const cleanLogs = OutputHelper.stripAnsi(rawOutput);
205
+ return cleanLogs.match(/Stack Begin\s/g)?.length ?? 0;
206
+ }
134
207
  /**
135
208
  * Check specifically for Jest test suite/test failures in logs.
136
209
  * Unlike parseTestLogs, this ignores "Stack Begin" runtime errors since
@@ -1 +1 @@
1
- {"version":3,"file":"batch-log-parser.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"batch-log-parser.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=batch-log-parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-log-parser.test.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { countTracebacks, parseBatchTestLogs } from './batch-log-parser.js';
3
+ const SLUG_MAP = new Map([['egghunt2026', 'egghunt2026']]);
4
+ function buildLogs(section) {
5
+ return [
6
+ '===BATCH_TEST_BEGIN egghunt2026===',
7
+ section,
8
+ '===BATCH_TEST_END egghunt2026 PASS 1000===',
9
+ '===BATCH_TEST_SUMMARY===',
10
+ '[{"slug":"egghunt2026","success":true,"durationMs":1000}]',
11
+ ].join('\n');
12
+ }
13
+ describe('parseBatchTestLogs', () => {
14
+ it('reads test counts out of a package section', () => {
15
+ const logs = buildLogs('Tests: 275 passed, 275 total');
16
+ const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
17
+ expect(result?.testCounts).toEqual({ passed: 275, failed: 0, total: 275 });
18
+ });
19
+ it('fails a pass it cannot read, rather than trusting the pcall', () => {
20
+ // The summary prints last, so it survives a log window that dropped the
21
+ // head. The pcall said success, but nothing here saw a test run.
22
+ const logs = [
23
+ 'Tests: 275 passed, 275 total',
24
+ '===BATCH_TEST_END egghunt2026 PASS 1000===',
25
+ '===BATCH_TEST_SUMMARY===',
26
+ '[{"slug":"egghunt2026","success":true,"durationMs":1000}]',
27
+ ].join('\n');
28
+ const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
29
+ expect(result?.success).toBe(false);
30
+ expect(result?.error).toContain('No test output could be attributed');
31
+ expect(result?.testCounts).toBeUndefined();
32
+ });
33
+ it('still shows output it could not attribute', () => {
34
+ // 330KB of real test output was being reported as "(no output)" because no
35
+ // BEGIN marker survived to delimit it.
36
+ const logs = [
37
+ 'PlayerBadgeHelper: attempt to index nil',
38
+ '===BATCH_TEST_SUMMARY===',
39
+ '[{"slug":"egghunt2026","success":true,"durationMs":1000}]',
40
+ ].join('\n');
41
+ const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
42
+ expect(result?.logs).toContain('PlayerBadgeHelper');
43
+ });
44
+ it('counts tracebacks that jest reports as a clean pass', () => {
45
+ const logs = buildLogs([
46
+ 'Tests: 155 passed, 155 total',
47
+ 'PlayerBadgeHelper: attempt to index nil',
48
+ 'Stack Begin',
49
+ "Script 'PlayerBadgeHelper', Line 365",
50
+ 'Stack End',
51
+ ].join('\n'));
52
+ const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
53
+ expect(result?.testCounts?.failed).toBe(0);
54
+ expect(result?.tracebackCount).toBe(1);
55
+ });
56
+ });
57
+ describe('countTracebacks', () => {
58
+ it('counts each traceback separately', () => {
59
+ expect(countTracebacks('Stack Begin\nfoo\nStack End\nStack Begin\n')).toBe(2);
60
+ });
61
+ it('is zero for empty output', () => {
62
+ expect(countTracebacks('')).toBe(0);
63
+ });
64
+ });
65
+ //# sourceMappingURL=batch-log-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-log-parser.test.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"test-github-columns.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/reporting/test-github-columns.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAG9B,MAAM,sCAAsC,CAAC;AAG9C,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,mBAAmB,EAAE,CAEzD;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,IAAI,wBAAwB,CAQlE"}
1
+ {"version":3,"file":"test-github-columns.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/reporting/test-github-columns.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAG9B,MAAM,sCAAsC,CAAC;AAG9C,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,mBAAmB,EAAE,CAEzD;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,IAAI,wBAAwB,CASlE"}
@@ -11,6 +11,7 @@ export function createTestCommentConfig() {
11
11
  sectionId: 'tests',
12
12
  extraColumns: createTestColumns(),
13
13
  errorHeading: 'Test Results',
14
+ expectsTestCounts: true,
14
15
  };
15
16
  }
16
17
  function createErrorColumn() {
@@ -1 +1 @@
1
- {"version":3,"file":"test-github-columns.js","sourceRoot":"","sources":["../../../../src/utils/testing/reporting/test-github-columns.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,GACf,MAAM,sCAAsC,CAAC;AAG9C,yEAAyE;AACzE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,iBAAiB,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,OAAO,EAAE,cAAc;QACvB,aAAa,EAAE,iCAAiC;QAChD,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,iBAAiB,EAAE;QACjC,YAAY,EAAE,cAAc;KAC7B,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO;QACL,MAAM,EAAE,OAAO;QACf,UAAU,EAAE,MAAM;QAClB,MAAM,CAAC,GAAiB;YACtB,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,OAAO,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,MAAM,CAAC,GAAiB;YACtB,MAAM,OAAO,GAAI,GAAG,CAAC,MAAsC,EAAE,OAAO,IAAI,CAAC,CAAC;YAC1E,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,OAAO,GAAG,gCAAgC,OAAO,EAAE,CAAC;YAC1D,MAAM,OAAO,GAAG,8CAA8C,OAAO,EAAE,CAAC;YACxE,OAAO,UAAU,OAAO,gBAAgB,OAAO,GAAG,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"test-github-columns.js","sourceRoot":"","sources":["../../../../src/utils/testing/reporting/test-github-columns.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,GACf,MAAM,sCAAsC,CAAC;AAG9C,yEAAyE;AACzE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,iBAAiB,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,OAAO,EAAE,cAAc;QACvB,aAAa,EAAE,iCAAiC;QAChD,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,iBAAiB,EAAE;QACjC,YAAY,EAAE,cAAc;QAC5B,iBAAiB,EAAE,IAAI;KACxB,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO;QACL,MAAM,EAAE,OAAO;QACf,UAAU,EAAE,MAAM;QAClB,MAAM,CAAC,GAAiB;YACtB,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtC,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,OAAO,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,MAAM,CAAC,GAAiB;YACtB,MAAM,OAAO,GAAI,GAAG,CAAC,MAAsC,EAAE,OAAO,IAAI,CAAC,CAAC;YAC1E,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,OAAO,GAAG,gCAAgC,OAAO,EAAE,CAAC;YAC1D,MAAM,OAAO,GAAG,8CAA8C,OAAO,EAAE,CAAC;YACxE,OAAO,UAAU,OAAO,gBAAgB,OAAO,GAAG,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -11,6 +11,8 @@ export interface SingleTestResult {
11
11
  * non-aggregated cloud/local runs — callers should fall back to wall-clock.
12
12
  */
13
13
  durationMs?: number;
14
+ /** Why the run failed, when the runner can say more than "it failed". */
15
+ error?: string;
14
16
  }
15
17
  export interface SingleTestOptions {
16
18
  packagePath: string;
@@ -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,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAQ/B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,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,CA8D3B;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,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAS/B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,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,CAgE3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,MAAM,CAAC,CAajB"}
@@ -3,6 +3,7 @@ import * as path from 'path';
3
3
  import { randomUUID } from 'crypto';
4
4
  import { parseTestLogs, parseTestCounts, } from '../test-log-parser.js';
5
5
  import { buildDeployMetadataAttributes, gatherGitDeployInfo, injectDeployMetadataInPlaceAsync, packageUsesManifestAsync, } from '../../deploy/deploy-metadata.js';
6
+ import { readPackageVersionAsync } from '../../nevermore-cli-utils.js';
6
7
  /**
7
8
  * Build, deploy, and run a test for a single package using the provided
8
9
  * JobContext. The context determines the execution environment (cloud or local).
@@ -28,6 +29,7 @@ export async function runSingleTestAsync(context, options) {
28
29
  timestamp: new Date().toISOString(),
29
30
  placeId: builtPlace.target.placeId,
30
31
  universeId: builtPlace.target.universeId,
32
+ packageVersion: await readPackageVersionAsync(packagePath),
31
33
  }));
32
34
  }
33
35
  const scriptContent = scriptText ??
@@ -50,6 +52,7 @@ export async function runSingleTestAsync(context, options) {
50
52
  logs: parsed.logs,
51
53
  testCounts: parseTestCounts(parsed.logs),
52
54
  durationMs: result.durationMs,
55
+ error: result.errorMessage,
53
56
  };
54
57
  }
55
58
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/nevermore-cli",
3
- "version": "4.40.0",
3
+ "version": "4.41.1",
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.17.0",
29
- "@quenty/nevermore-cli-helpers": "1.16.0",
30
- "@quenty/nevermore-template-helpers": "1.18.0",
31
- "@quenty/studio-bridge": "0.17.0",
28
+ "@quenty/cli-output-helpers": "1.17.1",
29
+ "@quenty/nevermore-cli-helpers": "1.16.1",
30
+ "@quenty/nevermore-template-helpers": "1.18.1",
31
+ "@quenty/studio-bridge": "0.17.1",
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": "2c903e91ae2ea1702ae1ce94af20af83af81e4fe"
60
+ "gitHead": "35993999cfe6fbdfd44721a1835b6ee29602f057"
61
61
  }
@@ -34,7 +34,10 @@ import {
34
34
  discoverChangedTargetPackagesAsync,
35
35
  flattenToBatchTargets,
36
36
  } from '../../utils/batch/changed-packages-utils.js';
37
- import { isCI } from '../../utils/nevermore-cli-utils.js';
37
+ import {
38
+ isCI,
39
+ readPackageVersionAsync,
40
+ } from '../../utils/nevermore-cli-utils.js';
38
41
  import { parseTestLogs } from '../../utils/testing/test-log-parser.js';
39
42
 
40
43
  const SMOKE_TEST_SCRIPT_PATH = resolvePackagePath(
@@ -244,6 +247,7 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
244
247
  timestamp: deployTimestamp,
245
248
  universeId: buildTarget.target.universeId,
246
249
  placeId: buildTarget.target.placeId,
250
+ packageVersion: await readPackageVersionAsync(buildTarget.path),
247
251
  },
248
252
  buildTarget.manifestPlaces
249
253
  )
@@ -171,6 +171,7 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
171
171
  showLogs: args.logs ?? false,
172
172
  verbose: args.verbose,
173
173
  actionVerb: 'Testing',
174
+ expectsTestCounts: true,
174
175
  })
175
176
  : new SpinnerReporter(state, {
176
177
  showLogs: args.logs ?? false,
@@ -251,6 +252,7 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
251
252
  progressSummary: result.testCounts
252
253
  ? { kind: 'test-counts' as const, ...result.testCounts }
253
254
  : undefined,
255
+ error: result.error,
254
256
  };
255
257
  },
256
258
  });
@@ -29,7 +29,11 @@ import { RateLimiter } from '../../utils/open-cloud/rate-limiter.js';
29
29
  import { CloudJobContext } from '../../utils/job-context/cloud-job-context.js';
30
30
  import { runBatchAsync } from '../../utils/batch/batch-runner.js';
31
31
  import { type BatchTarget } from '../../utils/batch/changed-packages-utils.js';
32
- import { isCI, readPackageNameAsync } from '../../utils/nevermore-cli-utils.js';
32
+ import {
33
+ isCI,
34
+ readPackageNameAsync,
35
+ readPackageVersionAsync,
36
+ } from '../../utils/nevermore-cli-utils.js';
33
37
  import {
34
38
  loadDeployConfigAsync,
35
39
  resolveDeployConfigPath,
@@ -248,6 +252,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
248
252
 
249
253
  const cwd = process.cwd();
250
254
  const packageName = (await readPackageNameAsync(cwd)) ?? path.basename(cwd);
255
+ const packageVersion = await readPackageVersionAsync(cwd);
251
256
 
252
257
  const { targetName, autoDetected: targetAutoDetected } =
253
258
  await selectTargetAsync(cwd, {
@@ -414,6 +419,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
414
419
  timestamp: deployTimestamp,
415
420
  universeId: args.universeId ?? buildTarget.target.universeId,
416
421
  placeId: args.placeId ?? buildTarget.target.placeId,
422
+ packageVersion,
417
423
  },
418
424
  buildTarget.manifestPlaces
419
425
  )
@@ -77,6 +77,19 @@ describe('buildDeployMetadataAttributes', () => {
77
77
  expect('Branch' in attributes).toBe(false);
78
78
  });
79
79
 
80
+ it('includes the package version when present', () => {
81
+ const attributes = buildDeployMetadataAttributes(
82
+ {},
83
+ { ...PLACE, packageVersion: '1.0.0' }
84
+ );
85
+ expect(attributes.PackageVersion).toBe('1.0.0');
86
+ });
87
+
88
+ it('omits the package version when unavailable', () => {
89
+ const attributes = buildDeployMetadataAttributes({}, PLACE);
90
+ expect('PackageVersion' in attributes).toBe(false);
91
+ });
92
+
80
93
  it('reflects a Saved (unpublished) deploy', () => {
81
94
  const attributes = buildDeployMetadataAttributes(
82
95
  {},
@@ -75,6 +75,8 @@ export interface DeployPlaceInfo {
75
75
  timestamp: string;
76
76
  placeId: number;
77
77
  universeId: number;
78
+ /** `version` from the deploying package's package.json (e.g. "1.0.0"), if any. */
79
+ packageVersion?: string;
78
80
  }
79
81
 
80
82
  /**
@@ -108,6 +110,7 @@ export function buildDeployMetadataAttributes(
108
110
  if (git.commit) attributes.Commit = git.commit;
109
111
  if (git.version) attributes.Version = git.version;
110
112
  if (git.branch) attributes.Branch = git.branch;
113
+ if (place.packageVersion) attributes.PackageVersion = place.packageVersion;
111
114
  if (places && places.length > 0) {
112
115
  attributes.Places = JSON.stringify(
113
116
  places.map((p) => ({
@@ -113,7 +113,11 @@ export class BatchScriptJobContext implements JobContext {
113
113
  return { success: false };
114
114
  }
115
115
 
116
- return { success: result.success, durationMs: result.durationMs };
116
+ return {
117
+ success: result.success,
118
+ durationMs: result.durationMs,
119
+ errorMessage: result.error,
120
+ };
117
121
  }
118
122
 
119
123
  async getLogsAsync(deployment: Deployment): Promise<string> {
@@ -51,6 +51,21 @@ export async function readPackageNameAsync(
51
51
  }
52
52
  }
53
53
 
54
+ export async function readPackageVersionAsync(
55
+ packagePath: string
56
+ ): Promise<string | undefined> {
57
+ try {
58
+ const content = await fs.readFile(
59
+ path.join(packagePath, 'package.json'),
60
+ 'utf-8'
61
+ );
62
+ const pkg = JSON.parse(content) as { version?: string };
63
+ return pkg.version;
64
+ } catch {
65
+ return undefined;
66
+ }
67
+ }
68
+
54
69
  export async function fileExistsAsync(filePath: string): Promise<boolean> {
55
70
  try {
56
71
  await fs.access(filePath);
@@ -336,7 +336,9 @@ export class OpenCloudClient {
336
336
  private async _fetchRawLogsAsync(taskPath: string): Promise<string> {
337
337
  const apiKey = await this._resolveApiKeyAsync();
338
338
  const messages: string[] = [];
339
+ const structured: { message: string; createTime: string }[] = [];
339
340
  let pageToken: string | undefined;
341
+ let pagesFetched = 0;
340
342
 
341
343
  do {
342
344
  const url = new URL(`https://apis.roblox.com/cloud/v2/${taskPath}/logs`);
@@ -371,18 +373,39 @@ export class OpenCloudClient {
371
373
 
372
374
  for (const entry of data.luauExecutionSessionTaskLogs ?? []) {
373
375
  if (entry.structuredMessages?.length) {
376
+ // Keep createTime alongside the text: the API does not guarantee
377
+ // chronological order, and readers downstream assume it.
374
378
  for (const msg of entry.structuredMessages) {
375
- messages.push(msg.message);
379
+ structured.push({
380
+ message: msg.message,
381
+ createTime: msg.createTime,
382
+ });
376
383
  }
377
384
  } else if (entry.messages?.length) {
378
385
  messages.push(...entry.messages);
379
386
  }
380
387
  }
381
388
 
389
+ pagesFetched++;
382
390
  pageToken = data.nextPageToken || undefined;
383
391
  } while (pageToken);
384
392
 
385
- return messages.join('\n');
393
+ // Out-of-order messages silently destroy marker-delimited parsing: a
394
+ // trailing summary that arrives early ends the scan before any of the
395
+ // output it summarizes has been read.
396
+ structured.sort((a, b) => a.createTime.localeCompare(b.createTime));
397
+ messages.push(...structured.map((m) => m.message));
398
+
399
+ const text = messages.join('\n');
400
+
401
+ // Log volume is the prime suspect when engine output goes missing between
402
+ // the task and the parser, and the parser cannot tell a short run from a
403
+ // truncated fetch. Record what arrived so a real run can settle it.
404
+ OutputHelper.verbose(
405
+ `[open-cloud] Task logs: ${pagesFetched} page(s), ${messages.length} messages, ${text.length} chars`
406
+ );
407
+
408
+ return text;
386
409
  }
387
410
 
388
411
  /**