@neocompose/cli 0.50.2 → 0.50.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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.50.4] - 2026-09-14
4
+
5
+ - Resolve inherited lookup metadata when reading sparse member overrides in NeoScript. Single-select lookups return their referenced values for comparisons and member access; multi-select lookups remain collections.
6
+
7
+ ## [0.50.3] - 2026-09-14
8
+
9
+ - Preserve packed siblings when preparing push source identity for new children in an existing value graph. Pending seeds now fill missing rows without replacing reconstructed stored rows.
10
+ - Resolve omitted fields on stored classes without construction records from their shared declaration defaults. CLI validation, NeoScript reads, and editor value cells now agree without adding per-instance overrides or inventing constructor provenance.
11
+
3
12
  ## [0.50.2] - 2026-09-12
4
13
 
5
14
  - Export Unity C# as separate files named after their generated types. Keep stable identities in the manifest to preserve Unity GUIDs through renames. Preserve unchanged files and their Unity metadata, remove obsolete owned outputs, and share the integrity manifest with editor synchronization.
package/dist/neo.mjs CHANGED
@@ -53894,7 +53894,7 @@ function buildDefaultMemberValue(args) {
53894
53894
  `Cannot create a value of missing class "${effectiveClassId}".`
53895
53895
  );
53896
53896
  }
