@neocompose/cli 0.26.0 → 0.26.1

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.26.1] - 2026-08-10
4
+
5
+ ### Fixed
6
+
7
+ - Preserve concrete generic bindings while replaying nested constructors in class initializers, including generic entries inside inherited collection defaults. `neo status` and push preparation no longer reject a closed `NeoAnimationSegmentFrame<T>` as an open generic or report unchanged construction arguments as conflicting.
8
+ - Treat assignment to a single-value Lookup as a write to its owning selection row, while continuing to enforce the referenced collection's storage on writes through the selected value. Save-backed selections can now point at Immutable catalog entries without becoming immutable themselves.
9
+ - Rewrite reconstructed interface-member symbols through their interface owner's verified pending id instead of trying to assign the composite compiler symbol its own record id.
10
+ - Accept a constrained open generic member as a covariant implementation of a get-only interface property while continuing to reject that unsafe substitution for settable properties.
11
+
3
12
  ## [0.26.0] - 2026-08-09
4
13
 
5
14
  ### Added
package/dist/neo.mjs CHANGED
@@ -10150,7 +10150,9 @@ var init_strict_resolver = __esm({
10150
10150
  pointer: operand.pointer
10151
10151
  },
10152
10152
  type: isNullable(operand.type) ? { ...operand.type, nullable: false } : operand.type,
10153
- ...operand.writability ? { writability: operand.writability } : {}
10153
+ ...operand.writability ? { writability: operand.writability } : {},
10154
+ ...operand.entryWritability ? { entryWritability: operand.entryWritability } : {},
10155
+ ...operand.writeRoot ? { writeRoot: operand.writeRoot } : {}
10154
10156
  };
10155
10157
  }
