@neocompose/cli 0.89.11 → 0.89.13

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.
@@ -37246,6 +37246,13 @@ function applyConstructorFields(args) {
37246
37246
  let kept = 0;
37247
37247
  for (const row of createdValues) {
37248
37248
  if (row.id === keptId || row.containerId === keptId) {
37249
+ if (row.containerId === keptId) {
37250
+ if (ctx.__indexes !== void 0)
37251
+ unindexEvaluatorRow(ctx.__indexes, row);
37252
+ delete row.containerId;
37253
+ if (ctx.__indexes !== void 0)
37254
+ indexEvaluatorRow(ctx.__indexes, row);
37255
+ }
37249
37256
  createdById.delete(row.id);
37250
37257
  continue;
37251
37258
  }
@@ -40459,6 +40466,9 @@ function materializeConstructorArgumentValue(args) {
40459
40466
  for (const entry of rows) sourceEntries.push(entry.value);
40460
40467
  }
40461
40468
  const ids = [];
40469
+ const authoredEntries = args.ctx.__constructionEntryIds === void 0 ? void 0 : [];
40470
+ if (authoredEntries !== void 0)
40471
+ args.ctx.__constructionEntryIds?.set(row.id, authoredEntries);
40462
40472
  const references = recordedReferenceEntries(sourceEntries, args.ctx) ?? (args.collectionEntriesAreReferences === false ? 1 /* Values */ : collectionReferences(sourceEntries, args.ctx));
40463
40473
  for (const [index, rawEntry] of sourceEntries.entries()) {
40464
40474
  if (args.collectionOwnerId !== void 0 && args.collectionEntriesAreReferences !== false && isReferenceEntry(references, index) && typeof rawEntry === "string" && evalValueById(
@@ -40468,6 +40478,7 @@ function materializeConstructorArgumentValue(args) {
40468
40478
  args.ctx.__valueOverlay
40469
40479
  ) !== null) {
40470
40480
  ids.push(rawEntry);
40481
+ authoredEntries?.push(rawEntry);
40471
40482
  continue;
40472
40483
  }
40473
40484
  const entryValue = constructorCollectionEntryValue(
@@ -40489,6 +40500,7 @@ function materializeConstructorArgumentValue(args) {
40489
40500
  },
40490
40501
  destinationName: `${args.member.name}[${index}]`
40491
40502
  });
40503
+ authoredEntries?.push(child.id);
40492
40504
  if (listKindOf(args.member) === 1 /* Unordered */) {
40493
40505
  child.containerId = row.id;
40494
40506
  } else {
@@ -41035,11 +41047,13 @@ function cloneClassValueGraph(receiver, expected, ctx) {
41035
41047
  );
41036
41048
  clonedRecord[key] = clonedChild.id;
41037
41049
  }
41038
- } else if (Array.isArray(sourceRow.value) && (isMemberEntryCollectionBase(sourceMember) || sourceTypeInfo?.type === 6 /* List */ || sourceTypeInfo?.type === 28 /* Set */)) {
41050
+ } else if (Array.isArray(sourceRow.value) && (isMemberEntryCollectionBase(sourceMember) || isMemberTupleBase(sourceMember) || sourceTypeInfo?.type === 30 /* Tuple */ || sourceTypeInfo?.type === 6 /* List */ || sourceTypeInfo?.type === 28 /* Set */)) {
41039
41051
  const entryMember = isMemberEntryCollectionBase(sourceMember) ? evalMemberById(ctx.vm, sourceMember.entryMemberId) : null;
41040
41052
  const entryTypeInfo = sourceTypeInfo?.type === 6 /* List */ || sourceTypeInfo?.type === 28 /* Set */ ? sourceTypeInfo.entryTypeInfo : void 0;
41041
- if (entryMember !== null || entryTypeInfo !== void 0) {
41042
- clone.value = sourceRow.value.map((childId) => {
41053
+ const tuple = isMemberTupleBase(sourceMember) ? sourceMember : null;
41054
+ const tupleType = sourceTypeInfo?.type === 30 /* Tuple */ ? sourceTypeInfo : null;
41055
+ if (entryMember !== null || entryTypeInfo !== void 0 || tuple !== null || tupleType !== null) {
41056
+ clone.value = sourceRow.value.map((childId, index) => {
41043
41057
  if (typeof childId !== "string") return childId;
41044
41058
  const child = evalValueById(
41045
41059
  ctx,
@@ -41048,11 +41062,17 @@ function cloneClassValueGraph(receiver, expected, ctx) {
41048
41062
  ctx.__valueOverlay
41049
41063
  );
41050
41064
  if (child === null) return childId;
41065
+ const elementMember = tuple === null ? entryMember : evalMemberById(ctx.vm, tuple.elementMemberIds[index]);
41066
+ const elementType = tupleType === null ? entryTypeInfo : tupleType.elements[index]?.typeInfo;
41067
+ if (elementMember === null && elementType === void 0)
41068
+ throw new NSGetterRuntimeError(
41069
+ `Class.Clone tuple element ${index} has no type descriptor.`
41070
+ );
41051
41071
  return cloneRow2(
41052
41072
  child,
41053
- entryMember,
41073
+ elementMember,
41054
41074
  child.containerId === sourceRow.id ? id : void 0,
41055
- entryTypeInfo
41075
+ elementType
41056
41076
  ).id;
41057
41077
  });
41058
41078
  ctx.onUnattributableValueRead?.(containerEntriesRead(sourceRow.id));
@@ -43298,7 +43318,16 @@ var MaterializedValueGraphContext = class _MaterializedValueGraphContext {
43298
43318
  ownershipFacts() {
43299
43319
  if (this.ownership !== void 0) return this.ownership;
43300
43320
  const targetValueIds = new Set(this.valuesById.keys());
43301
- const owners = resolveOwnerMembersForValues(this.document, targetValueIds);
43321
+ const owners = resolveOwnerMembersForValues(
43322
+ this.document,
43323
+ targetValueIds,
43324
+ [...this.contextualRootMembersByValueId ?? []].map(
43325
+ ([valueId, member]) => ({
43326
+ valueId,
43327
+ member: resolveMember(member, this.document.members)
43328
+ })
43329
+ )
43330
+ );
43302
43331
  this.ownership = {
43303
43332
  owners,
43304
43333
  independentlyOwnedValueIds: new Set(owners.keys())
@@ -46230,6 +46259,7 @@ function evaluateInitializerMaterialization(args) {
46230
46259
  const createdValues = [];
46231
46260
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
46232
46261
  const evaluated = args.evaluateInitializer({
46262
+ constructionEntryIds: args.constructionEntryIds,
46233
46263
  randomSource: args.randomSource,
46234
46264
  genericEnv: args.genericEnv,
46235
46265
  init: args.init,
@@ -46309,7 +46339,9 @@ function finalizeMaterializedRoot(args) {
46309
46339
  });
46310
46340
  }
46311
46341
  function materializeInitializerValue(args) {
46342
+ const constructionEntryIds = args.captureConstructionEntries ? /* @__PURE__ */ new Map() : void 0;
46312
46343
  const { evaluated, createdValues, storageKeyDeclarations } = evaluateInitializerMaterialization({
46344
+ constructionEntryIds,
46313
46345
  randomSource: args.randomSource,
46314
46346
  evaluateInitializer: args.evaluateInitializer,
46315
46347
  init: args.row.init,
@@ -46361,6 +46393,7 @@ function materializeInitializerValue(args) {
46361
46393
  return {
46362
46394
  root,
46363
46395
  createdValues,
46396
+ constructionEntryIds,
46364
46397
  snapshot: evaluated.snapshot,
46365
46398
  pinnedRootSchemaKeys: evaluated.pinnedRootSchemaKeys ?? /* @__PURE__ */ new Set(),
46366
46399
  pinnedSchemaKeysByValueId: evaluated.pinnedSchemaKeysByValueId ?? /* @__PURE__ */ new Map()
@@ -46830,7 +46863,7 @@ function buildVirtualInstanceMaterializedIndex(args) {
46830
46863
  return {
46831
46864
  rows,
46832
46865
  rowsById,
46833
- graph: new MaterializedValueGraphContext(
46866
+ graph: args.materializedGraph ?? new MaterializedValueGraphContext(
46834
46867
  { ...args.document, values: rows },
46835
46868
  rowsById
46836
46869
  ),
@@ -47306,7 +47339,9 @@ function resolveVirtualInstanceGraph(args) {
47306
47339
  if (parent !== void 0 && isMemberEntryCollectionBase(parent.member) && listKindOf(parent.member) === 1 /* Unordered */)
47307
47340
  effective.containerId = parentId;
47308
47341
  }
47309
- if (isClassSlotMember(indexed.member) && effective.value !== null) {
47342
+ if (args.opaquePaths?.has(pathKey)) {
47343
+ effective.value = materialized?.value ?? indexed.expandedRow.value;
47344
+ } else if (isClassSlotMember(indexed.member) && effective.value !== null) {
47310
47345
  const storedRecord = stringRecord(materialized?.value);
47311
47346
  const classId = rowClassId(indexed.member, effective);
47312
47347
  const constructedChildren = materialized === null ? /* @__PURE__ */ new Map() : settledAggregateChildren(materialized, classId, pathKey);
@@ -48640,6 +48675,7 @@ function indexExpansion(args) {
48640
48675
  discoveredNodes?.push(node);
48641
48676
  nodesByPath.set(pathKey, node);
48642
48677
  appendChildPath(parentPath, pathKey);
48678
+ if (args.opaquePaths?.has(pathKey)) return;
48643
48679
  if (isClassTypedMember(member)) {
48644
48680
  const record4 = stringRecord(row.value);
48645
48681
  const classId = row.classId ?? member.classId;
@@ -51144,6 +51180,7 @@ function evaluateMemberInitializer(args) {
51144
51180
  );
51145
51181
  const compiled = compileMemberInitializer(args, databaseVM);
51146
51182
  const ctx = {
51183
+ __constructionEntryIds: args.constructionEntryIds,
51147
51184
  randomSource: args.randomSource,
51148
51185
  randomIdentity,
51149
51186
  ...args.sessionValues === void 0 ? {} : { __runtimeSessionValues: args.sessionValues },
@@ -59025,9 +59062,10 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
59025
59062
  if (outerEntry === null) return null;
59026
59063
  const existing = context.byOuterEntry.get(outerEntry);
59027
59064
  if (existing !== void 0) return existing;
59065
+ const capturedType = context.outerScope.lookupNarrowedType(name, outerEntry) ?? outerEntry.type;
59028
59066
  const parameter3 = variable(
59029
59067
  `__capture_${context.serial}_${context.captures.length}__`,
59030
- outerEntry.type,
59068
+ capturedType,
59031
59069
  void 0,
59032
59070
  this.project
59033
59071
  );
@@ -59035,7 +59073,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
59035
59073
  ...scopeVariable(
59036
59074
  name,
59037
59075
  parameter3,
59038
- outerEntry.type,
59076
+ capturedType,
59039
59077
  "local" /* Local */,
59040
59078
  "local" /* Local */,
59041
59079
  outerEntry.writeRoot,
@@ -66775,7 +66813,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
66775
66813
  return literal(symbol.type, null);
66776
66814
  }
66777
66815
  hasValueReceiver(name, scope) {
66778
- return scope.lookup(name) !== null || this.implicitMember(name) !== null;
66816
+ return scope.lookup(name) !== null || this.delegateCaptureContexts.some(
66817
+ (context) => context.outerScope.lookup(name) !== null
66818
+ ) || this.implicitMember(name) !== null;
66779
66819
  }
66780
66820
  implicitMember(name) {
66781
66821
  if (this.context.implicitMemberAccess !== true) return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.89.11",
3
+ "version": "0.89.13",
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.11 -->
12
+ <!-- reviewed-through-cli: 0.89.13 -->
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.11 -->
146
+ <!-- reviewed-through-cli: 0.89.13 -->
147
147
  ```
148
148
 
149
149
  Keep this skill on current behavior. Upgrade steps, rollout prerequisites,
@@ -43,6 +43,9 @@ Generic bindings and their nested collection descriptors follow the owning
43
43
  declaration's identity. Deleting and recreating an idless declaration creates
44
44
  fresh bindings; retaining its pulled IDs preserves them.
45
45
 
46
+ Editor rename follows an interface member through its compatible implementations
47
+ and overrides. Unrelated members and overloads keep their names.
48
+
46
49
  ## Modifiers
47
50
 
48
51
  `public`, `protected`, `private`, `static`, `virtual`, `abstract`, `sealed`,
@@ -36,6 +36,8 @@ indentation, using the project's configured spaces or tabs.
36
36
  The editor checks computed defaults with the same expression resolver as push.
37
37
  Unknown names, missing members, invalid type arguments, and expression type
38
38
  errors appear at the offending initializer expression, including nested defaults.
39
+ This includes simple member reads such as `value.Name`: nullable receivers and
40
+ private or protected access receive the same checks as executable bodies.
39
41
 
40
42
  A default that isn't a closed literal stores as a computed initializer and
41
43
  replays for omitted members in push, web, and SDK. A stored override stays
@@ -149,3 +149,5 @@ computed properties and callable signatures for cursors; store `List<T>` data
149
149
  explicitly. Stored enumerable interface members accept authored class rows.
150
150
  Runtime sequences are shown as unenumerated and are not expanded for previews.
151
151
  `ToSet()` rejects enumerable/cursor interface elements.
152
+
153
+ `Clone()` also copies owned class values inside tuples. References inside the copied graph keep their targets.
@@ -11,7 +11,12 @@ List<Item> ready = this.Items.Where((item) => item.Count > 0);
11
11
  ```
12
12
 
13
13
  - Lambdas may be returned, stored, or assigned to typed locals. They capture
14
- surrounding locals and parameters by value when created.
14
+ surrounding locals and parameters by value when created. A non-null check
15
+ on a local remains valid inside its capture, even if the outer local is later
16
+ reassigned. This does not freeze mutable fields on captured objects.
17
+ A captured value can share a class name; member access uses the value.
18
+ - Editor completion uses the delegate parameter type inside tuple values and
19
+ named constructor arguments, including overloaded constructors.
15
20
  - `(x) => x * 2` equals `(x) => { return x * 2; }`. In a void delegate the
16
21
  expression must call or assign. Parenthesize a dictionary-literal body:
17
22
  `() => ({ "a": 1 })`.
@@ -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
@@ -64,6 +64,10 @@ frame. For editing an existing clip, see [frame overrides](animation.md).
64
64
  as instance overrides, and `ToVariant(Base)` removes the applied layer.
65
65
  - On an object nested inside another instance's construction, `ToVariant`
66
66
  applies in place and records nothing.
67
+ - Child overrides also answer omitted fields on children with their own
68
+ constructor recipes. The child keeps its identity and unanswered defaults.
69
+ Later instance writes remain pins until an answering variant transition clears
70
+ them. Structured partials change only the named components.
67
71
  - Selections compare equal when class, variant, and bound lookup row match.
68
72
  An unset optional selection differs from `Base`.
69
73