53897
- if (member.payload !== 1 /* Partial */ && typeof effectiveClass.requiredConstructorId === "string" && args.constructorRoot === void 0 && args.authoredRoot === void 0) {
53897
+ if (member.payload !== 1 /* Partial */ && typeof effectiveClass.requiredConstructorId === "string" && args.constructorRoot === void 0 && args.authoredRoot === void 0 && args.declarationRoot !== true) {
53898
53898
  throw new Error(
53899
53899
  `Class "${effectiveClass.name}" declares a required constructor; provide its constructor arguments.`
53900
53900
  );
@@ -53967,6 +53967,9 @@ function buildDefaultMemberValue(args) {
53967
53967
  anchorsParentClassPartition = true;
53968
53968
  }
53969
53969
  if (record4[schemaKey] !== void 0) continue;
53970
+ if (args.declarationRoot === true && !isLiteralValueContent(resolvedChildMember.defaultValue)) {
53971
+ continue;
53972
+ }
53970
53973
  if (args.authoredRoot?.suppliedSchemaKeys.has(schemaKey) === true) {
53971
53974
  continue;
53972
53975
  }
@@ -76010,12 +76013,13 @@ function resolveRuntimeSchemaMember(receiver, schemaKey, ctx) {
76010
76013
  if (!runtimeClassId) return null;
76011
76014
  const memberId = cachedMergedSchemaMemberId(runtimeClassId, schemaKey, ctx);
76012
76015
  if (memberId === null) return null;
76013
- const member = evalMemberById(ctx.vm, memberId);
76014
- if (member === null) return null;
76016
+ const rawMember = evalMemberById(ctx.vm, memberId);
76017
+ if (rawMember === null) return null;
76018
+ const member = cachedResolvedMember(rawMember, ctx);
76015
76019
  if (member.kind !== 21 /* Generic */) return member;
76016
76020
  const env = runtimeGenericEnvForValueRow(row, ctx, /* @__PURE__ */ new Set());
76017
76021
  try {
76018
- return substituteMember(member, env, ctx.vm.members);
76022
+ return substituteMember(member, env, ctx.vm.members, member);
76019
76023
  } catch (error) {
76020
76024
  throw new NSGetterRuntimeError(
76021
76025
  `Cannot resolve runtime member '${member.name}' for Class '${runtimeClassId}': ${error instanceof Error ? error.message : String(error)}`
@@ -81273,10 +81277,10 @@ function materializeMemberDefaultValue(args) {
81273
81277
  args.readTracking?.recordUnattributableValueRead(
81274
81278
  `declaration-owner-resolution:${args.envelope.id}`
81275
81279
  );
81276
- const { valuesById, rootOwners } = declarationInitializerContext(
81277
- args.document
81278
- );
81279
81280
  const declarationArguments = (member, init, sourceValueId) => {
81281
+ const { valuesById, rootOwners } = declarationInitializerContext(
81282
+ args.document
81283
+ );
81280
81284
  const ownerClass = typeof sourceValueId === "string" ? initializerOwnerContext(
81281
81285
  args.document,
81282
81286
  sourceValueId,
@@ -81308,6 +81312,7 @@ function materializeMemberDefaultValue(args) {
81308
81312
  member: args.member,
81309
81313
  createdValues,
81310
81314
  storageKeyDeclarations,
81315
+ declarationRoot: args.declarationRoot,
81311
81316
  ...args.genericEnv === void 0 ? {} : { genericEnv: args.genericEnv },
81312
81317
  // A declaration default may itself be init-backed one level down (P43 §2),
81313
81318
  // and those nested initializers must evaluate against the same document.
@@ -81750,13 +81755,12 @@ function resolveVirtualInstanceGraph(args) {
81750
81755
  const effective = {
81751
81756
  ...mergeExpandedAndMaterializedRow(indexed.expandedRow, materialized),
81752
81757
  id: effectiveId,
81753
- // Virtual rows inherit partition and timestamps from the root. Real rows
81754
- // retain their own envelope through the spread above.
81758
+ // Materialization has already resolved each child's storage partition.
81759
+ // Virtual rows inherit root timestamps; real rows retain their envelope.
81755
81760
  ...materialized === null ? {
81756
81761
  projectId: args.instanceRoot.projectId,
81757
81762
  createdAt: args.instanceRoot.createdAt,
81758
- updatedAt: args.instanceRoot.updatedAt,
81759
- ...args.instanceRoot.mapKey === void 0 ? {} : { mapKey: args.instanceRoot.mapKey }
81763
+ updatedAt: args.instanceRoot.updatedAt
81760
81764
  } : {}
81761
81765
  };
81762
81766
  if (isMemberClassBase(indexed.member) && effective.value !== null) {
@@ -82036,13 +82040,26 @@ function resolvedStoredInstanceRows(args) {
82036
82040
  const rows = new Map(document.values.map((row) => [row.id, row]));
82037
82041
  const materializedIndex = buildVirtualInstanceMaterializedIndex({ document });
82038
82042
  const queue = [{ root: args.instanceRoot, member: args.rootMember }];
82043
+ const stored = indexExpansion({
82044
+ document,
82045
+ instanceRoot: args.instanceRoot,
82046
+ rootMember: args.rootMember,
82047
+ expandedRoot: rows.get(args.instanceRoot.id) ?? args.instanceRoot,
82048
+ expandedRows: document.values
82049
+ });
82050
+ for (const node of stored.nodesByPath.values()) {
82051
+ if (node.expandedRow.id === args.instanceRoot.id) continue;
82052
+ if (!isMemberClassBase(node.member)) continue;
82053
+ if (!isStoredClassResolutionRoot(node.expandedRow)) continue;
82054
+ queue.push({ root: node.expandedRow, member: node.member });
82055
+ }
82039
82056
  const resolvedRootIds = /* @__PURE__ */ new Set();
82040
82057
  const resolvedFrameByValueId = /* @__PURE__ */ new Map();
82041
82058
  while (queue.length > 0) {
82042
82059
  const next = queue.shift();
82043
82060
  if (next === void 0 || resolvedRootIds.has(next.root.id)) continue;
82044
82061
  resolvedRootIds.add(next.root.id);
82045
- const expanded = expandStoredInstance({
82062
+ const expanded = expandStoredClassValue({
82046
82063
  evaluateInitializer: args.evaluateInitializer,
82047
82064
  document,
82048
82065
  instanceRoot: next.root,
@@ -82089,6 +82106,63 @@ function resolvedStoredInstanceRows(args) {
82089
82106
  }
82090
82107
  return rows;
82091
82108
  }
82109
+ function expandStoredClassValue(args) {
82110
+ if (isLiteralValueContent(args.instanceRoot) && isVirtualInstanceRootShape(args.instanceRoot)) {
82111
+ return expandStoredInstance(args);
82112
+ }
82113
+ const root = literalRow(args.instanceRoot);
82114
+ if (root.constructorArgs !== void 0) return expandStoredInstance(args);
82115
+ const member = resolveMember2(args.rootMember, args.document.members);
82116
+ if (!isMemberClassBase(member)) {
82117
+ throw new Error(
82118
+ `Stored default projection member "${memberIdOf(args.rootMember)}" is not Class-valued.`
82119
+ );
82120
+ }
82121
+ if (member.payload === 1 /* Partial */) {
82122
+ return { root, rows: [], pinnedRootSchemaKeys: /* @__PURE__ */ new Set() };
82123
+ }
82124
+ if (root.value === null) {
82125
+ return { root, rows: [], pinnedRootSchemaKeys: /* @__PURE__ */ new Set() };
82126
+ }
82127
+ const classId = root.classId ?? member.classId;
82128
+ args.readRecorder?.recordValueRead(root.id);
82129
+ args.readRecorder?.recordGlobalRead("declaration-default");
82130
+ const materialized = materializeMemberDefaultValue({
82131
+ evaluateInitializer: args.evaluateInitializer,
82132
+ document: args.document,
82133
+ member: closeClassArgumentsFromRowStamp(
82134
+ {
82135
+ ...member,
82136
+ classId,
82137
+ defaultValue: derivesContentFromMemberDefault({
82138
+ member,
82139
+ instanceRoot: root,
82140
+ effectiveClassId: classId
82141
+ }) ? member.defaultValue : void 0
82142
+ },
82143
+ root
82144
+ ),
82145
+ envelope: root,
82146
+ declarationRoot: true
82147
+ });
82148
+ return {
82149
+ root: { ...root, classId, value: materialized.root.value },
82150
+ rows: materialized.createdValues,
82151
+ pinnedRootSchemaKeys: /* @__PURE__ */ new Set()
82152
+ };
82153
+ }
82154
+ function isStoredClassResolutionRoot(value) {
82155
+ if (!isLiteralValueContent(value)) return false;
82156
+ if (isVirtualInstanceRootShape(value)) return true;
82157
+ return typeof value.classId === "string" && value.value !== null && typeof value.value === "object" && !Array.isArray(value.value);
82158
+ }
82159
+ function storedClassResolutionMember(member, row, members) {
82160
+ const resolved = resolveMember2(member, members);
82161
+ if (isMemberClassBase(resolved)) return resolved;
82162
+ if (resolved.kind !== 21 /* Generic */ || typeof row.classId !== "string")
82163
+ return null;
82164
+ return { ...resolved, kind: 7 /* Class */, classId: row.classId };
82165
+ }
82092
82166
  function planVirtualOverrideWrite(args) {
82093
82167
  const target = args.graph.locationsById.get(args.valueId);
82094
82168
  if (target === void 0) {
@@ -83569,8 +83643,12 @@ function createHeadlessVirtualInstanceResolver(args) {
83569
83643
  failedRootIds.add(rootId);
83570
83644
  return /* @__PURE__ */ new Map();
83571
83645
  }
83572
- const member = resolveMember2(declaredMember, document.members);
83573
- if (!isMemberClassBase(member) || !isLiteralValueContent(instanceRoot)) {
83646
+ const member = storedClassResolutionMember(
83647
+ declaredMember,
83648
+ instanceRoot,
83649
+ document.members
83650
+ );
83651
+ if (member === null || !isLiteralValueContent(instanceRoot)) {
83574
83652
  failedRootIds.add(rootId);
83575
83653
  return /* @__PURE__ */ new Map();
83576
83654
  }
@@ -83580,7 +83658,7 @@ function createHeadlessVirtualInstanceResolver(args) {
83580
83658
  document: resolverDocument,
83581
83659
  materializedRows: document.values
83582
83660
  });
83583
- const expanded = expandStoredInstance({
83661
+ const expanded = expandStoredClassValue({
83584
83662
  evaluateInitializer: args.evaluateInitializer,
83585
83663
  document: resolverDocument,
83586
83664
  instanceRoot,
@@ -83622,7 +83700,7 @@ function createHeadlessVirtualInstanceResolver(args) {
83622
83700
  while (placement !== null) {
83623
83701
  args.readRecorder?.recordValueRead(placement.valueId);
83624
83702
  const raw = rawById.get(placement.valueId);
83625
- if (raw !== void 0 && isLiteralValueContent(raw) && isVirtualInstanceRootShape(raw)) {
83703
+ if (raw !== void 0 && isLiteralValueContent(raw) && isStoredClassResolutionRoot(raw)) {
83626
83704
  return [...expandRoot(placement.valueId, placement.memberId).values()];
83627
83705
  }
83628
83706
  placement = placement.parentValueId === null ? null : placements().get(placement.parentValueId) ?? null;
@@ -84032,6 +84110,12 @@ var init_materialize_values = __esm({
84032
84110
  });
84033
84111
 
84034
84112
  // ../src/runtime/virtual-instance-values.ts
84113
+ function expandStoredClassValue2(args) {
84114
+ return expandStoredClassValue({
84115
+ ...args,
84116
+ evaluateInitializer: evaluateMemberInitializer
84117
+ });
84118
+ }
84035
84119
  function expandStoredInstance2(args) {
84036
84120
  return expandStoredInstance({
84037
84121
  ...args,
@@ -101776,6 +101860,7 @@ var init_project_version_static_value_writes = __esm({
101776
101860
  dialogueIds = /* @__PURE__ */ new Set();
101777
101861
  schemaIndex;
101778
101862
  virtualValueIds;
101863
+ declarationMaterializedIndex = null;
101779
101864
  stack = /* @__PURE__ */ new Set();
101780
101865
  createdCollectionStampByValueId = /* @__PURE__ */ new Map();
101781
101866
  /** Built once and reused by every nested construction-root proof. */
@@ -101902,11 +101987,51 @@ var init_project_version_static_value_writes = __esm({
101902
101987
  args.genericEnv,
101903
101988
  args.path
101904
101989
  );
101905
- this.validateSemanticNode({ ...args, member, value });
101990
+ const resolved = this.resolveDeclaredDefaults(
101991
+ member,
101992
+ value,
101993
+ args.genericEnv
101994
+ );
101995
+ this.validateSemanticNode({ ...args, member, value: resolved });
101906
101996
  } finally {
101907
101997
  this.stack.delete(value.id);
101908
101998
  }
101909
101999
  }
102000
+ resolveDeclaredDefaults(member, value, genericEnv) {
102001
+ const closed = substituteMember(member, genericEnv, this.document.members);
102002
+ if (!isMemberClassBase(closed)) return value;
102003
+ if (!isLiteralValueContent(value)) return value;
102004
+ if (value.value === null || typeof value.value !== "object" || Array.isArray(value.value))
102005
+ return value;
102006
+ if (value.instanceConstructorId !== void 0 || value.instanceVariantId != null)
102007
+ return value;
102008
+ if (this.virtualValueIds.has(value.id)) return value;
102009
+ const expanded = expandStoredClassValue2({
102010
+ document: this.merged().document,
102011
+ instanceRoot: value,
102012
+ rootMember: closed
102013
+ });
102014
+ const graph = resolveVirtualInstanceGraph({
102015
+ document: this.merged().document,
102016
+ instanceRoot: value,
102017
+ rootMember: closed,
102018
+ expandedRoot: expanded.root,
102019
+ expandedRows: expanded.rows,
102020
+ materializedIndex: this.declarationMaterializedIndex ??= buildVirtualInstanceMaterializedIndex({
102021
+ document: this.merged().document
102022
+ })
102023
+ });
102024
+ for (const [id2, row] of graph.rowsById) {
102025
+ if (this.valueById.has(id2)) continue;
102026
+ this.valueById.set(id2, row);
102027
+ }
102028
+ const resolved = graph.rowsById.get(value.id);
102029
+ if (resolved === void 0 || !isLiteralValueContent(resolved))
102030
+ return value;
102031
+ if (resolved.value === null || typeof resolved.value !== "object" || Array.isArray(resolved.value))
102032
+ return value;
102033
+ return { ...resolved, value: { ...resolved.value, ...value.value } };
102034
+ }
101910
102035
  /**
101911
102036
  * A static graph can contain nested construction roots under an ordinary
101912
102037
  * list or Class root. Replay each reachable root that carries complete
@@ -130834,20 +130959,22 @@ function createPendingProjectSourceIdentityV4(workspace, status, authoredValueSe
130834
130959
  });
130835
130960
  }
130836
130961
  if (seed.valueId === void 0) continue;
130837
- records2.set(`value:${seed.valueId}`, {
130838
- recordKind: "value",
130839
- recordId: seed.valueId,
130840
- contentHash: "",
130841
- deleted: false,
130842
- data: {
130843
- id: seed.valueId,
130844
- projectId: workspace.config.projectId,
130845
- ...encodeStoredValueNode(seed),
130846
- createdAt: now,
130847
- updatedAt: now
130848
- }
130849
- });
130962
+ if (!records2.has(`value:${seed.valueId}`))
130963
+ records2.set(`value:${seed.valueId}`, {
130964
+ recordKind: "value",
130965
+ recordId: seed.valueId,
130966
+ contentHash: "",
130967
+ deleted: false,
130968
+ data: {
130969
+ id: seed.valueId,
130970
+ projectId: workspace.config.projectId,
130971
+ ...encodeStoredValueNode(seed),
130972
+ createdAt: now,
130973
+ updatedAt: now
130974
+ }
130975
+ });
130850
130976
  for (const value of seed.values ?? []) {
130977
+ if (records2.has(`value:${value.id}`)) continue;
130851
130978
  records2.set(`value:${value.id}`, {
130852
130979
  recordKind: "value",
130853
130980
  recordId: value.id,
@@ -132352,7 +132479,7 @@ var init_registry2 = __esm({
132352
132479
  "schema-contract/registry.mjs"() {
132353
132480
  "use strict";
132354
132481
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
132355
- cliVersion: "0.50.2",
132482
+ cliVersion: "0.50.4",
132356
132483
  projectFileUploadBatchSize: 32,
132357
132484
  documentRecords: {
132358
132485
  member: {
@@ -139568,7 +139695,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
139568
139695
  async function main() {
139569
139696
  const args = parseArgs(process.argv.slice(2));
139570
139697
  if (args.command === "--version") {
139571
- console.log("0.50.2");
139698
+ console.log("0.50.4");
139572
139699
  return;
139573
139700
  }
139574
139701
  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.2",
3
+ "version": "0.50.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.50.2 -->
12
+ <!-- reviewed-through-cli: 0.50.4 -->
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.2 -->
91
+ <!-- reviewed-through-cli: 0.50.4 -->
92
92
  ```
93
93
 
94
94
  The quoted version above is checked too, so this instruction cannot go stale
@@ -136,6 +136,13 @@ member creates a sparse override with its deterministic projected ID; removing
136
136
  that member from an existing initializer resets the override and resumes source
137
137
  tracking. Require either transition to appear in `neo diff`.
138
138
 
139
+ A stored class with no construction record still inherits literal declaration
140
+ defaults for omitted fields. For example, `FoodInfo.Quality = .OneStar` supplies
141
+ the quality of an existing food row that stores only its price. Do not add an
142
+ instance override to repair that omission. Reads do not invent a historical
143
+ constructor, and required fields with no applicable default remain errors.
144
+ Explicit stored overrides and partial payloads keep their existing meaning.
145
+
139
146
  Generic arguments specify types, not default values. A required generic member
140
147
  must be supplied at construction unless its member declaration or an inherited
141
148
  member declaration supplies a default. Missing required members are compile