@neocompose/cli 0.62.1 → 0.63.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.
package/dist/neo.mjs CHANGED
@@ -19678,6 +19678,7 @@ var init_project_schema_contract_generated = __esm({
19678
19678
  "argumentTypes",
19679
19679
  "dispatch",
19680
19680
  "bodyMode",
19681
+ "effect",
19681
19682
  "uiAction",
19682
19683
  "templateId",
19683
19684
  "genericParamId"
@@ -19881,6 +19882,10 @@ var init_project_schema_contract_generated = __esm({
19881
19882
  "Sprite",
19882
19883
  "Audio"
19883
19884
  ],
19885
+ "NeoEffectKind": [
19886
+ "None",
19887
+ "Auto"
19888
+ ],
19884
19889
  "NeoProjectRecordKind": [
19885
19890
  "Project",
19886
19891
  "Member",
@@ -24245,6 +24250,9 @@ function fieldsForAnnotation(name, context, environment) {
24245
24250
  if (context.kind === "type") return null;
24246
24251
  if (name === "storage") return storageFields(context);
24247
24252
  if (name === "distribution") return distributionFields(context);
24253
+ if (name === "effect") {
24254
+ return context.kind === "member" && context.memberKind === "function" ? [{ name: "kind", type: "NeoEffectKind" }] : null;
24255
+ }
24248
24256
  if (name === "relations") return relationFields(context, environment);
24249
24257
  if (name === "system") {
24250
24258
  return context.kind === "class" || context.kind === "schema" || context.kind === "member" ? markerFields("NeoSystemAttribute") : null;
@@ -27804,11 +27812,23 @@ function validateMembers(environment, diagnostics) {
27804
27812
  );
27805
27813
  }
27806
27814
  }
27815
+ for (const member of ref.declaration.members) {
27816
+ const effect = effectAnnotation(member);
27817
+ if (effect === void 0) continue;
27818
+ diagnose(
27819
+ diagnostics,
27820
+ ref.uri,
27821
+ effect.nameRange,
27822
+ "invalid-effect",
27823
+ `Interface member '${ref.declaration.name}.${member.name}' cannot be an @effect; only class member functions can.`
27824
+ );
27825
+ }
27807
27826
  validateInterfaceMemberConflicts(ref, environment, diagnostics);
27808
27827
  }
27809
27828
  for (const ref of environment.classes.values()) {
27810
27829
  validateClassMemberModifiers(ref, environment, diagnostics);
27811
27830
  validateClassOverrides(ref, environment, diagnostics);
27831
+ validateEffects(ref, environment, diagnostics);
27812
27832
  if (ref.declaration.modifiers.includes("abstract")) {
27813
27833
  validateAbstractInterfaceMembers(ref, environment, diagnostics);
27814
27834
  } else {
@@ -28234,6 +28254,70 @@ function validateClassOverrides(ref, environment, diagnostics) {
28234
28254
  }
28235
28255
  }
28236
28256
  }
28257
+ function validateEffects(ref, environment, diagnostics) {
28258
+ let inherited;
28259
+ for (const member of ref.declaration.members) {
28260
+ if (member.kind !== "function") continue;
28261
+ const annotation2 = effectAnnotation(member);
28262
+ let kind = annotation2 === void 0 ? void 0 : effectKind(annotation2);
28263
+ if (annotation2 === void 0) {
28264
+ if (!member.modifiers.includes("override") || !member.modifiers.includes("native")) {
28265
+ continue;
28266
+ }
28267
+ inherited ??= inheritedClassMembers(ref, environment);
28268
+ kind = inheritedEffectKind(inherited, member.name);
28269
+ }
28270
+ if (kind !== "Auto") continue;
28271
+ const problem = effectIneligibility(member);
28272
+ if (problem === null) continue;
28273
+ diagnose(
28274
+ diagnostics,
28275
+ ref.uri,
28276
+ annotation2?.nameRange ?? member.nameRange,
28277
+ "invalid-effect",
28278
+ `'${ref.declaration.name}.${member.name}' cannot be an @effect: ${problem}.`
28279
+ );
28280
+ }
28281
+ }
28282
+ function effectAnnotation(member) {
28283
+ return member.annotations.find((entry) => entry.name === "effect");
28284
+ }
28285
+ function effectKind(annotation2) {
28286
+ if (annotation2.arguments.length === 0) return "Auto";
28287
+ const argument2 = annotation2.arguments.find((entry) => entry.name === "kind") ?? annotation2.arguments.find((entry) => entry.name === void 0);
28288
+ if (argument2 === void 0) return void 0;
28289
+ let expression;
28290
+ try {
28291
+ expression = parseExpression(argument2.text);
28292
+ } catch (error) {
28293
+ if (error instanceof CompileError) return void 0;
28294
+ throw error;
28295
+ }
28296
+ return expression.kind === "contextualEnum" ? expression.name : void 0;
28297
+ }
28298
+ function inheritedEffectKind(inherited, name) {
28299
+ for (let index = inherited.length - 1; index >= 0; index -= 1) {
28300
+ const view = inherited[index];
28301
+ if (!namesEqual(view.member.name, name)) continue;
28302
+ const annotation2 = effectAnnotation(view.member);
28303
+ if (annotation2 !== void 0) return effectKind(annotation2);
28304
+ }
28305
+ return void 0;
28306
+ }
28307
+ function effectIneligibility(member) {
28308
+ if (member.modifiers.includes("static")) {
28309
+ return "a static function has no instance to run for";
28310
+ }
28311
+ if (member.modifiers.includes("native")) {
28312
+ return "a native function has no NeoScript reads to track";
28313
+ }
28314
+ if (member.modifiers.includes("async")) {
28315
+ return "an effect runs immediately and cannot be async";
28316
+ }
28317
+ if (member.type.name !== "void") return "an effect must return void";
28318
+ if (member.parameters.length > 0) return "an effect takes no parameters";
28319
+ return null;
28320
+ }
28237
28321
  function isPlatformImplementedSystemMember(member) {
28238
28322
  if (!member.modifiers.includes("protected")) return false;
28239
28323
  return member.annotations.some((entry) => entry.name === "system");
@@ -28699,6 +28783,8 @@ var init_project_source_type_checker = __esm({
28699
28783
  init_language_spec();
28700
28784
  init_project_source_ast();
28701
28785
  init_lexer();
28786
+ init_executable_parser();
28787
+ init_strict_compile_error();
28702
28788
  init_project_source_accessors();
28703
28789
  init_project_source_identifiers();
28704
28790
  BUILTIN_ARITY = /* @__PURE__ */ new Map([
@@ -30106,6 +30192,7 @@ function projectDeclarationAnnotationNames(declaration) {
30106
30192
  }
30107
30193
  function projectMemberAnnotationNames(member) {
30108
30194
  const names = ["id", "settings", "storage", "distribution"];
30195
+ if (member?.kind === "function") names.push("effect");
30109
30196
  if (member?.type.name === "List") names.push("index", "column");
30110
30197
  return names;
30111
30198
  }
@@ -31770,6 +31857,8 @@ function annotationSignatureParameters(name) {
31770
31857
  return ["StorageKind allowed"];
31771
31858
  case "distribution":
31772
31859
  return ["NeoSubtreeDistribution kind"];
31860
+ case "effect":
31861
+ return ["NeoEffectKind kind"];
31773
31862
  case "relations":
31774
31863
  return ["relation descriptors"];
31775
31864
  case "incomplete":
@@ -38122,6 +38211,7 @@ var init_args = __esm({
38122
38211
  "generate-ids",
38123
38212
  "help",
38124
38213
  "passWithNoTests",
38214
+ "runInBand",
38125
38215
  "no-verify",
38126
38216
  "fix",
38127
38217
  "yes"
@@ -38173,9 +38263,11 @@ var init_args = __esm({
38173
38263
  "outputFile",
38174
38264
  "output-file",
38175
38265
  "testNamePattern",
38266
+ "maxWorkers",
38176
38267
  "test-timeout",
38177
38268
  "testTimeout",
38178
38269
  "passWithNoTests",
38270
+ "runInBand",
38179
38271
  "no-verify"
38180
38272
  ]);
38181
38273
  TEST_ONLY_FLAGS = /* @__PURE__ */ new Set([
@@ -38183,9 +38275,11 @@ var init_args = __esm({
38183
38275
  "outputFile",
38184
38276
  "output-file",
38185
38277
  "testNamePattern",
38278
+ "maxWorkers",
38186
38279
  "test-timeout",
38187
38280
  "testTimeout",
38188
- "passWithNoTests"
38281
+ "passWithNoTests",
38282
+ "runInBand"
38189
38283
  ]);
38190
38284
  }
38191
38285
  });
@@ -40016,7 +40110,7 @@ function assertMemberInvariants(member, path) {
40016
40110
  fail2("script", "is required for a concrete scripted member.");
40017
40111
  }
40018
40112
  }
40019
- var nonEmptyString, nullableString2, nullableId, finiteNumber, nullableNumber, nullableInteger, jsonValueSchema, schemaSourcePositionSchema, schemaSourceSpanSchema, schemaSourceSymbolKinds, schemaSourceIdentitySchema, memberSourceIdentitySchema, systemProtectionKindSchema, worldSystemClassKindSchema, schemaSystemMetadataSchema, schemaGenericBindingSchema, schemaGenericBindingRecordSchema, genericConstraintSchema, schemaGenericParameterSchema, primitiveTypeKinds, schemaTypeCache, returnTypeCache, schemaTypeSchema, schemaFunctionReturnTypeSchema, schemaParameterDefaultSchema, schemaFunctionArgumentSchema, memberOwnerSchema, schemaDefaultValueSchema, propertyScriptSchema, functionScriptSchema, commonMemberEntries, schemaMemberCommonSchema, simpleMemberSchemas, dictionaryKeySchema, schemaListIndexSchema, schemaListColumnSchema, callableEntries, schemaMemberSchema, SchemaMemberContractError;
40113
+ var nonEmptyString, nullableString2, nullableId, finiteNumber, nullableNumber, nullableInteger, jsonValueSchema, schemaSourcePositionSchema, schemaSourceSpanSchema, schemaSourceSymbolKinds, schemaSourceIdentitySchema, memberSourceIdentitySchema, systemProtectionKindSchema, worldSystemClassKindSchema, schemaSystemMetadataSchema, schemaGenericBindingSchema, schemaGenericBindingRecordSchema, genericConstraintSchema, schemaGenericParameterSchema, primitiveTypeKinds, schemaTypeCache, returnTypeCache, schemaTypeSchema, schemaFunctionReturnTypeSchema, schemaParameterDefaultSchema, schemaFunctionArgumentSchema, memberOwnerSchema, schemaDefaultValueSchema, propertyScriptSchema, functionScriptSchema, commonMemberEntries, schemaMemberCommonSchema, simpleMemberSchemas, dictionaryKeySchema, schemaListIndexSchema, schemaListColumnSchema, callableEntries, functionEffectSchema, schemaMemberSchema, SchemaMemberContractError;
40020
40114
  var init_schema_member = __esm({
40021
40115
  "../packages/manifest/src/schema-member.ts"() {
40022
40116
  "use strict";
@@ -40341,6 +40435,7 @@ var init_schema_member = __esm({
40341
40435
  returnType: schemaFunctionReturnTypeSchema,
40342
40436
  arguments: array2(schemaFunctionArgumentSchema)
40343
40437
  };
40438
+ functionEffectSchema = optional(picklist(["none", "auto"]));
40344
40439
  schemaMemberSchema = variant("kind", [
40345
40440
  ...simpleMemberSchemas,
40346
40441
  memberSchema("int", {
@@ -40403,11 +40498,13 @@ var init_schema_member = __esm({
40403
40498
  }),
40404
40499
  memberSchema("function", {
40405
40500
  ...callableEntries,
40406
- deferred: boolean2()
40501
+ deferred: boolean2(),
40502
+ effect: functionEffectSchema
40407
40503
  }),
40408
40504
  memberSchema("scriptFunction", {
40409
40505
  ...callableEntries,
40410
40506
  deferred: boolean2(),
40507
+ effect: functionEffectSchema,
40411
40508
  bodyMode: optional(literal2("ui")),
40412
40509
  uiAction: optional(jsonValueSchema),
40413
40510
  script: nullable(functionScriptSchema)
@@ -40498,6 +40595,7 @@ var init_document_contracts = __esm({
40498
40595
  "argumentTypes",
40499
40596
  "dispatch",
40500
40597
  "bodyMode",
40598
+ "effect",
40501
40599
  "uiAction",
40502
40600
  "templateId",
40503
40601
  "genericParamId"
@@ -42202,12 +42300,24 @@ function memberFromDocument(record6, members, owners, classNames, context) {
42202
42300
  FUNCTION_DISPATCH,
42203
42301
  record6,
42204
42302
  "dispatch"
42205
- ) === "asynchronous"
42303
+ ) === "asynchronous",
42304
+ // The row's own value, not the chain's: an override without `@effect`
42305
+ // inherits, and resolving here would emit the ancestor's kind back
42306
+ // into the override's source as phantom drift.
42307
+ ...data.effect === void 0 || data.effect === null ? {} : {
42308
+ effect: ordinalValue(
42309
+ data.effect,
42310
+ FUNCTION_EFFECT,
42311
+ record6,
42312
+ "effect"
42313
+ )
42314
+ }
42206
42315
  };
42207
42316
  if (kind === MEMBER_KIND.Function) {
42208
42317
  return { ...common, kind: "function", ...signature };
42209
42318
  }
42210
- const code = optionalStringOrNull(field("code", null));
42319
+ const codeValue = field("code", null);
42320
+ const code = codeValue === "" ? "" : optionalStringOrNull(codeValue);
42211
42321
  const bodyModeValue = ordinalValue(
42212
42322
  field("bodyMode", 0),
42213
42323
  FUNCTION_BODY,
@@ -42453,6 +42563,9 @@ function memberToDocumentFields(member, baseData3) {
42453
42563
  if (member.deferred || isOverride) {
42454
42564
  fields.dispatch = member.deferred ? 1 : 0;
42455
42565
  }
42566
+ if (member.effect !== void 0) {
42567
+ fields.effect = FUNCTION_EFFECT.indexOf(member.effect);
42568
+ }
42456
42569
  if (member.kind === "scriptFunction" && member.script !== null && member.bodyMode !== "ui") {
42457
42570
  fields.code = member.script.sourceText;
42458
42571
  }
@@ -43247,7 +43360,7 @@ function invalidDocument(record6, path, message) {
43247
43360
  `${record6.recordKind}:${record6.recordId}.${path} ${message}.`
43248
43361
  );
43249
43362
  }
43250
- var MEMBER_KIND, MEMBER_MODIFIERS, MEMBER_ACCESS, MEMBER_STORAGE, MEMBER_DISTRIBUTION, STRING_FORMAT, MEMBER_SEARCH_BY, MEMBER_SELECTION, FUNCTION_DISPATCH, FUNCTION_BODY, MEMBER_PAYLOAD, DICTIONARY_KEY, LIST_KIND, LIST_INDEX, COLUMN_VISIBILITY, COLUMN_PIN, COLUMN_OVERFLOW, GENERIC_BINDING, TYPE_KIND_BY_MEMBER_KIND, SIMPLE_MEMBER_KIND_BY_KIND, MEMBER_KIND_BY_KIND, TYPE_MEMBER_KIND_BY_KIND, MEMBER_IDENTITY_FIELDS, INHERITED_MEMBER_ORDINAL_FIELDS, NULLABLE_OVERRIDE_MEMBER_FIELDS;
43363
+ var MEMBER_KIND, MEMBER_MODIFIERS, MEMBER_ACCESS, MEMBER_STORAGE, MEMBER_DISTRIBUTION, STRING_FORMAT, MEMBER_SEARCH_BY, MEMBER_SELECTION, FUNCTION_DISPATCH, FUNCTION_BODY, FUNCTION_EFFECT, MEMBER_PAYLOAD, DICTIONARY_KEY, LIST_KIND, LIST_INDEX, COLUMN_VISIBILITY, COLUMN_PIN, COLUMN_OVERFLOW, GENERIC_BINDING, TYPE_KIND_BY_MEMBER_KIND, SIMPLE_MEMBER_KIND_BY_KIND, MEMBER_KIND_BY_KIND, TYPE_MEMBER_KIND_BY_KIND, MEMBER_IDENTITY_FIELDS, INHERITED_MEMBER_ORDINAL_FIELDS, NULLABLE_OVERRIDE_MEMBER_FIELDS;
43251
43364
  var init_codecs = __esm({
43252
43365
  "src/project-manifest/record-adapters/codecs.ts"() {
43253
43366
  "use strict";
@@ -43298,6 +43411,7 @@ var init_codecs = __esm({
43298
43411
  MEMBER_SELECTION = ["single", "multi"];
43299
43412
  FUNCTION_DISPATCH = ["synchronous", "asynchronous"];
43300
43413
  FUNCTION_BODY = ["code", "ui"];
43414
+ FUNCTION_EFFECT = ["none", "auto"];
43301
43415
  MEMBER_PAYLOAD = ["full", "partial"];
43302
43416
  DICTIONARY_KEY = ["string", "enum"];
43303
43417
  LIST_KIND = ["ordered", "unordered"];
@@ -49165,6 +49279,9 @@ var init_structured_leaf_fields = __esm({
49165
49279
  });
49166
49280
 
49167
49281
  // ../src/models/members/member-kinds.ts
49282
+ function isFunctionEffectKind(value) {
49283
+ return value === 0 /* None */ || value === 1 /* Auto */;
49284
+ }
49168
49285
  function isMemberAccessKind(value) {
49169
49286
  return MEMBER_ACCESS_KINDS.includes(value);
49170
49287
  }
@@ -49913,6 +50030,11 @@ function hasValidStorageField(v, allowNull) {
49913
50030
  if (typeof v.kind !== "number") return false;
49914
50031
  return memberKindSupportsStorage(v.kind);
49915
50032
  }
50033
+ function hasValidEffectField(v) {
50034
+ if (v.effect === void 0) return true;
50035
+ if (!isFunctionEffectKind(v.effect)) return false;
50036
+ return v.kind === 13 /* Function */ || v.kind === 23 /* NSFunction */;
50037
+ }
49916
50038
  function hasValidDistributionField(v) {
49917
50039
  if (v.distribution === void 0) return true;
49918
50040
  if (!isNeoSubtreeDistributionKind(v.distribution)) return false;
@@ -49943,6 +50065,7 @@ function isMemberBase(value) {
49943
50065
  }
49944
50066
  if (!hasValidStorageField(v, true)) return false;
49945
50067
  if (!hasValidDistributionField(v)) return false;
50068
+ if (!hasValidEffectField(v)) return false;
49946
50069
  const storageKey = getField(value, "storageKey");
49947
50070
  if (storageKey !== void 0 && storageKey !== null && typeof storageKey !== "string")
49948
50071
  return false;
@@ -50042,6 +50165,7 @@ function isMemberOverrideBase(value) {
50042
50165
  }
50043
50166
  if (!hasValidStorageField(v, false)) return false;
50044
50167
  if (!hasValidDistributionField(v)) return false;
50168
+ if (!hasValidEffectField(v)) return false;
50045
50169
  if (v.defaultValue !== void 0 && v.defaultValue !== null && !isMemberValueBase(v.defaultValue)) {
50046
50170
  return false;
50047
50171
  }
@@ -59701,6 +59825,7 @@ function emitMember(context, member, enclosingClassId) {
59701
59825
  // P76 §1 is never materialized into source, so a member that omits the
59702
59826
  // annotation round-trips as an omission.
59703
59827
  ...member.distribution ? [`@distribution(kind: .${enumCase(member.distribution)})`] : [],
59828
+ ...(member.kind === "function" || member.kind === "scriptFunction") && member.effect !== void 0 ? [member.effect === "auto" ? "@effect" : "@effect(kind: .None)"] : [],
59704
59829
  ...memberSettings(context, member),
59705
59830
  ...listAnnotations(member),
59706
59831
  ...member.system ? [systemAnnotation2(member.system)] : []
@@ -62573,6 +62698,11 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
62573
62698
  };
62574
62699
  }
62575
62700
  );
62701
+ const effect = functionEffectValue(
62702
+ annotation(declaration.annotations, "effect"),
62703
+ ownerClass,
62704
+ declaration
62705
+ );
62576
62706
  const settings = annotation(declaration.annotations, "settings");
62577
62707
  const logicMode = contextualEnumArgument(settings, "logic");
62578
62708
  if (logicMode !== null && logicMode !== "UI") {
@@ -62599,6 +62729,7 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
62599
62729
  returnType,
62600
62730
  arguments: argumentsValue,
62601
62731
  deferred: declaration.modifiers.includes("async"),
62732
+ ...effect,
62602
62733
  ...logicMode === "UI" ? { bodyMode: "ui", uiAction } : {},
62603
62734
  script: {
62604
62735
  kind: "function",
@@ -62616,6 +62747,7 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
62616
62747
  returnType,
62617
62748
  arguments: argumentsValue,
62618
62749
  deferred: declaration.modifiers.includes("async"),
62750
+ ...effect,
62619
62751
  bodyMode: "ui",
62620
62752
  ...uiAction === void 0 ? {} : { uiAction },
62621
62753
  script: null
@@ -62628,6 +62760,7 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
62628
62760
  returnType,
62629
62761
  arguments: argumentsValue,
62630
62762
  deferred: declaration.modifiers.includes("async"),
62763
+ ...effect,
62631
62764
  script: null
62632
62765
  };
62633
62766
  }
@@ -62636,7 +62769,8 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
62636
62769
  kind: "function",
62637
62770
  returnType,
62638
62771
  arguments: argumentsValue,
62639
- deferred: declaration.modifiers.includes("async")
62772
+ deferred: declaration.modifiers.includes("async"),
62773
+ ...effect
62640
62774
  };
62641
62775
  }
62642
62776
  return lowerFieldMember(
@@ -62766,6 +62900,16 @@ function distributionValue(value, ownerClass, declaration) {
62766
62900
  `@distribution on ${site} has unknown kind ".${kind}". Valid kinds are .Sparse and .Packed.`
62767
62901
  );
62768
62902
  }
62903
+ function functionEffectValue(value, ownerClass, declaration) {
62904
+ if (value === void 0) return {};
62905
+ if (value.arguments.length === 0) return { effect: "auto" };
62906
+ const kind = contextualEnumArgument(value, "kind");
62907
+ if (kind === "None") return { effect: "none" };
62908
+ if (kind === "Auto") return { effect: "auto" };
62909
+ throw new Error(
62910
+ `@effect on ${ownerClass.name}.${declaration.name} has unknown kind${kind === null ? "" : ` ".${kind}"`}. Valid kinds are .None and .Auto.`
62911
+ );
62912
+ }
62769
62913
  function resolvedMemberStorage(context, memberId, visited = /* @__PURE__ */ new Set()) {
62770
62914
  if (visited.has(memberId)) return null;
62771
62915
  visited.add(memberId);
@@ -145290,6 +145434,113 @@ var init_project_integrity = __esm({
145290
145434
  }
145291
145435
  });
145292
145436
 
145437
+ // src/test-worker-pool.ts
145438
+ import { Worker as Worker5 } from "node:worker_threads";
145439
+ var TestWorkerPool;
145440
+ var init_test_worker_pool = __esm({
145441
+ "src/test-worker-pool.ts"() {
145442
+ "use strict";
145443
+ TestWorkerPool = class {
145444
+ constructor(workerUrl) {
145445
+ this.workerUrl = workerUrl;
145446
+ }
145447
+ workerUrl;
145448
+ interrupted = false;
145449
+ workers = [];
145450
+ failures = /* @__PURE__ */ new Map();
145451
+ pending = /* @__PURE__ */ new Map();
145452
+ async start(document, count) {
145453
+ await Promise.all(
145454
+ Array.from({ length: count }, async () => {
145455
+ const worker = new Worker5(this.workerUrl);
145456
+ this.workers.push(worker);
145457
+ worker.on(
145458
+ "error",
145459
+ (error) => this.fail(
145460
+ worker,
145461
+ error instanceof Error ? error : new Error(String(error))
145462
+ )
145463
+ );
145464
+ worker.on(
145465
+ "exit",
145466
+ (code) => this.fail(
145467
+ worker,
145468
+ new Error(
145469
+ `Test worker exited before completing its file (code ${code}).`
145470
+ )
145471
+ )
145472
+ );
145473
+ const response = await this.request(worker, { kind: "init", document });
145474
+ if (response.kind !== "ready")
145475
+ throw new Error("Test worker did not initialize its project.");
145476
+ })
145477
+ );
145478
+ }
145479
+ fail(worker, error) {
145480
+ this.failures.set(worker, error);
145481
+ this.pending.get(worker)?.(error);
145482
+ }
145483
+ request(worker, request) {
145484
+ const failure = this.failures.get(worker);
145485
+ if (failure !== void 0) return Promise.reject(failure);
145486
+ return new Promise((resolve5, reject) => {
145487
+ const cleanup = () => {
145488
+ worker.off("message", onMessage);
145489
+ this.pending.delete(worker);
145490
+ };
145491
+ const onMessage = (response) => {
145492
+ cleanup();
145493
+ if (response.kind === "error") reject(new Error(response.message));
145494
+ else resolve5(response);
145495
+ };
145496
+ const onError = (error) => {
145497
+ cleanup();
145498
+ reject(error);
145499
+ };
145500
+ this.pending.set(worker, onError);
145501
+ worker.once("message", onMessage);
145502
+ try {
145503
+ worker.postMessage(request);
145504
+ } catch (error) {
145505
+ onError(error instanceof Error ? error : new Error(String(error)));
145506
+ }
145507
+ });
145508
+ }
145509
+ async run(jobs, timeoutMs, onResult) {
145510
+ let next = 0;
145511
+ await Promise.all(
145512
+ this.workers.map(async (worker) => {
145513
+ while (!this.interrupted && next < jobs.length) {
145514
+ const job = jobs[next++];
145515
+ const response = await this.request(worker, {
145516
+ kind: "run",
145517
+ ...job,
145518
+ timeoutMs
145519
+ });
145520
+ if (response.kind !== "result")
145521
+ throw new Error("Test worker returned no file result.");
145522
+ onResult(job.spec, response.result);
145523
+ }
145524
+ })
145525
+ );
145526
+ }
145527
+ interrupt() {
145528
+ this.interrupted = true;
145529
+ for (const worker of this.workers) {
145530
+ worker.postMessage({ kind: "interrupt" });
145531
+ }
145532
+ }
145533
+ async stop() {
145534
+ for (const reject of this.pending.values())
145535
+ reject(new Error("Test worker stopped."));
145536
+ await Promise.all(this.workers.map((worker) => worker.terminate()));
145537
+ this.workers.length = 0;
145538
+ this.failures.clear();
145539
+ }
145540
+ };
145541
+ }
145542
+ });
145543
+
145293
145544
  // src/neoscript-language-adapter.ts
145294
145545
  function createCliNeoScriptContext(options) {
145295
145546
  const members = [...options.documents.members];
@@ -145299,12 +145550,7 @@ function createCliNeoScriptContext(options) {
145299
145550
  members,
145300
145551
  classes: [...options.documents.classes],
145301
145552
  enums: [...options.documents.enums],
145302
- interfaces: [...options.documents.interfaces],
145303
- databaseVM: {
145304
- memberById: (id2) => members.find(
145305
- (member) => member.id === id2
145306
- ) ?? null
145307
- }
145553
+ interfaces: [...options.documents.interfaces]
145308
145554
  };
145309
145555
  const compilerContext = createNeoScriptDocumentContext({
145310
145556
  vm,
@@ -145346,7 +145592,7 @@ async function validateCliNeoScript(uri, source, context) {
145346
145592
  service.closeDocument(uri);
145347
145593
  }
145348
145594
  }
145349
- function compileCliNeoScript(uri, source, context) {
145595
+ function compileCliNeoScript(uri, source, context, projectIndex) {
145350
145596
  const result = compileNeoScriptStrict(
145351
145597
  {
145352
145598
  uri,
@@ -145354,7 +145600,8 @@ function compileCliNeoScript(uri, source, context) {
145354
145600
  version: 1,
145355
145601
  text: source
145356
145602
  },
145357
- context
145603
+ context,
145604
+ { projectIndex }
145358
145605
  );
145359
145606
  const error = result.diagnostics.find(
145360
145607
  (diagnostic) => diagnostic.severity === "error"
@@ -147354,7 +147601,7 @@ var init_registry2 = __esm({
147354
147601
  "../packages/manifest/schema-contract/registry.mjs"() {
147355
147602
  "use strict";
147356
147603
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
147357
- cliVersion: "0.62.1",
147604
+ cliVersion: "0.63.0",
147358
147605
  projectFileUploadBatchSize: 32,
147359
147606
  documentRecords: {
147360
147607
  member: {
@@ -147406,6 +147653,10 @@ var init_registry2 = __esm({
147406
147653
  "argumentTypes",
147407
147654
  "dispatch",
147408
147655
  "bodyMode",
147656
+ // P97 §1.1. No normalization rule, like `distribution`: absence means
147657
+ // unset (a declaration resolves to `.None`, an override inherits) and
147658
+ // explicit ordinal 0 is an authored `.None` that stops inheritance.
147659
+ "effect",
147409
147660
  "uiAction",
147410
147661
  "templateId",
147411
147662
  "genericParamId"
@@ -147708,7 +147959,8 @@ var init_registry2 = __esm({
147708
147959
  NeoColumnVisibility: ["Visible", "Hidden"],
147709
147960
  NeoColumnPin: ["None", "Leading"],
147710
147961
  NeoColumnOverflow: ["Clip", "Wrap"],
147711
- NeoFileKind: ["Sprite", "Audio"]
147962
+ NeoFileKind: ["Sprite", "Audio"],
147963
+ NeoEffectKind: ["None", "Auto"]
147712
147964
  },
147713
147965
  markers: {
147714
147966
  NeoSchemaClassAttribute: {
@@ -148773,8 +149025,10 @@ var init_registry2 = __esm({
148773
149025
  // src/commands/test.ts
148774
149026
  var test_exports = {};
148775
149027
  __export(test_exports, {
149028
+ executeTestFile: () => executeTestFile,
148776
149029
  inspectNeoTestCompilation: () => inspectNeoTestCompilation,
148777
149030
  maintainNeoTestBuildCache: () => maintainNeoTestBuildCache,
149031
+ prepareTestEvaluator: () => prepareTestEvaluator,
148778
149032
  runTest: () => runTest
148779
149033
  });
148780
149034
  import { createHash as createHash10, randomUUID as randomUUID6 } from "node:crypto";
@@ -148798,6 +149052,7 @@ import {
148798
149052
  resolve as resolve4,
148799
149053
  sep as sep8
148800
149054
  } from "node:path";
149055
+ import { availableParallelism } from "node:os";
148801
149056
  import { isDeepStrictEqual } from "node:util";
148802
149057
  function isRecord11(value) {
148803
149058
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -149119,8 +149374,28 @@ function cacheTestCandidate(workspace, inputFingerprint, candidate) {
149119
149374
  );
149120
149375
  return { ...candidate, documentSha256 };
149121
149376
  }
149122
- function compileSpec(workspace, document, absolutePath, projectCompilationHash2) {
149123
- const scriptDocument = readDocumentArrays(document);
149377
+ function createSpecCompiler(document) {
149378
+ const context = withNeoTestPrelude({
149379
+ ...createCliNeoScriptContext({
149380
+ documents: readDocumentArrays(document),
149381
+ kind: "function",
149382
+ thisClass: null
149383
+ }),
149384
+ kind: "function",
149385
+ projectSourceKind: "spec",
149386
+ returnType: { kind: "primitive", name: "void" }
149387
+ });
149388
+ const projectIndex = createProjectIndex(context.project);
149389
+ return (uri, source) => compileCliNeoScript(uri, source, context, projectIndex);
149390
+ }
149391
+ function lazySpecCompiler(document) {
149392
+ let compiler;
149393
+ return (uri, source) => {
149394
+ compiler ??= createSpecCompiler(document);
149395
+ return compiler(uri, source);
149396
+ };
149397
+ }
149398
+ function compileSpec(workspace, compile, absolutePath, projectCompilationHash2) {
149124
149399
  const path = relative8(workspace.root, absolutePath).split(sep8).join("/");
149125
149400
  const source = readFileSync19(absolutePath, "utf8");
149126
149401
  const sourceHash = createHash10("sha256").update(source).digest("hex");
@@ -149143,21 +149418,10 @@ function compileSpec(workspace, document, absolutePath, projectCompilationHash2)
149143
149418
  }
149144
149419
  } catch {
149145
149420
  }
149146
- const baseContext2 = createCliNeoScriptContext({
149147
- documents: scriptDocument,
149148
- kind: "function",
149149
- thisClass: null
149150
- });
149151
- const context = withNeoTestPrelude({
149152
- ...baseContext2,
149153
- kind: "function",
149154
- projectSourceKind: "spec",
149155
- returnType: { kind: "primitive", name: "void" }
149156
- });
149157
149421
  const compiled = {
149158
149422
  path,
149159
149423
  source,
149160
- action: compileCliNeoScript(`file://${absolutePath}`, source, context)
149424
+ action: compile(`file://${absolutePath}`, source)
149161
149425
  };
149162
149426
  atomicWrite(
149163
149427
  artifactPath,
@@ -149837,6 +150101,18 @@ function failureFor(error, file, position, member = null) {
149837
150101
  function suiteHasSelectedTests(suite, selected) {
149838
150102
  return suite.tests.some((test) => selected.has(test.id)) || suite.suites.some((child) => suiteHasSelectedTests(child, selected));
149839
150103
  }
150104
+ function prepareTestEvaluator(document) {
150105
+ sharedEvaluatorBase(document);
150106
+ }
150107
+ async function executeTestFile(spec, document, selected, timeoutMs, interrupted = () => false) {
150108
+ return executeRegisteredSpec(
150109
+ registerSpec(spec, document),
150110
+ document,
150111
+ selected,
150112
+ timeoutMs,
150113
+ interrupted
150114
+ );
150115
+ }
149840
150116
  async function executeRegisteredSpec(registered, document, selected, timeoutMs, interrupted) {
149841
150117
  const results = [];
149842
150118
  const fileFailures = [];
@@ -150035,8 +150311,11 @@ async function runTest(workspace, options, dependencies = {}) {
150035
150311
  let testDurationMs = 0;
150036
150312
  let exitCode = 0;
150037
150313
  let interrupted = false;
150314
+ let workerPool;
150315
+ let parallelExecution = false;
150038
150316
  const handleSigint = () => {
150039
150317
  interrupted = true;
150318
+ workerPool?.interrupt();
150040
150319
  };
150041
150320
  const assertNotInterrupted = () => {
150042
150321
  if (interrupted) {
@@ -150051,6 +150330,7 @@ async function runTest(workspace, options, dependencies = {}) {
150051
150330
  select: 0,
150052
150331
  compile: 0,
150053
150332
  register: 0,
150333
+ workers: 0,
150054
150334
  execute: 0,
150055
150335
  finalize: 0
150056
150336
  };
@@ -150081,6 +150361,9 @@ async function runTest(workspace, options, dependencies = {}) {
150081
150361
  }
150082
150362
  if (candidate === null) {
150083
150363
  const prepared = dependencies.prepareLocalCandidate === void 0 ? await prepareLocalCandidateV4(workspace, {
150364
+ // Tests need the compiled, validated candidate. Serializing it
150365
+ // back to source and re-lowering is a push dry-run check.
150366
+ fullValidation: false,
150084
150367
  onPhase: (label) => {
150085
150368
  dependencies.progress?.update(label);
150086
150369
  }
@@ -150132,8 +150415,9 @@ async function runTest(workspace, options, dependencies = {}) {
150132
150415
  );
150133
150416
  }
150134
150417
  enterPhase("compile", "Compiling test files\u2026");
150418
+ const compile = lazySpecCompiler(rawDocument);
150135
150419
  specs = selectedPaths.map(
150136
- (path) => compileSpec(workspace, rawDocument, path, compilationHash)
150420
+ (path) => compileSpec(workspace, compile, path, compilationHash)
150137
150421
  );
150138
150422
  let pattern = null;
150139
150423
  if (options.testNamePattern !== null) {
@@ -150162,21 +150446,54 @@ async function runTest(workspace, options, dependencies = {}) {
150162
150446
  );
150163
150447
  }
150164
150448
  const selectedIds = new Set(selectedTests.map((test) => test.id));
150165
- enterPhase("execute", "Running tests\u2026");
150166
150449
  const timeoutMs = options.timeoutMs ?? workspace.config.test?.timeoutMs ?? 5e3;
150167
- for (const entry of registered) {
150168
- const executed = await executeRegisteredSpec(
150169
- entry,
150170
- rawDocument,
150171
- selectedIds,
150172
- timeoutMs,
150173
- () => interrupted
150174
- );
150450
+ const maxWorkers = options.maxWorkers ?? workspace.config.test?.maxWorkers ?? Math.min(4, availableParallelism());
150451
+ if (!Number.isSafeInteger(maxWorkers) || maxWorkers <= 0) {
150452
+ throw new NeoTestUsageError("--maxWorkers must be a positive integer.");
150453
+ }
150454
+ const jobs = registered.filter(
150455
+ (entry) => (selectedTestCountByFile.get(entry.spec.path) ?? 0) > 0
150456
+ );
150457
+ const workerCount = options.runInBand === true ? 1 : Math.min(maxWorkers, jobs.length);
150458
+ const recordResult = (spec, executed) => {
150175
150459
  results.push(...executed.tests);
150176
150460
  testDurationMs += executed.testDurationMs;
150177
- fileFailuresByPath.set(entry.spec.path, executed.failures);
150461
+ fileFailuresByPath.set(spec.path, executed.failures);
150462
+ };
150463
+ if (workerCount > 1) {
150464
+ enterPhase("workers", "Starting test workers\u2026");
150465
+ workerPool = new TestWorkerPool(
150466
+ new URL("./test-worker.mjs", import.meta.url)
150467
+ );
150468
+ await workerPool.start(rawDocument, workerCount);
150178
150469
  assertNotInterrupted();
150470
+ parallelExecution = true;
150471
+ enterPhase("execute", "Running tests\u2026");
150472
+ await workerPool.run(
150473
+ jobs.map((entry) => ({
150474
+ spec: entry.spec,
150475
+ selectedIds: entry.tests.filter((test) => selectedIds.has(test.id)).map((test) => test.id)
150476
+ })),
150477
+ timeoutMs,
150478
+ recordResult
150479
+ );
150480
+ } else {
150481
+ enterPhase("execute", "Running tests\u2026");
150482
+ for (const entry of jobs) {
150483
+ recordResult(
150484
+ entry.spec,
150485
+ await executeRegisteredSpec(
150486
+ entry,
150487
+ rawDocument,
150488
+ selectedIds,
150489
+ timeoutMs,
150490
+ () => interrupted
150491
+ )
150492
+ );
150493
+ assertNotInterrupted();
150494
+ }
150179
150495
  }
150496
+ assertNotInterrupted();
150180
150497
  if (results.some((result) => result.status === "failed") || [...fileFailuresByPath.values()].some((failures) => failures.length > 0)) {
150181
150498
  exitCode = 1;
150182
150499
  }
@@ -150184,7 +150501,7 @@ async function runTest(workspace, options, dependencies = {}) {
150184
150501
  const buildManifest = {
150185
150502
  version: 1,
150186
150503
  cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
150187
- runnerRevision: 3,
150504
+ runnerRevision: 4,
150188
150505
  compilerRevision: NEOSCRIPT_COMPILER_REVISION,
150189
150506
  evaluatorRevision: 4,
150190
150507
  projectFingerprint,
@@ -150204,12 +150521,12 @@ async function runTest(workspace, options, dependencies = {}) {
150204
150521
  `
150205
150522
  );
150206
150523
  } catch (error) {
150207
- const diagnosticCode = error instanceof NeoTestInterruptedError ? "NEO_TEST_INTERRUPTED" : error instanceof NeoTestPreparedCandidateError ? "NEO_TEST_PREPARED_CANDIDATE" : error instanceof NeoTestUsageError ? "NEO_TEST_USAGE" : error instanceof NeoTestNoTestsError ? "NEO_TEST_NO_TESTS" : error instanceof NeoTestRegistrationError ? "NEO_TEST_REGISTRATION" : phase === "prepare" ? "NEO_TEST_PREPARATION" : phase === "compile" ? "NEO_TEST_COMPILE" : "NEO_TEST_RUNNER";
150208
- exitCode = error instanceof NeoTestInterruptedError ? 130 : error instanceof NeoTestUsageError || error instanceof NeoTestReportWriteError || error instanceof NeoTestPreparedCandidateError || diagnosticCode === "NEO_TEST_RUNNER" ? 2 : 1;
150524
+ const diagnosticCode = interrupted || error instanceof NeoTestInterruptedError ? "NEO_TEST_INTERRUPTED" : error instanceof NeoTestPreparedCandidateError ? "NEO_TEST_PREPARED_CANDIDATE" : error instanceof NeoTestUsageError ? "NEO_TEST_USAGE" : error instanceof NeoTestNoTestsError ? "NEO_TEST_NO_TESTS" : error instanceof NeoTestRegistrationError ? "NEO_TEST_REGISTRATION" : phase === "prepare" ? "NEO_TEST_PREPARATION" : phase === "compile" ? "NEO_TEST_COMPILE" : "NEO_TEST_RUNNER";
150525
+ exitCode = interrupted || error instanceof NeoTestInterruptedError ? 130 : error instanceof NeoTestUsageError || error instanceof NeoTestReportWriteError || error instanceof NeoTestPreparedCandidateError || diagnosticCode === "NEO_TEST_RUNNER" ? 2 : 1;
150209
150526
  diagnostics.push({
150210
150527
  severity: "error",
150211
150528
  code: diagnosticCode,
150212
- message: errorMessage2(error),
150529
+ message: interrupted ? "Neo test was interrupted by SIGINT; partial results were written." : errorMessage2(error),
150213
150530
  file: null,
150214
150531
  line: null,
150215
150532
  column: null,
@@ -150217,6 +150534,7 @@ async function runTest(workspace, options, dependencies = {}) {
150217
150534
  });
150218
150535
  }
150219
150536
  finishPhase();
150537
+ await workerPool?.stop();
150220
150538
  dependencies.progress?.stop();
150221
150539
  process.off("SIGINT", handleSigint);
150222
150540
  const failed = results.filter((result) => result.status === "failed").length;
@@ -150226,21 +150544,33 @@ async function runTest(workspace, options, dependencies = {}) {
150226
150544
  );
150227
150545
  const skipped = Math.max(0, selectedTestTotal - results.length);
150228
150546
  const durationMs = performance.now() - performanceStarted;
150229
- const startupDurationMs = Math.max(0, durationMs - testDurationMs);
150547
+ const startupDurationMs = parallelExecution ? Math.max(0, durationMs - phaseDurations.execute) : Math.max(0, durationMs - testDurationMs);
150230
150548
  const perTestStartupDurationMs = results.reduce(
150231
150549
  (sum, result) => sum + result.startupDurationMs,
150232
150550
  0
150233
150551
  );
150234
150552
  const sharedStartupDurationMs = Math.max(
150235
150553
  0,
150236
- startupDurationMs - perTestStartupDurationMs
150554
+ startupDurationMs - (parallelExecution ? 0 : perTestStartupDurationMs)
150237
150555
  );
150556
+ const testsByFile = /* @__PURE__ */ new Map();
150557
+ for (const result of results) {
150558
+ const tests = testsByFile.get(result.file) ?? [];
150559
+ tests.push(result);
150560
+ testsByFile.set(result.file, tests);
150561
+ }
150238
150562
  const testFiles = specs.map((spec) => {
150239
- const tests = results.filter((result) => result.file === spec.path);
150563
+ const tests = testsByFile.get(spec.path) ?? [];
150240
150564
  const failures = fileFailuresByPath.get(spec.path) ?? [];
150565
+ let status = "passed";
150566
+ if (tests.some((test) => test.status === "failed") || failures.length > 0) {
150567
+ status = "failed";
150568
+ } else if (tests.length < (selectedTestCountByFile.get(spec.path) ?? 0) && exitCode !== 0) {
150569
+ status = interrupted ? "interrupted" : "failed";
150570
+ }
150241
150571
  return {
150242
150572
  path: spec.path,
150243
- status: tests.some((test) => test.status === "failed") || failures.length > 0 ? "failed" : interrupted && tests.length < (selectedTestCountByFile.get(spec.path) ?? 0) ? "interrupted" : "passed",
150573
+ status,
150244
150574
  tests,
150245
150575
  failures
150246
150576
  };
@@ -150276,6 +150606,7 @@ async function runTest(workspace, options, dependencies = {}) {
150276
150606
  selectMs: phaseDurations.select,
150277
150607
  compileMs: phaseDurations.compile,
150278
150608
  registerMs: phaseDurations.register,
150609
+ workerStartupMs: phaseDurations.workers,
150279
150610
  executeMs: phaseDurations.execute,
150280
150611
  finalizeMs: phaseDurations.finalize
150281
150612
  },
@@ -150357,8 +150688,9 @@ async function runTest(workspace, options, dependencies = {}) {
150357
150688
  console.log(
150358
150689
  ` ${color.bold(pad("Tests", 11))} ${formatStatusCounts(report.summary.passed, report.summary.failed, report.summary.tests, report.summary.skipped)}`
150359
150690
  );
150691
+ const timingDetail = parallelExecution ? `test work ${formatTestDuration(report.summary.testDurationMs)}, execution ${formatTestDuration(report.timings.executeMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)}` : `test ${formatTestDuration(report.summary.testDurationMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)}`;
150360
150692
  console.log(
150361
- ` ${color.bold(pad("Duration", 11))} ${color.bold(`total ${formatTestDuration(report.summary.durationMs)}`)} ${color.dim(`(test ${formatTestDuration(report.summary.testDurationMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)})`)}`
150693
+ ` ${color.bold(pad("Duration", 11))} ${color.bold(`total ${formatTestDuration(report.summary.durationMs)}`)} ${color.dim(`(${timingDetail})`)}`
150362
150694
  );
150363
150695
  }
150364
150696
  if (!report.success) process.exitCode = exitCode;
@@ -150388,9 +150720,10 @@ async function inspectNeoTestCompilation(workspace, dependencies = {}) {
150388
150720
  document
150389
150721
  );
150390
150722
  const errors = [];
150723
+ const compile = lazySpecCompiler(document);
150391
150724
  for (const path of selectedPaths) {
150392
150725
  try {
150393
- compileSpec(workspace, document, path, compilationHash);
150726
+ compileSpec(workspace, compile, path, compilationHash);
150394
150727
  } catch (error) {
150395
150728
  errors.push({
150396
150729
  file: relative8(workspace.root, path).split(sep8).join("/"),
@@ -150409,6 +150742,7 @@ var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, TEST_CANDIDATE_CACH
150409
150742
  var init_test = __esm({
150410
150743
  "src/commands/test.ts"() {
150411
150744
  "use strict";
150745
+ init_test_worker_pool();
150412
150746
  init_src();
150413
150747
  init_members();
150414
150748
  init_neoscript2();
@@ -155345,7 +155679,7 @@ function readManifest(path) {
155345
155679
  });
155346
155680
  return { projectId: data.projectId, files };
155347
155681
  }
155348
- function writeUnityGeneratedFiles(directory, projectId, files) {
155682
+ function writeUnityGeneratedFiles(directory, projectId, files, codegenRevision) {
155349
155683
  if (!Array.isArray(files) || files.length === 0)
155350
155684
  throw new Error(
155351
155685
  "The export returned no generated files. Update the server before exporting Unity code."
@@ -155409,6 +155743,7 @@ function writeUnityGeneratedFiles(directory, projectId, files) {
155409
155743
  {
155410
155744
  schemaVersion: 1,
155411
155745
  projectId,
155746
+ codegenRevision,
155412
155747
  files: [...files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0).map((file) => ({
155413
155748
  id: file.id,
155414
155749
  path: file.path,
@@ -155490,7 +155825,8 @@ async function runExportUnity(workspace, outDir) {
155490
155825
  writeUnityGeneratedFiles(
155491
155826
  scriptsDir,
155492
155827
  response.projectId,
155493
- response.generatedFiles
155828
+ response.generatedFiles,
155829
+ response.codegenRevision
155494
155830
  );
155495
155831
  writeFileSync16(join19(resourcesDir, "project.json"), response.projectJson);
155496
155832
  for (const file of response.localizationFiles ?? []) {
@@ -155947,6 +156283,11 @@ ${h("Usage")}
155947
156283
  neo test ${d("[file-or-directory ...]")}
155948
156284
  neo test -t ${d('"name pattern"')}
155949
156285
  neo test ${d("--reporter=json --outputFile=output.json")}
156286
+ neo test ${d("--maxWorkers=4")}
156287
+ neo test ${d("--runInBand")}
156288
+
156289
+ Files run in parallel, using up to four available CPU workers by default.
156290
+ --maxWorkers overrides neo.json test.maxWorkers; --runInBand runs serially.
155950
156291
 
155951
156292
  Tests execute against the locally compiled candidate graph, including changes
155952
156293
  that have not been pushed. Test files are never included in a push.
@@ -156034,7 +156375,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
156034
156375
  async function main() {
156035
156376
  const args = parseArgs(process.argv.slice(2));
156036
156377
  if (args.command === "--version") {
156037
- console.log("0.62.1");
156378
+ console.log("0.63.0");
156038
156379
  return;
156039
156380
  }
156040
156381
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
@@ -156360,6 +156701,11 @@ async function main() {
156360
156701
  "--testTimeout must be a positive number of milliseconds."
156361
156702
  );
156362
156703
  }
156704
+ const maxWorkersValue = stringFlag(args, "maxWorkers");
156705
+ const maxWorkers = maxWorkersValue === null ? void 0 : Number(maxWorkersValue);
156706
+ if (maxWorkers !== void 0 && (!Number.isSafeInteger(maxWorkers) || maxWorkers <= 0)) {
156707
+ throw new NeoCliUsageError("--maxWorkers must be a positive integer.");
156708
+ }
156363
156709
  const progress = reporterValue === "default" && process.stdout.isTTY === true ? spinner("Reading local workspace\u2026") : null;
156364
156710
  try {
156365
156711
  const workspace = loadWorkspaceForCommand(args);
@@ -156372,6 +156718,8 @@ async function main() {
156372
156718
  reporter: reporterValue,
156373
156719
  outputFile: stringFlag(args, "outputFile") ?? stringFlag(args, "output-file"),
156374
156720
  passWithNoTests: boolFlag(args, "passWithNoTests"),
156721
+ runInBand: boolFlag(args, "runInBand"),
156722
+ ...maxWorkers === void 0 ? {} : { maxWorkers },
156375
156723
  ...timeoutMs === void 0 ? {} : { timeoutMs }
156376
156724
  },
156377
156725
  progress === null ? {} : { progress }