@neocompose/cli 0.50.6 → 0.50.7

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,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.50.7] - 2026-09-14
4
+
5
+ - Preserve virtual default fields when cloning classes or importing constructor arguments. Fix `neo pull` failing with `Missing key 'Body' on object` for CharacterBody instances that clone a sparse cosmetic config. Index expanded graphs once to keep descendant reads linear.
6
+
3
7
  ## [0.50.6] - 2026-09-14
4
8
 
5
9
  - Match server preparation when adding world placements by loading their layer links and binding values without expanding unchanged placement siblings.
package/dist/neo.mjs CHANGED
@@ -76470,7 +76470,13 @@ function virtualExpandedRecordForReceiver(receiver, ctx) {
76470
76470
  if (rowId === null) return null;
76471
76471
  const rows = ctx.vm.databaseVM?.virtualInstanceRowsForValue(rowId);
76472
76472
  if (rows === void 0 || rows.length === 0) return null;
76473
- const expanded = rows.find((row) => row.id === rowId);
76473
+ ctx.__virtualRowsById ??= /* @__PURE__ */ new WeakMap();
76474
+ let rowsById = ctx.__virtualRowsById.get(rows);
76475
+ if (rowsById === void 0) {
76476
+ rowsById = new Map(rows.map((row) => [row.id, row]));
76477
+ ctx.__virtualRowsById.set(rows, rowsById);
76478
+ }
76479
+ const expanded = rowsById.get(rowId);
76474
76480
  if (expanded === void 0) return null;
76475
76481
  const record4 = expanded.value;
76476
76482
  if (typeof record4 !== "object" || record4 === null || Array.isArray(record4)) {
@@ -79022,7 +79028,7 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
79022
79028
  if (isMemberLookupBase(member)) {
79023
79029
  return encodeLookupInitializerResult(member, result.value, created, ctx);
79024
79030
  }
79025
- const rootRow = initializerRootRow(result.value, created);
79031
+ let rootRow = initializerRootRow(result.value, created);
79026
79032
  for (const row of created) {
79027
79033
  if (row === rootRow) continue;
79028
79034
  createdValues.push(row);
@@ -79038,11 +79044,36 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
79038
79044
  existingValueRow
79039
79045
  };
79040
79046
  }
79041
- return { value: result.value, classId: existingRuntimeClassId };
79047
+ if (existingValueRow !== null && existingRuntimeClassId !== null && isMemberClassBase(member)) {
79048
+ const storage = constructorArgumentStorage(existingValueRow.id, ctx);
79049
+ if (storage !== 3 /* Session */) {
79050
+ const checkpoint = sessionCreationCheckpoint(ctx);
79051
+ const value = cloneClassValueGraph(
79052
+ result.value,
79053
+ existingRuntimeClassId,
79054
+ ctx
79055
+ );
79056
+ const importedRows = createdSessionValuesSince(ctx, checkpoint);
79057
+ const imported = initializerRootRow(value, importedRows);
79058
+ if (imported === null) {
79059
+ throw new NSGetterRuntimeError(
79060
+ `Initializer '${member.name}' imported a Class without a backing row.`
79061
+ );
79062
+ }
79063
+ rootRow = imported;
79064
+ result = { ...result, value };
79065
+ for (const row of importedRows) {
79066
+ if (row !== rootRow) createdValues.push(row);
79067
+ }
79068
+ }
79069
+ }
79070
+ if (rootRow === null) {
79071
+ return { value: result.value, classId: existingRuntimeClassId };
79072
+ }
79042
79073
  }
79043
79074
  deleteRuntimeSessionValue(ctx, rootRow.id);
79044
79075
  ctx.__executionState?.constructorGroups.delete(rootRow.id);
79045
- const constructorArgs = typeof result.value === "object" && result.value !== null ? ctx.__constructedArgumentsByValue.get(result.value) : void 0;
79076
+ const constructorArgs = typeof result.value === "object" && result.value !== null ? ctx.__constructedArgumentsByValue.get(result.value) ?? rootRow.constructorArgs ?? void 0 : void 0;
79046
79077
  const provenance = pickInstanceProvenance({
79047
79078
  constructorArgs,
79048
79079
  instanceConstructorId: rootRow.instanceConstructorId,
@@ -80420,7 +80451,11 @@ function cloneConstructorArgumentGraph(args) {
80420
80451
  );
80421
80452
  const record4 = {};
80422
80453
  clone.value = record4;
80423
- for (const [schemaKey, childId] of Object.entries(source.value)) {
80454
+ const sourceRecord = {
80455
+ ...virtualExpandedRecordForReceiver(source.value, args.ctx),
80456
+ ...source.value
80457
+ };
80458
+ for (const [schemaKey, childId] of Object.entries(sourceRecord)) {
80424
80459
  if (typeof childId !== "string") {
80425
80460
  throw new NSGetterRuntimeError(
80426
80461
  `Constructor import found a non-id Class field '${schemaKey}' on value '${source.id}'.`
@@ -80979,10 +81014,12 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
80979
81014
  registerRuntimeSessionValue(ctx, clone);
80980
81015
  clonedBySourceId.set(sourceRow.id, clone);
80981
81016
  if (typeof sourceRow.value === "object" && sourceRow.value !== null && !Array.isArray(sourceRow.value)) {
80982
- const sourceRecord = sourceRow.value;
80983
- const clonedRecord = { ...sourceRecord };
81017
+ const clonedRecord = {
81018
+ ...virtualExpandedRecordForReceiver(sourceRow.value, ctx),
81019
+ ...sourceRow.value
81020
+ };
80984
81021
  clone.value = clonedRecord;
80985
- for (const [key, childId] of Object.entries(sourceRecord)) {
81022
+ for (const [key, childId] of Object.entries(clonedRecord)) {
80986
81023
  if (typeof childId !== "string") continue;
80987
81024
  const childMember = sourceTypeInfo?.type === 5 /* Dictionary */ ? null : ownedObjectChildMember(sourceRow, sourceMember, key, ctx);
80988
81025
  const childTypeInfo = sourceTypeInfo?.type === 5 /* Dictionary */ ? sourceTypeInfo.entryTypeInfo : void 0;
@@ -133242,7 +133279,7 @@ var init_registry2 = __esm({
133242
133279
  "schema-contract/registry.mjs"() {
133243
133280
  "use strict";
133244
133281
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
133245
- cliVersion: "0.50.6",
133282
+ cliVersion: "0.50.7",
133246
133283
  projectFileUploadBatchSize: 32,
133247
133284
  documentRecords: {
133248
133285
  member: {
@@ -140458,7 +140495,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
140458
140495
  async function main() {
140459
140496
  const args = parseArgs(process.argv.slice(2));
140460
140497
  if (args.command === "--version") {
140461
- console.log("0.50.6");
140498
+ console.log("0.50.7");
140462
140499
  return;
140463
140500
  }
140464
140501
  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.50.6",
3
+ "version": "0.50.7",
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.50.6 -->
12
+ <!-- reviewed-through-cli: 0.50.7 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -88,7 +88,7 @@ wrappers.
88
88
  The marker near the top of `SKILL.md` must exactly match the package version:
89
89
 
90
90
  ```html
91
- <!-- reviewed-through-cli: 0.50.6 -->
91
+ <!-- reviewed-through-cli: 0.50.7 -->
92
92
  ```
93
93
 
94
94
  The quoted version above is checked too, so this instruction cannot go stale