@neocompose/cli 0.36.2 → 0.36.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.36.4] - 2026-08-19
4
+
5
+ ### Fixed
6
+
7
+ - Keep computed static/root binding value identities derived from their member
8
+ ids, so post-push source rewriting never inserts an `@id` inside the
9
+ initializer expression.
10
+ - Validate assigned-id source rewriting during `neo push --dry-run`, and keep
11
+ materialized scalar bindings stable so a successful push is followed by a
12
+ clean `neo status` without changing the authored initializer expression.
13
+
14
+ ## [0.36.3] - 2026-08-19
15
+
16
+ ### Fixed
17
+
18
+ - Preserve nullable List and Dictionary entry declarations in persisted
19
+ compiler contexts, and keep abstract stored collection fields writable
20
+ through the concrete subclass storage that implements them. Indexed
21
+ `is`-pattern reads and writes such as `Stacks[index] = null` now agree in
22
+ source analysis, IntelliSense, `neo script check --all`, and push replay.
23
+ - Run `neo script check --all` against one locally reconstructed prospective
24
+ project document instead of fetching a stale server document through a
25
+ separate path. New records, managed files, dialogues, and stored bodies are
26
+ validated with the same source transaction visible to local member bodies.
27
+ - Compile canonical `Reference<NeoImage>(id: ...).Slice(...)` and
28
+ `Reference<NeoAudioClip>(id: ...)` file fallbacks when a pulled file has no
29
+ registry symbol, and accept `List.Repeat<T>(value, count)` when an explicit
30
+ entry type is needed for values such as `null`.
31
+ - Include same-transaction texture and audio import-template changes in the
32
+ prospective document before validating managed-file defaults.
33
+
3
34
  ## [0.36.2] - 2026-08-19
4
35
 
5
36
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -1278,6 +1278,12 @@ function neoScriptRegistryEntryType(typeName) {
1278
1278
  }
1279
1279
  return REGISTRY_ENTRY_TYPES[typeName] ?? null;
1280
1280
  }
1281
+ function neoScriptRegistryReferenceType(entryTypeName) {
1282
+ for (const definition2 of Object.values(REGISTRY_ENTRY_TYPES)) {
1283
+ if (definition2.entryType === entryTypeName) return definition2.refType;
1284
+ }
1285
+ return null;
1286
+ }
1281
1287
  function parameter(name, type) {
1282
1288
  return { name, type };
1283
1289
  }
@@ -11398,6 +11404,19 @@ var init_strict_resolver = __esm({
11398
11404
  expression.pos
11399
11405
  );
11400
11406
  }
11407
+ if (isPrimitive(referencedType, "ImageRef") || isPrimitive(referencedType, "AudioClipRef")) {
11408
+ if (hasProvenanceArgument) {
11409
+ throw new CompileError(
11410
+ `Reference<${referenceTypeArgument.kind === "named" ? referenceTypeArgument.name : "file"}> does not support withProvenance because a project file reference is a file id, not a value-row reference.`,
11411
+ expression.pos
11412
+ );
11413
+ }
11414
+ return literal(
11415
+ referencedType,
11416
+ expression.args[0].value,
11417
+ this.project
11418
+ );
11419
+ }
11401
11420
  return {
11402
11421
  pointer: {
11403
11422
  type: "reference" /* Reference */,
@@ -11407,6 +11426,37 @@ var init_strict_resolver = __esm({
11407
11426
  type: referencedType
11408
11427
  };
11409
11428
  }
11429
+ if (expression.typeArguments && expression.callee.kind === "member" && expression.callee.receiver.kind === "ident" && expression.callee.receiver.name === NEOSCRIPT_LIST_TYPE_NAME) {
11430
+ if (expression.callee.name !== NEOSCRIPT_LIST_REPEAT_NAME) {
11431
+ throw new CompileError(
11432
+ `'${NEOSCRIPT_LIST_TYPE_NAME}' has no generic static member '${expression.callee.name}'.`,
11433
+ expression.pos
11434
+ );
11435
+ }
11436
+ if (expression.typeArguments.length !== 1) {
11437
+ throw new CompileError(
11438
+ `${NEOSCRIPT_LIST_TYPE_NAME}.${NEOSCRIPT_LIST_REPEAT_NAME}<T> requires exactly one entry type argument.`,
11439
+ expression.pos
11440
+ );
11441
+ }
11442
+ const entryTypeArgument = expression.typeArguments[0];
11443
+ if (entryTypeArgument === void 0) {
11444
+ throw new CompileError(
11445
+ `${NEOSCRIPT_LIST_TYPE_NAME}.${NEOSCRIPT_LIST_REPEAT_NAME}<T> requires exactly one entry type argument.`,
11446
+ expression.pos
11447
+ );
11448
+ }
11449
+ return this.resolveListStaticCall(
11450
+ expression.callee.name,
11451
+ expression.args,
11452
+ scope,
11453
+ {
11454
+ kind: "list",
11455
+ elementType: this.resolveType(entryTypeArgument)
11456
+ },
11457
+ expression.pos
11458
+ );
11459
+ }
11410
11460
  if (expression.typeArguments) {
11411
11461
  throw new CompileError(
11412
11462
  "Generic intrinsic calls require a declaration-aware project source context.",
@@ -15209,11 +15259,17 @@ var init_strict_resolver = __esm({
15209
15259
  */
15210
15260
  assertActionControlAccessible(action, operation, pos) {
15211
15261
  const symbol = action.symbol;
15212
- const owner = symbol === void 0 ? void 0 : symbol.inheritedFrom ? this.project.typeById.get(symbol.inheritedFrom.typeId) : [...this.project.typeById.values()].find(
15213
- (type) => type.members.some(
15214
- (candidate) => candidate.id === symbol.id && candidate.inheritedFrom === void 0
15215
- )
15216
- );
15262
+ let owner = symbol?.inheritedFrom ? this.project.typeById.get(symbol.inheritedFrom.typeId) : void 0;
15263
+ if (symbol !== void 0 && symbol.inheritedFrom === void 0) {
15264
+ for (const type of this.project.typeById.values()) {
15265
+ if (type.members.some(
15266
+ (candidate) => candidate.id === symbol.id && candidate.inheritedFrom === void 0
15267
+ )) {
15268
+ owner = type;
15269
+ break;
15270
+ }
15271
+ }
15272
+ }
15217
15273
  if (symbol !== void 0 && owner !== void 0 && memberAccessFailure({
15218
15274
  project: this.project,
15219
15275
  context: this.context,
@@ -15535,6 +15591,11 @@ var init_strict_resolver = __esm({
15535
15591
  resolved = { kind: "primitive", name: builtin };
15536
15592
  break;
15537
15593
  }
15594
+ const registryReference = neoScriptRegistryReferenceType(type.name);
15595
+ if (registryReference) {
15596
+ resolved = registryReference;
15597
+ break;
15598
+ }
15538
15599
  const named = this.project.typeByName.get(type.name);
15539
15600
  if (!named)
15540
15601
  throw new CompileError(`Unknown type '${type.name}'`, type.pos);
@@ -32603,10 +32664,8 @@ function attachConstructorSignature(type, environment) {
32603
32664
  type.id,
32604
32665
  environment
32605
32666
  );
32606
- if ([...genericEnvironment.values()].some(
32607
- (binding) => binding.kind === "unbound"
32608
- )) {
32609
- return type;
32667
+ for (const binding of genericEnvironment.values()) {
32668
+ if (binding.kind === "unbound") return type;
32610
32669
  }
32611
32670
  const constructorSignature2 = buildNeoScriptConstructorSignature(
32612
32671
  type.id,
@@ -32939,7 +32998,7 @@ function memberSymbol(member, schemaKey, environment, field) {
32939
32998
  writable: false
32940
32999
  };
32941
33000
  }
32942
- const writable = isReadOnly ? false : kind === "computed" ? computedHasSetter(member, field) : modifier !== "abstract" && member.locked !== true;
33001
+ const writable = isReadOnly ? false : kind === "computed" ? computedHasSetter(member, field) : member.locked !== true;
32943
33002
  const storage = typeof member.storage === "string" ? member.storage : void 0;
32944
33003
  const writability = isReadOnly ? "readOnly" : kind === "computed" ? writable ? "setter" : "readOnly" : !writable ? "readOnly" : storage === "immutable" || storage === "save" || storage === "session" ? storage : isStatic && ownerClassId ? staticDefaultWritability(ownerClassId, environment) : void 0;
32945
33004
  const lookupCollectionMemberId = kind === "lookup" ? string2(member.collectionMemberId, `${field}.collectionMemberId`) : null;
@@ -33475,9 +33534,12 @@ function memberType(member, environment, visiting, field) {
33475
33534
  };
33476
33535
  }
33477
33536
  if (kind === "variant") {
33478
- const variantClass = [...environment.classes.values()].find(
33479
- (candidate) => candidate.name === NEO_VARIANT_TYPE_NAME
33480
- );
33537
+ let variantClass;
33538
+ for (const candidate of environment.classes.values()) {
33539
+ if (candidate.name !== NEO_VARIANT_TYPE_NAME) continue;
33540
+ variantClass = candidate;
33541
+ break;
33542
+ }
33481
33543
  if (variantClass === void 0) return { ...unknownType(), nullable };
33482
33544
  return {
33483
33545
  kind: "named",
@@ -61766,7 +61828,8 @@ function interfaceToLanguageType(neoInterface, context) {
61766
61828
  closure = [neoInterface];
61767
61829
  }
61768
61830
  const members = /* @__PURE__ */ new Map();
61769
- for (const source of [...closure].reverse()) {
61831
+ for (let index = closure.length - 1; index >= 0; index -= 1) {
61832
+ const source = closure[index];
61770
61833
  for (const key of getInterfaceMemberKeyOrder(source)) {
61771
61834
  const member = source.members[key];
61772
61835
  if (!member) continue;
@@ -62013,13 +62076,11 @@ function memberRuntimeType(record3, context, seen = /* @__PURE__ */ new Set(), g
62013
62076
  const projectedEntry = entry ? substituteForGenericEnvironment(entry, genericEnvironment, context) : null;
62014
62077
  return {
62015
62078
  kind: "list",
62016
- elementType: projectedEntry ? requiredType(
62017
- memberRuntimeType(
62018
- projectedEntry,
62019
- context,
62020
- nextSeen,
62021
- genericEnvironment
62022
- )
62079
+ elementType: projectedEntry ? memberRuntimeType(
62080
+ projectedEntry,
62081
+ context,
62082
+ nextSeen,
62083
+ genericEnvironment
62023
62084
  ) : UNKNOWN_TYPE2,
62024
62085
  listMemberId: record3.id,
62025
62086
  nullable: !required2
@@ -62032,13 +62093,11 @@ function memberRuntimeType(record3, context, seen = /* @__PURE__ */ new Set(), g
62032
62093
  return {
62033
62094
  kind: "dictionary",
62034
62095
  keyType: member.keyKind === "enum" && member.keyEnumId ? namedType(member.keyEnumId, true) : primitive2("string", true),
62035
- valueType: projectedEntry ? requiredType(
62036
- memberRuntimeType(
62037
- projectedEntry,
62038
- context,
62039
- nextSeen,
62040
- genericEnvironment
62041
- )
62096
+ valueType: projectedEntry ? memberRuntimeType(
62097
+ projectedEntry,
62098
+ context,
62099
+ nextSeen,
62100
+ genericEnvironment
62042
62101
  ) : UNKNOWN_TYPE2,
62043
62102
  nullable: !required2
62044
62103
  };
@@ -63037,7 +63096,10 @@ function initializerReferencesLexicalThis(source) {
63037
63096
  }
63038
63097
  function initializerReferencesAnyIdentifier(source, names) {
63039
63098
  const identifiers = initializerReferencedIdentifiers(source);
63040
- return [...names].some((name) => identifiers.has(name));
63099
+ for (const name of names) {
63100
+ if (identifiers.has(name)) return true;
63101
+ }
63102
+ return false;
63041
63103
  }
63042
63104
  function compileNSPropertyBodies(args) {
63043
63105
  if (args.member.kind !== 10 /* NSProperty */) return;
@@ -63639,7 +63701,7 @@ function declaredConstructorsOfClass(constructors, schemaClass2) {
63639
63701
  });
63640
63702
  }
63641
63703
  function argumentNameSetKey2(names) {
63642
- return [...names].map((name) => name.toLowerCase()).sort().join(", ");
63704
+ return names.map((name) => name.toLowerCase()).sort().join(", ");
63643
63705
  }
63644
63706
  function describeConstructorOverloads(constructors) {
63645
63707
  return constructors.map(
@@ -63739,7 +63801,7 @@ function resolveMemberDeclaredTypeInfoInternal(member, members, seen) {
63739
63801
  return {
63740
63802
  type: resolved.kind,
63741
63803
  required: resolved.required,
63742
- entryTypeInfo: { ...entryTypeInfo, required: true },
63804
+ entryTypeInfo,
63743
63805
  ...isMemberDictionaryBase(resolved) && resolved.keyEnumId ? { keyEnumId: resolved.keyEnumId } : {}
63744
63806
  };
63745
63807
  }
@@ -92000,7 +92062,12 @@ function materializeAuthoredListItems(args) {
92000
92062
  args.member.entryMemberId
92001
92063
  );
92002
92064
  const unordered = listKindOf(args.member) === "unordered";
92003
- const ids = unordered ? [...args.authoredRows.values()].filter((row) => row.containerId === args.row.id).map((row) => row.id) : args.row.value;
92065
+ const ids = unordered ? [] : args.row.value;
92066
+ if (unordered) {
92067
+ for (const row of args.authoredRows.values()) {
92068
+ if (row.containerId === args.row.id) ids.push(row.id);
92069
+ }
92070
+ }
92004
92071
  const materializedIds = [];
92005
92072
  for (const childId of ids) {
92006
92073
  if (typeof childId !== "string") {
@@ -92259,6 +92326,12 @@ function initBackedValueRow(value) {
92259
92326
  if (!isMemberValue(value)) return null;
92260
92327
  return isInitValueContent(value) ? value : null;
92261
92328
  }
92329
+ function valueIdsFromRows(explicitRows, sweepRows) {
92330
+ const ids = /* @__PURE__ */ new Set();
92331
+ for (const row of explicitRows) ids.add(row.id);
92332
+ for (const row of sweepRows) ids.add(row.id);
92333
+ return ids;
92334
+ }
92262
92335
  function prepareServerOwnedValueInitializerBodies(args) {
92263
92336
  const explicitRows = /* @__PURE__ */ new Map();
92264
92337
  for (let index = 0; index < args.prepared.length; index += 1) {
@@ -92280,10 +92353,7 @@ function prepareServerOwnedValueInitializerBodies(args) {
92280
92353
  args.postDocument,
92281
92354
  args.prepared
92282
92355
  );
92283
- const targetIds = /* @__PURE__ */ new Set([
92284
- ...[...explicitRows.values()].map((row) => row.id),
92285
- ...sweepRows.map((row) => row.id)
92286
- ]);
92356
+ const targetIds = valueIdsFromRows(explicitRows.values(), sweepRows);
92287
92357
  const valuesById = new Map(
92288
92358
  committedDocument.values.map((value) => [value.id, value])
92289
92359
  );
@@ -92410,10 +92480,7 @@ function prepareServerOwnedDelegateValueBodies(args) {
92410
92480
  args.postDocument,
92411
92481
  args.prepared
92412
92482
  );
92413
- const targetIds = /* @__PURE__ */ new Set([
92414
- ...[...explicitRows.values()].map((row) => row.id),
92415
- ...sweepRows.map((row) => row.id)
92416
- ]);
92483
+ const targetIds = valueIdsFromRows(explicitRows.values(), sweepRows);
92417
92484
  const rootOwnerByValueId = /* @__PURE__ */ new Map();
92418
92485
  const delegateScope = withVariantOwnershipRoots(
92419
92486
  committedDocument,
@@ -92964,6 +93031,20 @@ function applyProjectVersionWriteChanges(document, changes) {
92964
93031
  changes,
92965
93032
  "project-file"
92966
93033
  ),
93034
+ // Import-setting templates are part of the same file graph. A new file
93035
+ // may select a new template in one source transaction, and default-value
93036
+ // materialization validates that relationship immediately against this
93037
+ // post-write document.
93038
+ textureTemplates: applyArrayChanges(
93039
+ document.textureTemplates ?? [],
93040
+ changes,
93041
+ "unity-texture-template"
93042
+ ),
93043
+ audioClipTemplates: applyArrayChanges(
93044
+ document.audioClipTemplates ?? [],
93045
+ changes,
93046
+ "unity-audio-clip-template"
93047
+ ),
92967
93048
  internalRecordRelations: applyArrayChanges(
92968
93049
  document.internalRecordRelations ?? [],
92969
93050
  changes,
@@ -94884,7 +94965,7 @@ function listVirtualProjectSourceFilesV4(files) {
94884
94965
  const kind = neoProjectSourceKind(file.path);
94885
94966
  return kind !== null && isNeoProjectProductionSourceKind(kind) && !neoProjectPathHasIgnoredDirectory(file.path);
94886
94967
  });
94887
- const sorted = [...selected].sort(
94968
+ const sorted = selected.sort(
94888
94969
  (left, right) => compareWorkspacePaths(left.path, right.path)
94889
94970
  );
94890
94971
  for (let index = 1; index < sorted.length; index += 1) {
@@ -95525,14 +95606,24 @@ function computeWorkspaceStatus(workspace, options) {
95525
95606
  (binary) => binary.action !== "unchanged" && binary.action !== "converged"
95526
95607
  );
95527
95608
  reportPhase("binary-inspection");
95528
- const invalidatedFileIds = /* @__PURE__ */ new Set([
95529
- ...binaryFiles.filter(
95530
- (binary) => binary.action === "create" || binary.action === "upload"
95531
- ).map((binary) => binary.fileId),
95532
- ...options.trustedPendingProjectFiles?.keys() ?? []
95533
- ]);
95609
+ const invalidatedFileIds = /* @__PURE__ */ new Set();
95610
+ for (const binary of binaryFiles) {
95611
+ if (binary.action === "create" || binary.action === "upload") {
95612
+ invalidatedFileIds.add(binary.fileId);
95613
+ }
95614
+ }
95615
+ for (const fileId of options.trustedPendingProjectFiles?.keys() ?? []) {
95616
+ invalidatedFileIds.add(fileId);
95617
+ }
95618
+ if (options.skipProjectBinaryInspection) {
95619
+ for (const record3 of reconstructed3.values()) {
95620
+ if (record3.recordKind === "project-file" && record3.fullData.status !== "uploaded") {
95621
+ invalidatedFileIds.add(record3.recordId);
95622
+ }
95623
+ }
95624
+ }
95534
95625
  for (const message of validateFinalizedFileAssignmentsV4(
95535
- [...reconstructed3.values()].map((record3) => ({
95626
+ Array.from(reconstructed3.values(), (record3) => ({
95536
95627
  recordKind: record3.recordKind,
95537
95628
  data: record3.fullData
95538
95629
  })),
@@ -95585,10 +95676,13 @@ function computeWorkspaceStatus(workspace, options) {
95585
95676
  intent: createNeoCliPushIntent(change),
95586
95677
  expectedBaseContentHash: change.kind === "create" ? null : change.casBaseHash ?? null
95587
95678
  })),
95588
- authoredValueSeeds: [...authoredValueSeeds].map(([memberId, seed]) => ({
95589
- memberId,
95590
- ...seed
95591
- }))
95679
+ authoredValueSeeds: Array.from(
95680
+ authoredValueSeeds,
95681
+ ([memberId, seed]) => ({
95682
+ memberId,
95683
+ ...seed
95684
+ })
95685
+ )
95592
95686
  });
95593
95687
  } catch (error) {
95594
95688
  parseErrors.push(
@@ -95911,12 +96005,23 @@ function prospectiveAnimationRecords(base, reconstructed3, changes, seeds) {
95911
96005
  const key = recordStateKey(change.recordKind, change.recordId);
95912
96006
  if (change.kind === "delete") prospective.delete(key);
95913
96007
  }
95914
- const projectRecord = [...prospective.values()].find(
95915
- (record3) => record3.recordKind === "project"
95916
- ) ?? [...reconstructed3.values()].filter((record3) => record3.recordKind === "project").map((record3) => ({
95917
- recordKind: record3.recordKind,
95918
- data: record3.fullData
95919
- }))[0];
96008
+ let projectRecord;
96009
+ for (const record3 of prospective.values()) {
96010
+ if (record3.recordKind === "project") {
96011
+ projectRecord = record3;
96012
+ break;
96013
+ }
96014
+ }
96015
+ if (projectRecord === void 0) {
96016
+ for (const record3 of reconstructed3.values()) {
96017
+ if (record3.recordKind !== "project") continue;
96018
+ projectRecord = {
96019
+ recordKind: record3.recordKind,
96020
+ data: record3.fullData
96021
+ };
96022
+ break;
96023
+ }
96024
+ }
95920
96025
  const projectId = projectRecord?.data.id;
95921
96026
  const seedEnvelope = typeof projectId === "string" ? { projectId, createdAt: 0, updatedAt: 0 } : {};
95922
96027
  for (const [key, record3] of reconstructed3) {
@@ -97317,43 +97422,47 @@ function compilePulledMemberInitializerBodyV4(document, memberId, compilationPro
97317
97422
  }
97318
97423
  function readPulledProjectDocumentV4(records2) {
97319
97424
  const raw = structuredClone(
97320
- pulledProjectDocumentRaw(replayWorkspace(records2))
97321
- );
97322
- return readProjectDocument(
97323
- completeProspectiveMemberCreateEnvelopes(
97324
- completeProspectiveLocalizedTexts(raw)
97325
- ),
97326
- {
97327
- constructors: "authored-or-compiled",
97328
- identities: "prospective",
97329
- members: "authored-or-compiled"
97330
- }
97425
+ pulledProjectDocumentRaw(
97426
+ replayWorkspace(completeProspectiveRecordCreateEnvelopes(records2))
97427
+ )
97331
97428
  );
97429
+ return readProjectDocument(completeProspectiveLocalizedTexts(raw), {
97430
+ constructors: "authored-or-compiled",
97431
+ identities: "prospective",
97432
+ members: "authored-or-compiled"
97433
+ });
97332
97434
  }
97333
- function completeProspectiveMemberCreateEnvelopes(raw) {
97334
- const members = raw.members;
97335
- if (!Array.isArray(members)) return raw;
97336
- if (!members.some(isPendingMemberWithoutCreateEnvelope)) return raw;
97337
- const project = raw.project;
97338
- if (!isObjectRecord2(project) || typeof project.id !== "string") {
97435
+ function completeProspectiveRecordCreateEnvelopes(records2) {
97436
+ let project;
97437
+ for (const record3 of records2.values()) {
97438
+ if (!record3.deleted && record3.recordKind === "project" && isObjectRecord2(record3.data)) {
97439
+ project = record3;
97440
+ break;
97441
+ }
97442
+ }
97443
+ const projectId = isObjectRecord2(project?.data) ? project.data.id : null;
97444
+ if (typeof projectId !== "string") {
97339
97445
  throw new Error(
97340
- "Pending source-authored members need the server create envelope, but the project record has no id."
97446
+ "Prospective source-authored records need the server create envelope, but the project record has no id."
97341
97447
  );
97342
97448
  }
97343
- return {
97344
- ...raw,
97345
- members: members.map(
97346
- (member) => isPendingMemberWithoutCreateEnvelope(member) ? {
97347
- projectId: project.id,
97449
+ const completed = /* @__PURE__ */ new Map();
97450
+ for (const [key, record3] of records2) {
97451
+ if (record3.deleted || record3.recordKind === "project" || !isObjectRecord2(record3.data) || typeof record3.data.id !== "string" || typeof record3.data.projectId === "string" && typeof record3.data.createdAt === "number" && typeof record3.data.updatedAt === "number") {
97452
+ completed.set(key, record3);
97453
+ continue;
97454
+ }
97455
+ completed.set(key, {
97456
+ ...record3,
97457
+ data: {
97458
+ projectId,
97348
97459
  createdAt: 0,
97349
97460
  updatedAt: 0,
97350
- ...member
97351
- } : member
97352
- )
97353
- };
97354
- }
97355
- function isPendingMemberWithoutCreateEnvelope(value) {
97356
- return isObjectRecord2(value) && typeof value.id === "string" && value.id.startsWith("__pending__:") && (typeof value.projectId !== "string" || typeof value.createdAt !== "number" || typeof value.updatedAt !== "number");
97461
+ ...record3.data
97462
+ }
97463
+ });
97464
+ }
97465
+ return completed;
97357
97466
  }
97358
97467
  function completeProspectiveLocalizedTexts(raw) {
97359
97468
  const localizedTexts = raw.localizedTexts;
@@ -99545,7 +99654,7 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99545
99654
  `Value ${path} in ${source.label} writes @id(${JSON.stringify(unattachedId)}) on part of a computed expression rather than on the row. Parenthesize the expression so the annotation names the whole row.`
99546
99655
  );
99547
99656
  }
99548
- if (annotated.id === null && isPendingId(valueId) && !context.pendingValueIdentitySites.has(valueId)) {
99657
+ if (annotated.id === null && isPendingId(valueId) && pendingMemberValueMemberId(valueId) === null && !context.pendingValueIdentitySites.has(valueId)) {
99549
99658
  context.pendingValueIdentitySites.set(valueId, {
99550
99659
  id: valueId,
99551
99660
  uri: source.source.uri,
@@ -100149,6 +100258,16 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
100149
100258
  }
100150
100259
  indexInitAuthoredRowIds(context, code, source.label);
100151
100260
  const storedConstructorArgs = isObjectRecord2(base.constructorArgs) ? base.constructorArgs : null;
100261
+ if (resolvedMember.kind !== "class" && isLiteralValueContent(base)) {
100262
+ addReconstructed(
100263
+ context,
100264
+ "value",
100265
+ expectedValueId,
100266
+ valueFileFields(base),
100267
+ source.source
100268
+ );
100269
+ return expectedValueId;
100270
+ }
100152
100271
  const materializedClass = resolvedMember.kind === "class" && isObjectRecord2(base.value);
100153
100272
  const effectiveClassId = resolvedMember.kind === "class" ? stringOrNull(base.classId) ?? resolvedMember.classId : null;
100154
100273
  const materializedPlainClass = materializedClass && effectiveClassId !== null && context.classes.get(effectiveClassId)?.requiredConstructorId === void 0;
@@ -109225,7 +109344,7 @@ function qualifiedMemberLabel(thisClass, member) {
109225
109344
  if (typeof thisClass.name !== "string") return `'${memberName}'`;
109226
109345
  return `'${thisClass.name}.${memberName}'`;
109227
109346
  }
109228
- function analyzeWorkspaceProjectManifestV4(workspace) {
109347
+ function analyzeWorkspaceProjectV4(workspace) {
109229
109348
  const status = computeWorkspaceStatus2(workspace, {
109230
109349
  skipProjectBinaryInspection: true
109231
109350
  });
@@ -109250,13 +109369,35 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
109250
109369
  data: record3.fullData
109251
109370
  });
109252
109371
  }
109253
- return documentsToProjectSchemaManifest(documents);
109372
+ const records2 = /* @__PURE__ */ new Map();
109373
+ for (const record3 of status.reconstructed.values()) {
109374
+ records2.set(`${record3.recordKind}:${record3.recordId}`, {
109375
+ recordKind: record3.recordKind,
109376
+ recordId: record3.recordId,
109377
+ contentHash: "local-script-check",
109378
+ deleted: false,
109379
+ data: record3.fullData
109380
+ });
109381
+ }
109382
+ return {
109383
+ manifest: documentsToProjectSchemaManifest(documents),
109384
+ document: readDocumentArrays(
109385
+ readPulledProjectDocumentV4(records2)
109386
+ )
109387
+ };
109254
109388
  }
109255
109389
  async function runScript(workspace, command, options, dependencies = {}) {
109256
109390
  let localCheckManifest = null;
109391
+ let localCheckDocument = null;
109257
109392
  const targetsLocalMember = (command === "check" || command === "compile") && options.memberRef !== null;
109258
109393
  if (command === "check" && options.all || targetsLocalMember) {
109259
- localCheckManifest = (dependencies.analyzeWorkspaceManifest ?? analyzeWorkspaceProjectManifestV4)(workspace);
109394
+ if (dependencies.analyzeWorkspaceManifest === void 0) {
109395
+ const localProject = analyzeWorkspaceProjectV4(workspace);
109396
+ localCheckManifest = localProject.manifest;
109397
+ localCheckDocument = localProject.document;
109398
+ } else {
109399
+ localCheckManifest = dependencies.analyzeWorkspaceManifest(workspace);
109400
+ }
109260
109401
  if (targetsLocalMember) {
109261
109402
  const localTarget = resolveLocalScriptMember(
109262
109403
  localCheckManifest,
@@ -109276,6 +109417,10 @@ async function runScript(workspace, command, options, dependencies = {}) {
109276
109417
  return;
109277
109418
  }
109278
109419
  }
109420
+ if (command === "check" && options.all && localCheckManifest !== null && localCheckDocument !== null) {
109421
+ runCheckAll(localCheckDocument, localCheckManifest, options);
109422
+ return;
109423
+ }
109279
109424
  const client = NeoApiClient.forBaseUrl(workspace.config.apiBaseUrl);
109280
109425
  const { raw } = await fetchProjectDocument(workspace);
109281
109426
  const document = readDocumentArrays(raw);
@@ -110219,6 +110364,7 @@ var init_script = __esm({
110219
110364
  init_workspace_status();
110220
110365
  init_source_diagnostics();
110221
110366
  init_project_documents();
110367
+ init_initializer_replay();
110222
110368
  init_push_body_diagnostics();
110223
110369
  RETURN_SHORTHANDS = {
110224
110370
  // MemberKind numerics: Bool=1, Int=2, String=3, Float=4.
@@ -112217,6 +112363,13 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
112217
112363
  );
112218
112364
  let preparedChanges = null;
112219
112365
  if (options.fullValidation) {
112366
+ onPhase("Verifying the assigned-id source rewrite\u2026");
112367
+ materializeAssignedSchemaIdsInAuthoredSource(
112368
+ workspace,
112369
+ pendingAssignment.assigned,
112370
+ status.pendingValueIdentitySites,
112371
+ true
112372
+ );
112220
112373
  onPhase("Verifying the complete source round trip\u2026");
112221
112374
  verifyProjectSourceCommitAgainstStateV4({
112222
112375
  projectId: workspace.config.projectId,
@@ -113046,17 +113199,7 @@ function rewriteFilesFromState(workspace, records2 = new Map(
113046
113199
  return { uri: file.path, kind, text: file.content };
113047
113200
  })
113048
113201
  );
113049
- const finalErrors = finalAnalysis.diagnostics.filter(
113050
- (diagnostic) => diagnostic.severity === "error" && !isPullRecoveryDiagnosticCode(diagnostic.code)
113051
- );
113052
- if (finalErrors.length > 0) {
113053
- throw new Error(
113054
- `Assigned-id source rewrite produced invalid source:
113055
- ${finalErrors.map(
113056
- (diagnostic) => ` ${diagnostic.uri}:${diagnostic.range.start.line + 1}:${diagnostic.range.start.character + 1} ${diagnostic.message}`
113057
- ).join("\n")}`
113058
- );
113059
- }
113202
+ assertAssignedIdSourceRewriteValid(finalAnalysis);
113060
113203
  writeProjectSourceAnalysisCacheV4(workspace.root, finalAnalysis);
113061
113204
  const emittedPaths = new Set(files.map((file) => file.path));
113062
113205
  for (const recordState of Object.values(workspace.state.records)) {
@@ -113082,7 +113225,20 @@ ${finalErrors.map(
113082
113225
  workspace.state.records[key] = nextState;
113083
113226
  }
113084
113227
  }
113085
- function materializeAssignedSchemaIdsInAuthoredSource(workspace, replacements, pendingValueIdentitySites = /* @__PURE__ */ new Map()) {
113228
+ function assertAssignedIdSourceRewriteValid(analysis) {
113229
+ const finalErrors = analysis.diagnostics.filter(
113230
+ (diagnostic) => diagnostic.severity === "error" && !isPullRecoveryDiagnosticCode(diagnostic.code)
113231
+ );
113232
+ if (finalErrors.length > 0) {
113233
+ throw new Error(
113234
+ `Assigned-id source rewrite produced invalid source:
113235
+ ${finalErrors.map(
113236
+ (diagnostic) => ` ${diagnostic.uri}:${diagnostic.range.start.line + 1}:${diagnostic.range.start.character + 1} ${diagnostic.message}`
113237
+ ).join("\n")}`
113238
+ );
113239
+ }
113240
+ }
113241
+ function materializeAssignedSchemaIdsInAuthoredSource(workspace, replacements, pendingValueIdentitySites = /* @__PURE__ */ new Map(), validateResult = false) {
113086
113242
  const pendingIdsByUri = /* @__PURE__ */ new Map();
113087
113243
  for (const pendingId2 of replacements.keys()) {
113088
113244
  if (!isPendingId(pendingId2)) continue;
@@ -113258,6 +113414,16 @@ function materializeAssignedSchemaIdsInAuthoredSource(workspace, replacements, p
113258
113414
  }
113259
113415
  preserved.set(uri, source);
113260
113416
  }
113417
+ if (validateResult && preserved.size > 0) {
113418
+ assertAssignedIdSourceRewriteValid(
113419
+ compileNeoProjectSources(
113420
+ inputs.map((input) => ({
113421
+ ...input,
113422
+ text: preserved.get(input.uri) ?? input.text
113423
+ }))
113424
+ )
113425
+ );
113426
+ }
113261
113427
  return preserved;
113262
113428
  }
113263
113429
  function sourceOffsetInsideInitializer(source, oneBasedLine, oneBasedColumn) {
@@ -113874,7 +114040,7 @@ var init_registry2 = __esm({
113874
114040
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
113875
114041
  formatVersion: 3,
113876
114042
  contractVersion: "3.14",
113877
- cliVersion: "0.36.2",
114043
+ cliVersion: "0.36.4",
113878
114044
  projectFileUploadBatchSize: 32,
113879
114045
  documentRecords: {
113880
114046
  member: {
@@ -120476,7 +120642,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
120476
120642
  async function main() {
120477
120643
  const args = parseArgs(process.argv.slice(2));
120478
120644
  if (args.command === "--version") {
120479
- console.log("0.36.2");
120645
+ console.log("0.36.4");
120480
120646
  return;
120481
120647
  }
120482
120648
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.36.2",
3
+ "version": "0.36.4",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.36.2 -->
12
+ <!-- reviewed-through-cli: 0.36.4 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -83,7 +83,7 @@ wrappers.
83
83
  The marker near the top of `SKILL.md` must exactly match the package version:
84
84
 
85
85
  ```html
86
- <!-- reviewed-through-cli: 0.36.2 -->
86
+ <!-- reviewed-through-cli: 0.36.4 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -78,6 +78,11 @@ neo script eval --function Outpost.RefreshUnlock --this-value <id> --args '[3]'
78
78
 
79
79
  Prefer `--json` for automation.
80
80
 
81
+ `neo script check --all` reconstructs the prospective project entirely from
82
+ the local workspace. It checks local schema bodies and stored dialogue,
83
+ migration, and text-variable bodies against that same source transaction, so
84
+ new declarations do not depend on a prior push or a network fetch.
85
+
81
86
  Inside an inline Class body, unqualified names resolve against that Class;
82
87
  invoke delegate and action members directly with `Selector()` or `OnChanged()`.
83
88
  Spell a zero-argument action as bare `NeoAction`; type arguments name action
@@ -196,11 +201,13 @@ instead of hand-counting a literal or looping around `Add`:
196
201
  List<int> scores = List.Repeat(0, 10);
197
202
  ```
198
203
 
199
- The entry type is inferred from the value and joined with the assignment
200
- context, exactly like a list literal, so assigning `List.Repeat(0, 4)` to a
201
- `List<float>` widens the entries to `float`. Never spell type arguments on the
202
- qualifier: `List<int>.Repeat(0, 3)` is an error, and bare `List` is a
203
- qualifier, not a value.
204
+ The entry type is normally inferred from the value and joined with the
205
+ assignment context, exactly like a list literal, so assigning
206
+ `List.Repeat(0, 4)` to a `List<float>` widens the entries to `float`. When the
207
+ value cannot carry the type by itself, use a call-site type argument, for
208
+ example `List.Repeat<InventoryItemStack?>(null, slotCount)`. Never spell type
209
+ arguments on the qualifier: `List<int>.Repeat(0, 3)` is an error, and bare
210
+ `List` is a qualifier, not a value.
204
211
 
205
212
  `count` must be an `int` — a `float` count is a compile error, and a negative
206
213
  count fails at runtime with `List.Repeat count must be non-negative; got