10156
10158
  case "coalesce": {
@@ -10999,7 +11001,7 @@ var init_strict_resolver = __esm({
10999
11001
  };
11000
11002
  }
11001
11003
  const writability = this.memberWritability(member, receiver);
11002
- const entryWritability = member.lookup?.multiselect === true ? this.lookupEntryWritability(member, receiver) : void 0;
11004
+ const entryWritability = member.lookup ? this.lookupEntryWritability(member, receiver) : void 0;
11003
11005
  const lookupWire = member.lookup?.multiselect === true && memberType2.kind === "set" ? {
11004
11006
  type: 9 /* Lookup */,
11005
11007
  required: !isNullable(memberType2),
@@ -11094,12 +11096,9 @@ var init_strict_resolver = __esm({
11094
11096
  }
11095
11097
  if (!member.writable) return void 0;
11096
11098
  if (!member.lookup) {
11097
- return member.writability ? toWritability(member.writability) : receiver.writability ?? "save" /* Save */;
11099
+ return member.writability ? toWritability(member.writability) : receiver.entryWritability ?? receiver.writability ?? "save" /* Save */;
11098
11100
  }
11099
- if (member.lookup.multiselect) {
11100
- return member.writability ? toWritability(member.writability) : receiver.writability ?? "save" /* Save */;
11101
- }
11102
- return this.lookupEntryWritability(member, receiver);
11101
+ return member.writability ? toWritability(member.writability) : receiver.writability ?? "save" /* Save */;
11103
11102
  }
11104
11103
  lookupEntryWritability(member, receiver) {
11105
11104
  if (!member.lookup) return "readOnly" /* ReadOnly */;
@@ -42908,6 +42907,7 @@ function evaluateLiteralContainer(args) {
42908
42907
  }
42909
42908
  return {
42910
42909
  literal: literal2,
42910
+ ...evaluated.genericBindings === void 0 ? {} : { genericBindings: evaluated.genericBindings },
42911
42911
  ...evaluated.provisionalRootId === void 0 ? {} : { provisionalRootId: evaluated.provisionalRootId },
42912
42912
  ...evaluated.existingValueRow === void 0 ? {} : { existingValueRow: evaluated.existingValueRow }
42913
42913
  };
@@ -42930,6 +42930,9 @@ function buildDefaultMemberValue(args) {
42930
42930
  return evaluated.existingValueRow;
42931
42931
  }
42932
42932
  const value2 = buildNewValue(args.projectId, evaluated.literal);
42933
+ if (evaluated.genericBindings !== void 0) {
42934
+ value2.genericBindings = { ...evaluated.genericBindings };
42935
+ }
42933
42936
  if (evaluated.provisionalRootId !== void 0) {
42934
42937
  retargetDelegateReceiverValueIds(
42935
42938
  [value2, ...args.createdValues],
@@ -43316,6 +43319,9 @@ function cloneDefaultValueForMember(args) {
43316
43319
  return evaluated.existingValueRow;
43317
43320
  }
43318
43321
  const evaluatedRow = buildNewValue(args.projectId, evaluated.literal);
43322
+ if (evaluated.genericBindings !== void 0) {
43323
+ evaluatedRow.genericBindings = { ...evaluated.genericBindings };
43324
+ }
43319
43325
  if (evaluated.provisionalRootId !== void 0) {
43320
43326
  retargetDelegateReceiverValueIds(
43321
43327
  [evaluatedRow, ...args.createdValues],
@@ -62168,6 +62174,43 @@ function validateConstructorFieldSlot(args) {
62168
62174
  requiredWithoutDefault: member.required && member.defaultValue == null
62169
62175
  };
62170
62176
  }
62177
+ function constructionGenericSlotsForMember(rawMember, ctx, instanceEnv, visitedMemberIds = /* @__PURE__ */ new Set()) {
62178
+ const member = substituteMember(
62179
+ rawMember,
62180
+ instanceEnv,
62181
+ ctx.vm.members
62182
+ );
62183
+ const memberId = Reflect.get(member, "id");
62184
+ if (typeof memberId === "string" && visitedMemberIds.has(memberId)) {
62185
+ return [];
62186
+ }
62187
+ const nextVisited = new Set(visitedMemberIds);
62188
+ if (typeof memberId === "string") nextVisited.add(memberId);
62189
+ if (isMemberClassBase(member)) {
62190
+ const classArguments2 = member.classArguments ?? {};
62191
+ return Object.keys(classArguments2).length === 0 ? [] : [{ classId: member.classId, classArguments: classArguments2 }];
62192
+ }
62193
+ if (!isMemberListBase(member) && !isMemberDictionaryBase(member)) return [];
62194
+ const entryMember = evalMemberById(ctx.vm, member.entryMemberId);
62195
+ if (entryMember === null) return [];
62196
+ return constructionGenericSlotsForMember(
62197
+ resolveMember2(entryMember, ctx.vm.members),
62198
+ ctx,
62199
+ instanceEnv,
62200
+ nextVisited
62201
+ );
62202
+ }
62203
+ function withConstructionGenericSlots(member, ctx, instanceEnv, evaluate) {
62204
+ const slots = constructionGenericSlotsForMember(member, ctx, instanceEnv);
62205
+ if (slots.length === 0) return evaluate();
62206
+ const previousSlots = ctx.__constructionGenericSlots;
62207
+ ctx.__constructionGenericSlots = [...previousSlots ?? [], ...slots];
62208
+ try {
62209
+ return evaluate();
62210
+ } finally {
62211
+ ctx.__constructionGenericSlots = previousSlots;
62212
+ }
62213
+ }
62171
62214
  function evaluateConstructorFields(descriptor, scope, ctx) {
62172
62215
  const schemaClass2 = descriptor.schemaClass;
62173
62216
  const evaluatedValues = descriptor.fields.map((validated) => {
@@ -62176,7 +62219,13 @@ function evaluateConstructorFields(descriptor, scope, ctx) {
62176
62219
  `Constructor field '${validated.schemaKey}' on '${schemaClass2.name}' has no call-site expression to evaluate.`
62177
62220
  );
62178
62221
  }
62179
- return evalPointer(validated.valuePointer, scope, ctx);
62222
+ const valuePointer = validated.valuePointer;
62223
+ return withConstructionGenericSlots(
62224
+ validated.member,
62225
+ ctx,
62226
+ descriptor.instanceEnv,
62227
+ () => evalPointer(valuePointer, scope, ctx)
62228
+ );
62180
62229
  });
62181
62230
  return descriptor.fields.map((validated, index) => {
62182
62231
  let value = evaluatedValues[index];
@@ -62214,6 +62263,14 @@ function syntheticConstructorMember(schemaClass2, classArguments2) {
62214
62263
  accessModifierKind: "public"
62215
62264
  };
62216
62265
  }
62266
+ function stampConstructedRootGenericBindings(root, descriptor) {
62267
+ const stamp = {};
62268
+ for (const parameter4 of descriptor.schemaClass.genericParams ?? []) {
62269
+ const binding = descriptor.instanceEnv.get(parameter4.id);
62270
+ if (binding?.kind === "member") stamp[parameter4.id] = binding.memberId;
62271
+ }
62272
+ if (Object.keys(stamp).length > 0) root.genericBindings = stamp;
62273
+ }
62217
62274
  function applyConstructorFields(args) {
62218
62275
  const {
62219
62276
  root,
@@ -62551,7 +62608,8 @@ function constructClassValueWithinFrame(descriptor, scope, ctx) {
62551
62608
  valuesByClassId: /* @__PURE__ */ new Map(),
62552
62609
  missingScopeReason: "no-constructor"
62553
62610
  },
62554
- classId
62611
+ classId,
62612
+ descriptor.instanceEnv
62555
62613
  ),
62556
62614
  constructorRoot: {
62557
62615
  providedSchemaKeys: new Set(
@@ -62560,6 +62618,7 @@ function constructClassValueWithinFrame(descriptor, scope, ctx) {
62560
62618
  }
62561
62619
  });
62562
62620
  root.classId = classId;
62621
+ stampConstructedRootGenericBindings(root, descriptor);
62563
62622
  if (typeof root.value !== "object" || root.value === null || Array.isArray(root.value)) {
62564
62623
  throw new Error(
62565
62624
  `Class constructor for '${schemaClass2.name}' produced a non-record root.`
@@ -62918,7 +62977,7 @@ function evaluateBaseInitializerFields(args) {
62918
62977
  return { validated, value };
62919
62978
  });
62920
62979
  }
62921
- function constructionInitEvaluator(ctx, createdValues, argumentScopes, constructedClassId) {
62980
+ function constructionInitEvaluator(ctx, createdValues, argumentScopes, constructedClassId, instanceEnv) {
62922
62981
  const indexes = constructorInitializerIndexes(ctx);
62923
62982
  const inheritanceChain = resolveInheritanceChain(
62924
62983
  constructedClassId,
@@ -62940,36 +62999,19 @@ function constructionInitEvaluator(ctx, createdValues, argumentScopes, construct
62940
62999
  };
62941
63000
  return (member, init, sourceValueId) => {
62942
63001
  const evaluate = (argumentValues = []) => {
62943
- if (!isMemberClassBase(member) || Object.keys(member.classArguments ?? {}).length === 0) {
62944
- return evaluateInitializerInContext(
62945
- init,
62946
- member,
62947
- ctx,
62948
- createdValues,
62949
- argumentValues,
62950
- sourceValueId ?? null
62951
- );
62952
- }
62953
- const previousSlots = ctx.__constructionGenericSlots;
62954
- ctx.__constructionGenericSlots = [
62955
- ...previousSlots ?? [],
62956
- {
62957
- classId: member.classId,
62958
- classArguments: member.classArguments ?? {}
62959
- }
62960
- ];
62961
- try {
62962
- return evaluateInitializerInContext(
63002
+ return withConstructionGenericSlots(
63003
+ member,
63004
+ ctx,
63005
+ instanceEnv,
63006
+ () => evaluateInitializerInContext(
62963
63007
  init,
62964
63008
  member,
62965
63009
  ctx,
62966
63010
  createdValues,
62967
63011
  argumentValues,
62968
63012
  sourceValueId ?? null
62969
- );
62970
- } finally {
62971
- ctx.__constructionGenericSlots = previousSlots;
62972
- }
63013
+ )
63014
+ );
62973
63015
  };
62974
63016
  if (init.compiled === void 0) {
62975
63017
  return evaluate();
@@ -63172,6 +63214,7 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
63172
63214
  return {
63173
63215
  value: result.value,
63174
63216
  classId: rootRow.classId ?? null,
63217
+ ...rootRow.genericBindings === void 0 ? {} : { genericBindings: { ...rootRow.genericBindings } },
63175
63218
  provisionalRootId: rootRow.id,
63176
63219
  ...constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(constructorArgs) }
63177
63220
  };
@@ -63407,7 +63450,8 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
63407
63450
  ctx,
63408
63451
  createdValues,
63409
63452
  preparedArgumentScopes,
63410
- classId
63453
+ classId,
63454
+ descriptor.instanceEnv
63411
63455
  ),
63412
63456
  constructorRoot: {
63413
63457
  providedSchemaKeys: new Set(
@@ -63417,6 +63461,7 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
63417
63461
  }
63418
63462
  });
63419
63463
  root.classId = classId;
63464
+ stampConstructedRootGenericBindings(root, descriptor);
63420
63465
  } catch (error) {
63421
63466
  if (error instanceof NSGetterRuntimeError) throw error;
63422
63467
  throw new NSGetterRuntimeError(
@@ -64752,6 +64797,7 @@ function evaluateMemberInitializer(args) {
64752
64797
  return {
64753
64798
  value: result.value,
64754
64799
  classId: rootRow.classId ?? null,
64800
+ ...rootRow.genericBindings === void 0 ? {} : { genericBindings: { ...rootRow.genericBindings } },
64755
64801
  provisionalRootId: rootRow.id,
64756
64802
  ...constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(constructorArgs) }
64757
64803
  };
@@ -64811,6 +64857,7 @@ function materializeInitializerValue(args) {
64811
64857
  ...envelope,
64812
64858
  value: evaluated.value,
64813
64859
  ...evaluated.classId === null ? {} : { classId: evaluated.classId },
64860
+ ...evaluated.genericBindings === void 0 ? {} : { genericBindings: { ...evaluated.genericBindings } },
64814
64861
  ...evaluated.constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(evaluated.constructorArgs) }
64815
64862
  };
64816
64863
  if (evaluated.provisionalRootId !== void 0) {
@@ -74550,6 +74597,13 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
74550
74597
  const classesById = new Map(
74551
74598
  classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
74552
74599
  );
74600
+ const genericParamConstraintsById = new Map(
74601
+ classes.flatMap(
74602
+ (schemaClass2) => (schemaClass2.genericParams ?? []).map(
74603
+ (param) => [param.id, param.constraint]
74604
+ )
74605
+ )
74606
+ );
74553
74607
  const interfacesById = new Map(
74554
74608
  interfaces.map((neoInterface) => [neoInterface.id, neoInterface])
74555
74609
  );
@@ -75439,6 +75493,33 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
75439
75493
  }
75440
75494
  return { type: resolved.kind, required: required2 };
75441
75495
  };
75496
+ const constrainedGenericTypeInfo = (typeInfo) => {
75497
+ if (!isRecord7(typeInfo) || typeInfo.type !== 21 || typeof typeInfo.genericParamId !== "string") {
75498
+ return null;
75499
+ }
75500
+ const constraint = genericParamConstraintsById.get(typeInfo.genericParamId);
75501
+ if (!constraint) return null;
75502
+ return constraint.kind === "class" ? {
75503
+ type: 7,
75504
+ required: typeInfo.required === true,
75505
+ classId: constraint.classId
75506
+ } : {
75507
+ type: 8,
75508
+ required: typeInfo.required === true,
75509
+ enumId: constraint.enumId
75510
+ };
75511
+ };
75512
+ const constrainedGenericMemberTypeInfo = (member, schemaClass2) => {
75513
+ const resolved = substituteMemberForClass(member, schemaClass2);
75514
+ if (resolved.kind !== 21 || typeof resolved.genericParamId !== "string") {
75515
+ return null;
75516
+ }
75517
+ return constrainedGenericTypeInfo({
75518
+ type: 21,
75519
+ required: true,
75520
+ genericParamId: resolved.genericParamId
75521
+ });
75522
+ };
75442
75523
  const substituteTypeInfoForClass = (typeInfo, schemaClass2) => {
75443
75524
  if (!isRecord7(typeInfo)) return typeInfo;
75444
75525
  if (typeInfo.type === 21 && typeof typeInfo.genericParamId === "string") {
@@ -75509,7 +75590,8 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
75509
75590
  if (resolved.kind === 13 || resolved.kind === 23) {
75510
75591
  return "Schema member is a Function but the interface declares a property.";
75511
75592
  }
75512
- const implementationType = memberTypeInfo(member, schemaClass2);
75593
+ const storedType = memberTypeInfo(member, schemaClass2);
75594
+ const implementationType = declaration.settable === true ? storedType : storedType ? constrainedGenericTypeInfo(storedType) ?? storedType : constrainedGenericMemberTypeInfo(member, schemaClass2);
75513
75595
  if (!implementationType) return "Schema member type could not be resolved.";
75514
75596
  const matches = declaration.settable === true ? invariantTypeInfo(implementationType, declaration.typeInfo) : typeInfoAssignable(implementationType, declaration.typeInfo);
75515
75597
  if (!matches) return "Property type does not conform.";
@@ -98877,8 +98959,13 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, localInit
98877
98959
  return fresh;
98878
98960
  };
98879
98961
  const collect = (value) => {
98880
- if (typeof value === "string" && isPendingId(value)) {
98881
- assign(value);
98962
+ if (typeof value === "string") {
98963
+ const interfaceOwner = pendingInterfaceMemberSymbolOwner(value);
98964
+ if (interfaceOwner !== null) {
98965
+ assign(interfaceOwner);
98966
+ return;
98967
+ }
98968
+ if (isPendingId(value)) assign(value);
98882
98969
  return;
98883
98970
  }
98884
98971
  if (Array.isArray(value)) {
@@ -99032,6 +99119,18 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, localInit
99032
99119
  }
99033
99120
  };
99034
99121
  }
99122
+ function pendingInterfaceMemberSymbolOwner(value) {
99123
+ const marker = ":member:";
99124
+ const markerIndex = value.indexOf(marker);
99125
+ if (markerIndex < 0) return null;
99126
+ const owner = value.slice(0, markerIndex);
99127
+ const parts = owner.split(":");
99128
+ if (parts.length !== 6) return null;
99129
+ if (parts[0] !== "__pending__" || parts[1] !== "interface") return null;
99130
+ if (!/^\d+$/u.test(parts[3] ?? "")) return null;
99131
+ if (!/^\d+$/u.test(parts[4] ?? "")) return null;
99132
+ return owner;
99133
+ }
99035
99134
  function readAcceptedProjectVersionCommitResponse(value) {
99036
99135
  if (!isObjectRecord2(value) || value.kind !== "accepted") return null;
99037
99136
  if (typeof value.transactionId !== "string") {
@@ -101612,7 +101711,7 @@ var init_registry2 = __esm({
101612
101711
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
101613
101712
  formatVersion: 3,
101614
101713
  contractVersion: "3.9",
101615
- cliVersion: "0.26.0",
101714
+ cliVersion: "0.26.1",
101616
101715
  projectFileUploadBatchSize: 32,
101617
101716
  documentRecords: {
101618
101717
  member: {
@@ -107920,7 +108019,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
107920
108019
  async function main() {
107921
108020
  const args = parseArgs(process.argv.slice(2));
107922
108021
  if (args.command === "--version") {
107923
- console.log("0.26.0");
108022
+ console.log("0.26.1");
107924
108023
  return;
107925
108024
  }
107926
108025
  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.26.0",
3
+ "version": "0.26.1",
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.26.0 -->
12
+ <!-- reviewed-through-cli: 0.26.1 -->
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.26.0 -->
86
+ <!-- reviewed-through-cli: 0.26.1 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale