@neocompose/cli 0.89.12 → 0.89.14

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.
@@ -22186,6 +22186,8 @@ var InitializerReadSet = class {
22186
22186
  staticMemberIds = /* @__PURE__ */ new Set();
22187
22187
  worldQueries = new WorldGridQueryReadSet();
22188
22188
  hasValuePlacementRead = false;
22189
+ hasUnnamedValuePlacementRead = false;
22190
+ placementIds = /* @__PURE__ */ new Set();
22189
22191
  hasUnattributableValueRead = false;
22190
22192
  /**
22191
22193
  * The unattributable reads by scope, for a fork of the same document to
@@ -22209,8 +22211,10 @@ var InitializerReadSet = class {
22209
22211
  return;
22210
22212
  }
22211
22213
  };
22212
- recordValuePlacementRead = () => {
22214
+ recordValuePlacementRead = (valueId) => {
22213
22215
  this.hasValuePlacementRead = true;
22216
+ if (valueId === void 0) this.hasUnnamedValuePlacementRead = true;
22217
+ else this.placementIds.add(valueId);
22214
22218
  };
22215
22219
  };
22216
22220
 
@@ -22815,6 +22819,7 @@ var NeoScriptGetterSubscriptions = class _NeoScriptGetterSubscriptions {
22815
22819
  const reads = new InitializerReadSet();
22816
22820
  for (const key of [
22817
22821
  "valueIds",
22822
+ "placementIds",
22818
22823
  "localizedTextIds",
22819
22824
  "variantIds",
22820
22825
  "containerIds",
@@ -22826,6 +22831,7 @@ var NeoScriptGetterSubscriptions = class _NeoScriptGetterSubscriptions {
22826
22831
  for (const read of source.reads.worldQueries)
22827
22832
  reads.worldQueries.add(read);
22828
22833
  reads.hasValuePlacementRead = source.reads.hasValuePlacementRead;
22834
+ reads.hasUnnamedValuePlacementRead = source.reads.hasUnnamedValuePlacementRead;
22829
22835
  reads.hasUnattributableValueRead = source.reads.hasUnattributableValueRead;
22830
22836
  cloned.setReads(copy, reads);
22831
22837
  }
@@ -37246,6 +37252,13 @@ function applyConstructorFields(args) {
37246
37252
  let kept = 0;
37247
37253
  for (const row of createdValues) {
37248
37254
  if (row.id === keptId || row.containerId === keptId) {
37255
+ if (row.containerId === keptId) {
37256
+ if (ctx.__indexes !== void 0)
37257
+ unindexEvaluatorRow(ctx.__indexes, row);
37258
+ delete row.containerId;
37259
+ if (ctx.__indexes !== void 0)
37260
+ indexEvaluatorRow(ctx.__indexes, row);
37261
+ }
37249
37262
  createdById.delete(row.id);
37250
37263
  continue;
37251
37264
  }
@@ -40459,6 +40472,9 @@ function materializeConstructorArgumentValue(args) {
40459
40472
  for (const entry of rows) sourceEntries.push(entry.value);
40460
40473
  }
40461
40474
  const ids = [];
40475
+ const authoredEntries = args.ctx.__constructionEntryIds === void 0 ? void 0 : [];
40476
+ if (authoredEntries !== void 0)
40477
+ args.ctx.__constructionEntryIds?.set(row.id, authoredEntries);
40462
40478
  const references = recordedReferenceEntries(sourceEntries, args.ctx) ?? (args.collectionEntriesAreReferences === false ? 1 /* Values */ : collectionReferences(sourceEntries, args.ctx));
40463
40479
  for (const [index, rawEntry] of sourceEntries.entries()) {
40464
40480
  if (args.collectionOwnerId !== void 0 && args.collectionEntriesAreReferences !== false && isReferenceEntry(references, index) && typeof rawEntry === "string" && evalValueById(
@@ -40468,6 +40484,7 @@ function materializeConstructorArgumentValue(args) {
40468
40484
  args.ctx.__valueOverlay
40469
40485
  ) !== null) {
40470
40486
  ids.push(rawEntry);
40487
+ authoredEntries?.push(rawEntry);
40471
40488
  continue;
40472
40489
  }
40473
40490
  const entryValue = constructorCollectionEntryValue(
@@ -40489,6 +40506,7 @@ function materializeConstructorArgumentValue(args) {
40489
40506
  },
40490
40507
  destinationName: `${args.member.name}[${index}]`
40491
40508
  });
40509
+ authoredEntries?.push(child.id);
40492
40510
  if (listKindOf(args.member) === 1 /* Unordered */) {
40493
40511
  child.containerId = row.id;
40494
40512
  } else {
@@ -43306,7 +43324,16 @@ var MaterializedValueGraphContext = class _MaterializedValueGraphContext {
43306
43324
  ownershipFacts() {
43307
43325
  if (this.ownership !== void 0) return this.ownership;
43308
43326
  const targetValueIds = new Set(this.valuesById.keys());
43309
- const owners = resolveOwnerMembersForValues(this.document, targetValueIds);
43327
+ const owners = resolveOwnerMembersForValues(
43328
+ this.document,
43329
+ targetValueIds,
43330
+ [...this.contextualRootMembersByValueId ?? []].map(
43331
+ ([valueId, member]) => ({
43332
+ valueId,
43333
+ member: resolveMember(member, this.document.members)
43334
+ })
43335
+ )
43336
+ );
43310
43337
  this.ownership = {
43311
43338
  owners,
43312
43339
  independentlyOwnedValueIds: new Set(owners.keys())
@@ -46238,6 +46265,7 @@ function evaluateInitializerMaterialization(args) {
46238
46265
  const createdValues = [];
46239
46266
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
46240
46267
  const evaluated = args.evaluateInitializer({
46268
+ constructionEntryIds: args.constructionEntryIds,
46241
46269
  randomSource: args.randomSource,
46242
46270
  genericEnv: args.genericEnv,
46243
46271
  init: args.init,
@@ -46317,7 +46345,9 @@ function finalizeMaterializedRoot(args) {
46317
46345
  });
46318
46346
  }
46319
46347
  function materializeInitializerValue(args) {
46348
+ const constructionEntryIds = args.captureConstructionEntries ? /* @__PURE__ */ new Map() : void 0;
46320
46349
  const { evaluated, createdValues, storageKeyDeclarations } = evaluateInitializerMaterialization({
46350
+ constructionEntryIds,
46321
46351
  randomSource: args.randomSource,
46322
46352
  evaluateInitializer: args.evaluateInitializer,
46323
46353
  init: args.row.init,
@@ -46369,6 +46399,7 @@ function materializeInitializerValue(args) {
46369
46399
  return {
46370
46400
  root,
46371
46401
  createdValues,
46402
+ constructionEntryIds,
46372
46403
  snapshot: evaluated.snapshot,
46373
46404
  pinnedRootSchemaKeys: evaluated.pinnedRootSchemaKeys ?? /* @__PURE__ */ new Set(),
46374
46405
  pinnedSchemaKeysByValueId: evaluated.pinnedSchemaKeysByValueId ?? /* @__PURE__ */ new Map()
@@ -46838,7 +46869,7 @@ function buildVirtualInstanceMaterializedIndex(args) {
46838
46869
  return {
46839
46870
  rows,
46840
46871
  rowsById,
46841
- graph: new MaterializedValueGraphContext(
46872
+ graph: args.materializedGraph ?? new MaterializedValueGraphContext(
46842
46873
  { ...args.document, values: rows },
46843
46874
  rowsById
46844
46875
  ),
@@ -46940,7 +46971,9 @@ function materializationReadTracking(recorder) {
46940
46971
  for (const read of readTracking.worldQueries) {
46941
46972
  recorder.recordWorldQueryRead?.(read);
46942
46973
  }
46943
- if (readTracking.hasValuePlacementRead) {
46974
+ for (const id of readTracking.placementIds)
46975
+ recorder.recordValuePlacementRead(id);
46976
+ if (readTracking.hasUnnamedValuePlacementRead) {
46944
46977
  recorder.recordValuePlacementRead();
46945
46978
  }
46946
46979
  for (const containerId of readTracking.containerEntryReadIds) {
@@ -47314,7 +47347,9 @@ function resolveVirtualInstanceGraph(args) {
47314
47347
  if (parent !== void 0 && isMemberEntryCollectionBase(parent.member) && listKindOf(parent.member) === 1 /* Unordered */)
47315
47348
  effective.containerId = parentId;
47316
47349
  }
47317
- if (isClassSlotMember(indexed.member) && effective.value !== null) {
47350
+ if (args.opaquePaths?.has(pathKey)) {
47351
+ effective.value = materialized?.value ?? indexed.expandedRow.value;
47352
+ } else if (isClassSlotMember(indexed.member) && effective.value !== null) {
47318
47353
  const storedRecord = stringRecord(materialized?.value);
47319
47354
  const classId = rowClassId(indexed.member, effective);
47320
47355
  const constructedChildren = materialized === null ? /* @__PURE__ */ new Map() : settledAggregateChildren(materialized, classId, pathKey);
@@ -48648,6 +48683,7 @@ function indexExpansion(args) {
48648
48683
  discoveredNodes?.push(node);
48649
48684
  nodesByPath.set(pathKey, node);
48650
48685
  appendChildPath(parentPath, pathKey);
48686
+ if (args.opaquePaths?.has(pathKey)) return;
48651
48687
  if (isClassTypedMember(member)) {
48652
48688
  const record4 = stringRecord(row.value);
48653
48689
  const classId = row.classId ?? member.classId;
@@ -50176,6 +50212,10 @@ function createHeadlessVirtualInstanceResolver(args) {
50176
50212
  if (valueId !== void 0) {
50177
50213
  for (const active of activeReads) active.placementIds.add(valueId);
50178
50214
  ownReads()?.placementIds.add(valueId);
50215
+ } else {
50216
+ for (const active of activeReads) active.global = true;
50217
+ const own = ownReads();
50218
+ if (own !== void 0) own.global = true;
50179
50219
  }
50180
50220
  args.readRecorder?.recordValuePlacementRead(valueId);
50181
50221
  },
@@ -50413,7 +50453,9 @@ function createHeadlessVirtualInstanceResolver(args) {
50413
50453
  for (const id of reads.variantIds) external.recordVariantRead(id);
50414
50454
  for (const id of reads.staticMemberIds)
50415
50455
  external.recordStaticMemberRead(id);
50416
- if (reads.placementIds.size > 0) external.recordValuePlacementRead();
50456
+ for (const id of reads.placementIds)
50457
+ external.recordValuePlacementRead(id);
50458
+ if (reads.global) external.recordGlobalRead("virtual-instance-expansion");
50417
50459
  for (const reason of reads.corpusIndexReads)
50418
50460
  external.recordGlobalRead(reason);
50419
50461
  }
@@ -50608,7 +50650,8 @@ function createHeadlessVirtualInstanceResolver(args) {
50608
50650
  share.containerChanged
50609
50651
  );
50610
50652
  if (shared === null) return null;
50611
- recorder.recordValuePlacementRead();
50653
+ for (const id of shared.reads.placementIds)
50654
+ recorder.recordValuePlacementRead(id);
50612
50655
  for (const id of shared.reads.valueIds) recorder.recordValueRead(id);
50613
50656
  for (const id of shared.reads.containerIds)
50614
50657
  recorder.recordContainerMembershipRead(id);
@@ -50643,12 +50686,10 @@ function createHeadlessVirtualInstanceResolver(args) {
50643
50686
  const virtualInstanceRowsForValue = (receiverValueId) => {
50644
50687
  const adopted = adoptSharedExpansion(receiverValueId);
50645
50688
  if (adopted !== null) return adopted;
50646
- recorder.recordValuePlacementRead();
50647
50689
  recorder.recordValueRead(receiverValueId);
50648
50690
  const readPlacement = (valueId) => {
50649
- for (const active of activeReads) active.placementIds.add(valueId);
50650
- ownReads()?.placementIds.add(valueId);
50651
- return placements().get(valueId) ?? null;
50691
+ recorder.recordValuePlacementRead(valueId);
50692
+ return rawById.has(valueId) ? placements().get(valueId) ?? null : null;
50652
50693
  };
50653
50694
  let placement = readPlacement(receiverValueId);
50654
50695
  const roots = [];
@@ -50685,10 +50726,19 @@ function createHeadlessVirtualInstanceResolver(args) {
50685
50726
  observeRoot(known.instanceRootId);
50686
50727
  observeOwner(valueId, true);
50687
50728
  }
50688
- if (known?.instanceRootId === valueId) return known;
50729
+ const readKnown = (graph2) => {
50730
+ const result = resultByRootId.get(graph2.instanceRootId);
50731
+ if (result !== void 0) {
50732
+ settledRows(result);
50733
+ forwardReads(result.reads);
50734
+ }
50735
+ observeOwner(valueId, true);
50736
+ return graph2;
50737
+ };
50738
+ if (known?.instanceRootId === valueId) return readKnown(known);
50689
50739
  const stored = rawById.get(valueId);
50690
50740
  if (known !== void 0 && (stored === void 0 || !isStoredClassResolutionRoot(stored) || isMaterializedSpine(known.locationsById.get(valueId))))
50691
- return known;
50741
+ return readKnown(known);
50692
50742
  virtualInstanceRowsForValue(valueId);
50693
50743
  if (frames.length === 0) return graphByValueId.get(valueId) ?? null;
50694
50744
  const graph = observeSettled(valueId);
@@ -50788,7 +50838,7 @@ function createHeadlessVirtualInstanceResolver(args) {
50788
50838
  readRecorder: recorder,
50789
50839
  recordReads: (target, read) => {
50790
50840
  let reads = callerReads.get(target);
50791
- if (reads === void 0) {
50841
+ if (reads === void 0 || reads.valueIds !== target.valueIds || reads.containerIds !== target.containerIds || reads.localizedTextIds !== target.localizedTextIds || reads.variantIds !== target.variantIds || reads.staticMemberIds !== target.staticMemberIds) {
50792
50842
  reads = {
50793
50843
  valueIds: target.valueIds,
50794
50844
  containerIds: target.containerIds,
@@ -50812,6 +50862,9 @@ function createHeadlessVirtualInstanceResolver(args) {
50812
50862
  return read();
50813
50863
  } finally {
50814
50864
  activeReads.pop();
50865
+ for (const id of reads.placementIds)
50866
+ target.recordValuePlacementRead(id);
50867
+ reads.placementIds.clear();
50815
50868
  if (reads.global)
50816
50869
  target.recordUnattributableValueRead("virtual-instance-expansion");
50817
50870
  for (const reason of reads.corpusIndexReads)
@@ -51152,6 +51205,7 @@ function evaluateMemberInitializer(args) {
51152
51205
  );
51153
51206
  const compiled = compileMemberInitializer(args, databaseVM);
51154
51207
  const ctx = {
51208
+ __constructionEntryIds: args.constructionEntryIds,
51155
51209
  randomSource: args.randomSource,
51156
51210
  randomIdentity,
51157
51211
  ...args.sessionValues === void 0 ? {} : { __runtimeSessionValues: args.sessionValues },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.89.12",
3
+ "version": "0.89.14",
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.89.12 -->
12
+ <!-- reviewed-through-cli: 0.89.14 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -143,7 +143,7 @@ The marker near the top of `SKILL.md` must exactly match the package version,
143
143
  and this quoted copy is checked too:
144
144
 
145
145
  ```html
146
- <!-- reviewed-through-cli: 0.89.12 -->
146
+ <!-- reviewed-through-cli: 0.89.14 -->
147
147
  ```
148
148
 
149
149
  Keep this skill on current behavior. Upgrade steps, rollout prerequisites,
@@ -28,7 +28,8 @@ production source stops the run. It skips the extra source round trip that
28
28
  `neo push --dry-run` performs.
29
29
 
30
30
  - Specs live in colocated `*.spec.neo` files that never sync. Object
31
- initializers work there as in bodies.
31
+ initializers work there as in bodies. The editor resolves project roots in
32
+ loop sources, including nested `foreach` loops over `root.Assets` collections.
32
33
  - Files run in parallel on up to four CPU workers. Set `test.maxWorkers` in
33
34
  `neo.json`, pass `--maxWorkers <n>`, or `--runInBand`. Hook and test order
34
35
  within a file is preserved; fixtures and mocks stay isolated.
@@ -7,7 +7,9 @@ and generated C# under `<generatedTypesDirectory>/Generated/`.
7
7
  `Library/NeoCompose/export.json` is written last for Unity to ingest.
8
8
 
9
9
  - Only changed files are written. Codegen is skipped when schema inputs are
10
- unchanged, but content is still validated. Repeated exports, undos, and
10
+ unchanged, but content is still validated. Initializer checks share settled
11
+ dependencies and resolve independent children without expanding every sibling.
12
+ Repeated exports, undos, and
11
13
  reverts reuse cached results after verifying output bytes.
12
14
  - The Unity project comes from `unityConfigPath`. Without it, an interactive
13
15
  export offers to link the one config asset naming this project; scripts get
@@ -22,7 +24,9 @@ and generated C# under `<generatedTypesDirectory>/Generated/`.
22
24
  owner or one of its constructed base types.
23
25
 
24
26
  Status and export stay clean when animation defaults use initializers or
25
- constructor arguments select collection rows through Lookups.
27
+ constructor arguments select collection rows through Lookups. Changing an
28
+ override method signature keeps its member ID; animation validation recompiles
29
+ a retained body against the new inherited signature.
26
30
 
27
31
  ## Local exports
28
32
 
@@ -63,6 +63,13 @@ Quest HardAsStone = new Quest() { Name = "Hard as stone" };
63
63
  form above. Never put an ID in both places. A local keeps its concrete type
64
64
  when a base-typed member consumes it.
65
65
 
66
+ Before its first push, a named aggregate in an owning graph reserves its
67
+ identity by its terminal local declaration. Inserting or reordering other list
68
+ entries keeps that value and its descendants stable across local exports.
69
+ Aliases share the terminal declaration's identity. Scalar locals remain reusable
70
+ values, so each owning occurrence gets its own identity. Keep the assigned
71
+ `@id` when renaming or moving a declaration after push.
72
+
66
73
  ## Locals as constructor arguments
67
74
 
68
75
  In constructor arguments and executable operands, a class local names its one