@neocompose/cli 0.73.1 → 0.73.2

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.73.2] - 2026-10-08
4
+
5
+ - Use the same pending getter identity in schema declarations and NeoFlow interpolation. New getters export before their first push, including inherited getters, without manually authored IDs.
6
+
7
+ - Reject lookup declarations and constructed targets incompatible with their configured collection before push, test, or export. Preserve valid subclass lookups and report declaration errors at the authored collection annotation.
8
+
3
9
  ## [0.73.1] - 2026-10-08
4
10
 
5
11
  - Breaking: rename `PriorityOption` to `NeoPriorityOption` in priority groups, to match `NeoPriorityGroup`. The old name is a compile error that names its replacement, and dialogue priorities that use the option still resolve. Stored data doesn't change. `neo pull` writes the new name.
package/dist/neo.mjs CHANGED
@@ -20692,6 +20692,13 @@ function span(identity2) {
20692
20692
  function materializedId(identity2, kind, name) {
20693
20693
  return materializedIdentityId(identity2, kind, name);
20694
20694
  }
20695
+ function materializedMemberId(owner, member) {
20696
+ return materializedId(
20697
+ member,
20698
+ owner.kind === "class" ? "member" : "interface-member",
20699
+ `${owner.name}.${member.name}`
20700
+ );
20701
+ }
20695
20702
  function materializedIdentityId(identity2, kind, name) {
20696
20703
  return identity2.id ?? `__pending__:${kind}:${encodeURIComponent(identity2.source.uri)}:${identity2.source.range.start.line}:${identity2.source.range.start.character}:${encodeURIComponent(name)}`;
20697
20704
  }
@@ -43884,6 +43891,16 @@ function validateAnnotations(uri, annotations, context, environment, diagnostics
43884
43891
  continue;
43885
43892
  }
43886
43893
  }
43894
+ if (annotation2.name === "settings" && field.name === "collection" && "type" in context) {
43895
+ validateLookupCollectionType(
43896
+ uri,
43897
+ argument2.text,
43898
+ argument2.range,
43899
+ context.type,
43900
+ environment,
43901
+ diagnostics
43902
+ );
43903
+ }
43887
43904
  validateExpressionText(
43888
43905
  uri,
43889
43906
  argument2.text,
@@ -43897,6 +43914,37 @@ function validateAnnotations(uri, annotations, context, environment, diagnostics
43897
43914
  }
43898
43915
  }
43899
43916
  }
43917
+ function validateLookupCollectionType(uri, collection, range2, declared, environment, diagnostics) {
43918
+ const path = collection.trim().split(".");
43919
+ const [owner, name] = path;
43920
+ if (path.length !== 2 || owner === void 0 || name === void 0) return;
43921
+ const field = sourceClassMemberForType({ name: owner }, name, environment);
43922
+ if (!field) return;
43923
+ const collectionType = substituteSemanticType(
43924
+ semanticType(field.member.type),
43925
+ field.bindings
43926
+ );
43927
+ const entryIndex = collectionElementIndex(collectionType.name);
43928
+ const entry = entryIndex === null ? void 0 : collectionType.arguments?.[entryIndex];
43929
+ const target = declared.name === "List" || declared.name === "Set" ? declared.arguments?.[0] : declared;
43930
+ if (!entry || !target) return;
43931
+ if (!environment.types.has(target.name) || !environment.types.has(entry.name))
43932
+ return;
43933
+ if (constructionTypesAssignable(
43934
+ { ...target, nullable: false },
43935
+ { ...entry, nullable: false },
43936
+ environment.globals,
43937
+ environment
43938
+ ))
43939
+ return;
43940
+ pushDiagnostic(
43941
+ diagnostics,
43942
+ uri,
43943
+ range2,
43944
+ "lookup-collection-type-mismatch",
43945
+ `Lookup declares ${describeType(target)}, but collection ${collection.trim()} holds ${describeType(entry)}.`
43946
+ );
43947
+ }
43900
43948
  function fieldsForAnnotation(name, context, environment) {
43901
43949
  if (name === "id") {
43902
43950
  return context.kind === "class" || context.kind === "schema" || context.kind === "member" || context.kind === "variantGlobal" || context.kind === "projectFile" || context.kind === "flowMember" || context.kind === "flowBinding" || context.kind === "flowGraph" ? [{ name: "id", type: "string" }] : null;
@@ -51641,7 +51689,7 @@ var init_registry = __esm({
51641
51689
  "../packages/manifest/schema-contract/registry.mjs"() {
51642
51690
  "use strict";
51643
51691
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
51644
- cliVersion: "0.73.1",
51692
+ cliVersion: "0.73.2",
51645
51693
  projectFileUploadBatchSize: 32,
51646
51694
  documentRecords: {
51647
51695
  member: {
@@ -66497,11 +66545,7 @@ function lowerClass(context, declaration) {
66497
66545
  const schema = {};
66498
66546
  const schemaKeyOrder = [];
66499
66547
  for (const memberDeclaration of declaration.members) {
66500
- const memberId = materializedId(
66501
- memberDeclaration,
66502
- "member",
66503
- `${declaration.name}.${memberDeclaration.name}`
66504
- );
66548
+ const memberId = materializedMemberId(declaration, memberDeclaration);
66505
66549
  schema[memberDeclaration.name] = memberId;
66506
66550
  schemaKeyOrder.push(memberDeclaration.name);
66507
66551
  const placement = { classId: id2, schemaKey: memberDeclaration.name };
@@ -67556,11 +67600,7 @@ function lowerInterface(context, declaration) {
67556
67600
  const id2 = materializedId(declaration, "interface", declaration.name);
67557
67601
  const base = context.baseInterfaces.get(id2);
67558
67602
  const members = declaration.members.map((member) => {
67559
- const memberId = materializedId(
67560
- member,
67561
- "interface-member",
67562
- `${declaration.name}.${member.name}`
67563
- );
67603
+ const memberId = materializedMemberId(declaration, member);
67564
67604
  const source = sourceIdentity(member, "interfaceMember", member.name);
67565
67605
  const accessModifier = effectiveSourceAccessModifier(
67566
67606
  member.modifiers,
@@ -68829,11 +68869,7 @@ function effectiveMemberIdByName(context, startClassId, name) {
68829
68869
  (member) => member.name === name
68830
68870
  );
68831
68871
  if (sourceMember !== void 0) {
68832
- return materializedId(
68833
- sourceMember,
68834
- "member",
68835
- `${sourceClass.name}.${sourceMember.name}`
68836
- );
68872
+ return materializedMemberId(sourceClass, sourceMember);
68837
68873
  }
68838
68874
  const sourceBase = sourceClass.baseTypes.find(
68839
68875
  (entry) => context.classIdsByName.has(entry.name)
@@ -73049,7 +73085,7 @@ function globalIds2(globals, kind) {
73049
73085
  return new Map(
73050
73086
  globals.map((global) => [
73051
73087
  global.name,
73052
- schemaIdentityId(global, kind, global.name)
73088
+ materializedId(global, kind, global.name)
73053
73089
  ])
73054
73090
  );
73055
73091
  }
@@ -73062,9 +73098,6 @@ function sourceId2(source, kind, name) {
73062
73098
  name
73063
73099
  );
73064
73100
  }
73065
- function schemaIdentityId(source, kind, name) {
73066
- return source.id ?? `__pending__:${kind}:${encodeURIComponent(source.source.uri)}:${source.source.range.start.line}:${source.source.range.start.character}:${encodeURIComponent(name)}`;
73067
- }
73068
73101
  function pendingId(kind, uri, owner, ordinal, name) {
73069
73102
  return `__pending__:${kind}:${encodeURIComponent(uri)}:${encodeURIComponent(owner)}:${ordinal}:${encodeURIComponent(name)}`;
73070
73103
  }
@@ -73107,6 +73140,7 @@ var SourceSchemaIndex;
73107
73140
  var init_dialogue_lower = __esm({
73108
73141
  "src/project-source/dialogue-lower.ts"() {
73109
73142
  "use strict";
73143
+ init_lower_support();
73110
73144
  init_dialogue_source_names();
73111
73145
  init_dialogue_group_paths();
73112
73146
  init_local_values();
@@ -73140,7 +73174,7 @@ var init_dialogue_lower = __esm({
73140
73174
  );
73141
73175
  this.classesById = new Map(
73142
73176
  analysis.schema.classes.map((entry) => [
73143
- schemaIdentityId(entry, "class", entry.name),
73177
+ materializedId(entry, "class", entry.name),
73144
73178
  entry
73145
73179
  ])
73146
73180
  );
@@ -73149,7 +73183,7 @@ var init_dialogue_lower = __esm({
73149
73183
  );
73150
73184
  this.interfacesById = new Map(
73151
73185
  analysis.schema.interfaces.map((entry) => [
73152
- schemaIdentityId(entry, "interface", entry.name),
73186
+ materializedId(entry, "interface", entry.name),
73153
73187
  entry
73154
73188
  ])
73155
73189
  );
@@ -73157,20 +73191,18 @@ var init_dialogue_lower = __esm({
73157
73191
  analysis.schema.enums.map((entry) => [entry.name, entry])
73158
73192
  );
73159
73193
  this.memberNamesById = new Map(
73160
- [
73161
- ...analysis.schema.classes.flatMap((entry) => entry.members),
73162
- ...analysis.schema.interfaces.flatMap((entry) => entry.members)
73163
- ].map((member) => [
73164
- schemaIdentityId(member, "member", member.name),
73165
- member.name
73166
- ])
73194
+ [...analysis.schema.classes, ...analysis.schema.interfaces].flatMap(
73195
+ (owner) => owner.members.map(
73196
+ (member) => [materializedMemberId(owner, member), member.name]
73197
+ )
73198
+ )
73167
73199
  );
73168
73200
  this.staticMemberExpressionsById = new Map(
73169
73201
  analysis.schema.classes.flatMap(
73170
73202
  (schemaClass2) => schemaClass2.members.flatMap(
73171
73203
  (member) => member.modifiers.includes("static") ? [
73172
73204
  [
73173
- schemaIdentityId(member, "member", member.name),
73205
+ materializedMemberId(schemaClass2, member),
73174
73206
  `${schemaClass2.name}.${member.name}`
73175
73207
  ]
73176
73208
  ] : []
@@ -73181,7 +73213,7 @@ var init_dialogue_lower = __esm({
73181
73213
  analysis.schema.enums.flatMap(
73182
73214
  (schemaEnum) => schemaEnum.options.map(
73183
73215
  (option) => [
73184
- schemaIdentityId(option, "enum-option", option.name),
73216
+ materializedId(option, "enum-option", option.name),
73185
73217
  option.name
73186
73218
  ]
73187
73219
  )
@@ -73245,13 +73277,13 @@ var init_dialogue_lower = __esm({
73245
73277
  };
73246
73278
  }
73247
73279
  classMember(schemaClass2, receiver, name, visited) {
73248
- const classId = schemaIdentityId(schemaClass2, "class", schemaClass2.name);
73280
+ const classId = materializedId(schemaClass2, "class", schemaClass2.name);
73249
73281
  if (visited.has(classId)) return null;
73250
73282
  visited.add(classId);
73251
73283
  const generics = this.genericEnvironment(schemaClass2, receiver);
73252
73284
  const own = schemaClass2.members.find((member) => member.name === name);
73253
73285
  if (own !== void 0) {
73254
- return this.resolvedMember(own, generics, true);
73286
+ return this.resolvedMember(schemaClass2, own, generics);
73255
73287
  }
73256
73288
  for (const base of schemaClass2.baseTypes) {
73257
73289
  const parent = this.classesByName.get(base.name);
@@ -73264,7 +73296,7 @@ var init_dialogue_lower = __esm({
73264
73296
  return null;
73265
73297
  }
73266
73298
  interfaceMember(schemaInterface, name, visited) {
73267
- const interfaceId = schemaIdentityId(
73299
+ const interfaceId = materializedId(
73268
73300
  schemaInterface,
73269
73301
  "interface",
73270
73302
  schemaInterface.name
@@ -73272,7 +73304,8 @@ var init_dialogue_lower = __esm({
73272
73304
  if (visited.has(interfaceId)) return null;
73273
73305
  visited.add(interfaceId);
73274
73306
  const own = schemaInterface.members.find((member) => member.name === name);
73275
- if (own !== void 0) return this.resolvedMember(own, /* @__PURE__ */ new Map(), false);
73307
+ if (own !== void 0)
73308
+ return this.resolvedMember(schemaInterface, own, /* @__PURE__ */ new Map());
73276
73309
  for (const base of schemaInterface.baseTypes) {
73277
73310
  const parent = this.interfacesByName.get(base.name);
73278
73311
  if (parent === void 0) continue;
@@ -73281,13 +73314,13 @@ var init_dialogue_lower = __esm({
73281
73314
  }
73282
73315
  return null;
73283
73316
  }
73284
- resolvedMember(member, generics, classPropertyIsGetter) {
73317
+ resolvedMember(owner, member, generics) {
73285
73318
  if (member.kind === "function") return null;
73286
73319
  const typeInfo = this.typeInfoForManifestType(member.type, generics);
73287
73320
  if (typeInfo === null) return null;
73288
73321
  return {
73289
- kind: classPropertyIsGetter && member.kind === "property" ? "getter" : "stored",
73290
- memberId: schemaIdentityId(member, "member", member.name),
73322
+ kind: owner.kind === "class" && member.kind === "property" ? "getter" : "stored",
73323
+ memberId: materializedMemberId(owner, member),
73291
73324
  schemaKey: member.name,
73292
73325
  typeInfo
73293
73326
  };
@@ -73295,7 +73328,7 @@ var init_dialogue_lower = __esm({
73295
73328
  genericEnvironment(schemaClass2, receiver) {
73296
73329
  const result = /* @__PURE__ */ new Map();
73297
73330
  for (const parameter4 of schemaClass2.genericParameters) {
73298
- const parameterId = schemaIdentityId(
73331
+ const parameterId = materializedId(
73299
73332
  parameter4.identity,
73300
73333
  "generic-parameter",
73301
73334
  `${schemaClass2.name}.${parameter4.name}`
@@ -73348,12 +73381,12 @@ var init_dialogue_lower = __esm({
73348
73381
  type: type.name === "Dictionary" ? 5 /* Dictionary */ : 6 /* List */,
73349
73382
  required: required2,
73350
73383
  entryTypeInfo,
73351
- ...keyEnum === void 0 ? {} : { keyEnumId: schemaIdentityId(keyEnum, "enum", keyEnum.name) }
73384
+ ...keyEnum === void 0 ? {} : { keyEnumId: materializedId(keyEnum, "enum", keyEnum.name) }
73352
73385
  };
73353
73386
  }
73354
73387
  const schemaClass2 = this.classesByName.get(type.name);
73355
73388
  if (schemaClass2 !== void 0) {
73356
- const classId = schemaIdentityId(schemaClass2, "class", schemaClass2.name);
73389
+ const classId = materializedId(schemaClass2, "class", schemaClass2.name);
73357
73390
  const typeArguments = Object.fromEntries(
73358
73391
  schemaClass2.genericParameters.flatMap((parameter4, index) => {
73359
73392
  const argument2 = type.arguments[index];
@@ -73362,7 +73395,7 @@ var init_dialogue_lower = __esm({
73362
73395
  if (argumentType === null) return [];
73363
73396
  return [
73364
73397
  [
73365
- schemaIdentityId(
73398
+ materializedId(
73366
73399
  parameter4.identity,
73367
73400
  "generic-parameter",
73368
73401
  `${schemaClass2.name}.${parameter4.name}`
@@ -73383,7 +73416,7 @@ var init_dialogue_lower = __esm({
73383
73416
  if (neoInterface !== void 0) {
73384
73417
  return {
73385
73418
  type: 22 /* Interface */,
73386
- interfaceId: schemaIdentityId(
73419
+ interfaceId: materializedId(
73387
73420
  neoInterface,
73388
73421
  "interface",
73389
73422
  neoInterface.name
@@ -73395,7 +73428,7 @@ var init_dialogue_lower = __esm({
73395
73428
  if (neoEnum !== void 0) {
73396
73429
  return {
73397
73430
  type: 8 /* Enum */,
73398
- enumId: schemaIdentityId(neoEnum, "enum", neoEnum.name),
73431
+ enumId: materializedId(neoEnum, "enum", neoEnum.name),
73399
73432
  required: required2
73400
73433
  };
73401
73434
  }
@@ -106560,6 +106593,67 @@ var init_project_commit_preparation_scoped_loader = __esm({
106560
106593
  }
106561
106594
  });
106562
106595
 
106596
+ // ../src/database/lookup-target-class-contract.ts
106597
+ function lookupTargetClassContractViolation(args) {
106598
+ const actualClassId = typeof args.targetClassId === "string" ? args.targetClassId : null;
106599
+ if (actualClassId === null) return null;
106600
+ const classById = args.schemaIndex.classesById;
106601
+ if (!classById.has(actualClassId)) return null;
106602
+ const entryClassId = lookupEntryClassId(
106603
+ args.member,
106604
+ args.schemaIndex.membersById
106605
+ );
106606
+ if (entryClassId !== null && classById.has(entryClassId) && !args.schemaIndex.classIsOrExtends(actualClassId, entryClassId)) {
106607
+ return `lookup member ${args.member.name} target ${args.targetValueId} is ${classDisplayName(actualClassId, classById)}, but collection ${collectionMemberName(args.member, args.schemaIndex)} holds ${classDisplayName(entryClassId, classById)}.`;
106608
+ }
106609
+ const declaredClassId = lookupDeclaredClassId(args.member, classById);
106610
+ if (declaredClassId !== null && !args.schemaIndex.classIsOrExtends(actualClassId, declaredClassId)) {
106611
+ const narrowedFrom = entryClassId === null || !classById.has(entryClassId) ? `the collection ${collectionMemberName(args.member, args.schemaIndex)}` : `the collection ${collectionMemberName(args.member, args.schemaIndex)} holds ${classDisplayName(entryClassId, classById)}`;
106612
+ return `lookup member ${args.member.name} target ${args.targetValueId} is ${classDisplayName(actualClassId, classById)}, but the member declares ${classDisplayName(declaredClassId, classById)} \u2014 ${narrowedFrom} and this member narrows it. Point it at a ${classDisplayName(declaredClassId, classById)} row.`;
106613
+ }
106614
+ return null;
106615
+ }
106616
+ function lookupEntryClassId(member, memberById2) {
106617
+ const collection = memberById2.get(member.collectionMemberId);
106618
+ if (collection === void 0) return null;
106619
+ if (!isMemberListBase(collection) && !isMemberDictionaryBase(collection)) {
106620
+ return null;
106621
+ }
106622
+ const entry = memberById2.get(collection.entryMemberId);
106623
+ if (entry === void 0) return null;
106624
+ return isMemberClassBase(entry) ? entry.classId : null;
106625
+ }
106626
+ function lookupDeclaredClassId(member, classById) {
106627
+ const declared = member.declaredTypeInfo;
106628
+ if (declared === void 0) return null;
106629
+ if (declared === null) return null;
106630
+ if (declared.type !== 7 /* Class */) return null;
106631
+ return classById.has(declared.classId) ? declared.classId : null;
106632
+ }
106633
+ function classDisplayName(classId, classById) {
106634
+ return classById.get(classId)?.name ?? classId;
106635
+ }
106636
+ function collectionMemberName(member, schemaIndex) {
106637
+ const collection = schemaIndex.membersById.get(member.collectionMemberId);
106638
+ if (collection === void 0) return member.collectionMemberId;
106639
+ const owner = schemaIndex.schemaPlacementsByMemberId.get(collection.id)?.[0]?.ownerClass;
106640
+ return owner ? `${owner.name}.${collection.name}` : collection.name;
106641
+ }
106642
+ function lookupDeclaredClassContractViolation(member, schemaIndex) {
106643
+ const declared = lookupDeclaredClassId(member, schemaIndex.classesById);
106644
+ const entry = lookupEntryClassId(member, schemaIndex.membersById);
106645
+ if (declared === null || entry === null || !schemaIndex.classesById.has(entry))
106646
+ return null;
106647
+ if (schemaIndex.classIsOrExtends(declared, entry)) return null;
106648
+ return `Lookup member ${member.name} declares ${classDisplayName(declared, schemaIndex.classesById)}, but collection ${collectionMemberName(member, schemaIndex)} holds ${classDisplayName(entry, schemaIndex.classesById)}.`;
106649
+ }
106650
+ var init_lookup_target_class_contract = __esm({
106651
+ "../src/database/lookup-target-class-contract.ts"() {
106652
+ "use strict";
106653
+ init_member_kinds();
106654
+ }
106655
+ });
106656
+
106563
106657
  // ../src/models/dialogue-context-resolver.ts
106564
106658
  function resolveDialoguePrimaryValueId(dialogue) {
106565
106659
  return dialogue.primaryLinkedValueId ?? null;
@@ -110127,76 +110221,6 @@ var init_project_document_value_overlay = __esm({
110127
110221
  }
110128
110222
  });
110129
110223
 
110130
- // ../src/database/lookup-target-class-contract.ts
110131
- function lookupTargetClassContractViolation(args) {
110132
- const actualClassId = typeof args.targetClassId === "string" ? args.targetClassId : null;
110133
- if (actualClassId === null) return null;
110134
- const classById = new Map(
110135
- args.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
110136
- );
110137
- if (!classById.has(actualClassId)) return null;
110138
- const entryClassId = lookupEntryClassId(args.member, args.memberById);
110139
- const collectionName = collectionMemberName(
110140
- args.member,
110141
- args.memberById,
110142
- args.classes
110143
- );
110144
- if (entryClassId !== null && classById.has(entryClassId) && !classAssignableToClass(actualClassId, entryClassId, classById)) {
110145
- return `lookup member ${args.member.name} target ${args.targetValueId} is ${classDisplayName(actualClassId, classById)}, but collection ${collectionName} holds ${classDisplayName(entryClassId, classById)}.`;
110146
- }
110147
- const declaredClassId = lookupDeclaredClassId(args.member, classById);
110148
- if (declaredClassId !== null && !classAssignableToClass(actualClassId, declaredClassId, classById)) {
110149
- const narrowedFrom = entryClassId === null || !classById.has(entryClassId) ? `the collection ${collectionName}` : `the collection ${collectionName} holds ${classDisplayName(entryClassId, classById)}`;
110150
- return `lookup member ${args.member.name} target ${args.targetValueId} is ${classDisplayName(actualClassId, classById)}, but the member declares ${classDisplayName(declaredClassId, classById)} \u2014 ${narrowedFrom} and this member narrows it. Point it at a ${classDisplayName(declaredClassId, classById)} row.`;
110151
- }
110152
- return null;
110153
- }
110154
- function lookupEntryClassId(member, memberById2) {
110155
- const collection = memberById2.get(member.collectionMemberId);
110156
- if (collection === void 0) return null;
110157
- if (!isMemberListBase(collection) && !isMemberDictionaryBase(collection)) {
110158
- return null;
110159
- }
110160
- const entry = memberById2.get(collection.entryMemberId);
110161
- if (entry === void 0) return null;
110162
- return isMemberClassBase(entry) ? entry.classId : null;
110163
- }
110164
- function lookupDeclaredClassId(member, classById) {
110165
- const declared = member.declaredTypeInfo;
110166
- if (declared === void 0) return null;
110167
- if (declared === null) return null;
110168
- if (declared.type !== 7 /* Class */) return null;
110169
- return classById.has(declared.classId) ? declared.classId : null;
110170
- }
110171
- function classAssignableToClass(actualClassId, expectedClassId, classById) {
110172
- const visited = /* @__PURE__ */ new Set();
110173
- let current = actualClassId;
110174
- while (current !== void 0 && !visited.has(current)) {
110175
- if (current === expectedClassId) return true;
110176
- visited.add(current);
110177
- current = classById.get(current)?.extendsClassId;
110178
- }
110179
- return false;
110180
- }
110181
- function classDisplayName(classId, classById) {
110182
- return classById.get(classId)?.name ?? classId;
110183
- }
110184
- function collectionMemberName(member, memberById2, classes) {
110185
- const collection = memberById2.get(member.collectionMemberId);
110186
- if (collection === void 0) return member.collectionMemberId;
110187
- const owner = classes.find(
110188
- (schemaClass2) => Object.values(schemaClass2.schema).includes(member.collectionMemberId)
110189
- );
110190
- if (owner === void 0) return collection.name;
110191
- return `${owner.name}.${collection.name}`;
110192
- }
110193
- var init_lookup_target_class_contract = __esm({
110194
- "../src/database/lookup-target-class-contract.ts"() {
110195
- "use strict";
110196
- init_member_kinds();
110197
- }
110198
- });
110199
-
110200
110224
  // ../src/database/stored-value-graph-semantics.ts
110201
110225
  function inspectStoredValueNode(options) {
110202
110226
  try {
@@ -111024,8 +111048,7 @@ var init_project_version_static_value_writes = __esm({
111024
111048
  member: dependency.member,
111025
111049
  targetValueId: targetId,
111026
111050
  targetClassId: target.classId ?? null,
111027
- memberById: this.schemaIndex.membersById,
111028
- classes: this.schemaIndex.classes
111051
+ schemaIndex: this.schemaIndex
111029
111052
  });
111030
111053
  if (violation !== null) throw new Error(`${path} ${violation}`);
111031
111054
  }
@@ -114350,7 +114373,10 @@ function hasAuthoredNeoScriptBody(member) {
114350
114373
  function assertConstructedGraphReferencesResolve(args) {
114351
114374
  const sites = collectTouchedInitializerSites(args);
114352
114375
  if (sites.length === 0) return;
114353
- const valueIds = new Set(args.document.values.map((value) => value.id));
114376
+ const valueById = new Map(
114377
+ args.document.values.map((value) => [value.id, value])
114378
+ );
114379
+ const schemaIndex = projectSchemaIndexFor(args.document);
114354
114380
  for (const site of sites) {
114355
114381
  if ((site.init.compiled?.parameters.length ?? 2) > 2) continue;
114356
114382
  if (site.sourceValueId === void 0 && [
@@ -114374,7 +114400,8 @@ function assertConstructedGraphReferencesResolve(args) {
114374
114400
  site,
114375
114401
  produced,
114376
114402
  createdValues,
114377
- documentValueIds: valueIds
114403
+ documentValuesById: valueById,
114404
+ schemaIndex
114378
114405
  });
114379
114406
  }
114380
114407
  }
@@ -114438,7 +114465,6 @@ function collectTouchedInitializerSites(args) {
114438
114465
  return sites;
114439
114466
  }
114440
114467
  function assertProducedGraphLookupsResolve(args) {
114441
- if (args.createdValues.length === 0) return;
114442
114468
  const rootMember = args.produced.classId === null ? args.site.member : { ...args.site.member, classId: args.produced.classId };
114443
114469
  const graphValues = args.createdValues;
114444
114470
  const rootRow = {
@@ -114464,20 +114490,28 @@ function assertProducedGraphLookupsResolve(args) {
114464
114490
  new Set(args.createdValues.map((value) => value.id)),
114465
114491
  [{ member: rootMember, valueId: rootRow.id }]
114466
114492
  );
114467
- const resolvableIds = /* @__PURE__ */ new Set([
114468
- ...args.documentValueIds,
114469
- ...args.createdValues.map((value) => value.id)
114470
- ]);
114471
- for (const row of args.createdValues) {
114472
- const member = ownerByValueId.get(row.id);
114473
- if (member === void 0 || member.kind !== 9 /* Lookup */) continue;
114493
+ const createdById = new Map(graphValues.map((value) => [value.id, value]));
114494
+ createdById.set(rootRow.id, rootRow);
114495
+ for (const row of createdById.values()) {
114496
+ const member = row === rootRow ? rootMember : ownerByValueId.get(row.id);
114497
+ if (member === void 0 || !isMemberLookupBase(member)) continue;
114474
114498
  if (!Array.isArray(row.value)) continue;
114475
114499
  for (const targetId of row.value) {
114476
114500
  if (typeof targetId !== "string") continue;
114477
- if (resolvableIds.has(targetId)) continue;
114478
- throw new Error(
114479
- `${args.site.label} constructs "${member.name}" pointing at value "${targetId}", which the construction does not produce and this project version does not contain.`
114480
- );
114501
+ const target = createdById.get(targetId) ?? args.documentValuesById.get(targetId) ?? initializerEvaluatorLookups(args.document).valueById(targetId);
114502
+ if (target === void 0 || target === null) {
114503
+ throw new Error(
114504
+ `${args.site.label} constructs "${member.name}" pointing at value "${targetId}", which the construction does not produce and this project version does not contain.`
114505
+ );
114506
+ }
114507
+ const violation = lookupTargetClassContractViolation({
114508
+ member,
114509
+ targetValueId: targetId,
114510
+ targetClassId: target.classId,
114511
+ schemaIndex: args.schemaIndex
114512
+ });
114513
+ if (violation !== null)
114514
+ throw new Error(`${args.site.label} ${violation}`);
114481
114515
  }
114482
114516
  }
114483
114517
  }
@@ -115468,6 +115502,9 @@ var SERVER_COMPILATION_PROJECT_CACHE_LIMIT, serverCompilationProjectCache, READ_
115468
115502
  var init_project_version_schema_commit = __esm({
115469
115503
  "../src/database/project-version-schema-commit.ts"() {
115470
115504
  "use strict";
115505
+ init_member_kinds();
115506
+ init_project_schema_index();
115507
+ init_lookup_target_class_contract();
115471
115508
  init_dialogue_logic_compile_pure();
115472
115509
  init_neoscript_compiler_revision();
115473
115510
  init_neoscript_source_catalog();
@@ -121203,6 +121240,19 @@ function assertProjectVersionWholeGraphWritesValid(args) {
121203
121240
  assertStagedUnorderedContainmentValid(args.document, projected, changes);
121204
121241
  assertWorldFootprintEntryTypes(projected, changes);
121205
121242
  assertStagedSchemaIdentifiersValid(projected, changes);
121243
+ if (changes.some(
121244
+ (change) => change.recordKind === "member" || change.recordKind === "class"
121245
+ )) {
121246
+ const schemaIndex = projectSchemaIndexFor(projected);
121247
+ for (const member of projected.members) {
121248
+ if (!isMemberLookupBase(member)) continue;
121249
+ const violation = lookupDeclaredClassContractViolation(
121250
+ member,
121251
+ schemaIndex
121252
+ );
121253
+ if (violation !== null) throw new Error(violation);
121254
+ }
121255
+ }
121206
121256
  assertStagedActionListenersValid(projected, changes);
121207
121257
  assertStagedUserDelegateTargetsValid(projected, changes);
121208
121258
  assertAuthoredMemberChangeListenersValid(args.document, projected, changes);
@@ -122417,6 +122467,9 @@ var KNOWN_TRANSACTION_OPERATIONS, INTERFACE_VALIDATED_RECORD_KINDS, ACTION_LISTE
122417
122467
  var init_project_version_whole_graph_validation = __esm({
122418
122468
  "../src/database/project-version-whole-graph-validation.ts"() {
122419
122469
  "use strict";
122470
+ init_member_kinds();
122471
+ init_project_schema_index();
122472
+ init_lookup_target_class_contract();
122420
122473
  init_project_root_members();
122421
122474
  init_neoscript_source_catalog();
122422
122475
  init_canonical_json();
@@ -129665,7 +129718,7 @@ function constructedClass(context, member, expression, currentClassId, path) {
129665
129718
  return target;
129666
129719
  }
129667
129720
  function assertConstructedClassAssignable(context, named, member, path) {
129668
- if (classAssignableToClass2(context, named.id, member.classId)) return;
129721
+ if (classAssignableToClass(context, named.id, member.classId)) return;
129669
129722
  const declaredName = context.classes.get(member.classId)?.name ?? member.classId;
129670
129723
  throw new Error(
129671
129724
  `Class value ${path} constructs ${named.name}, which does not descend from the declared class ${declaredName}.`
@@ -130371,13 +130424,13 @@ function validateReferenceContract(context, member, target, ownerValueId) {
130371
130424
  const expectedTypeName = lookupEntryTypeName(context, member);
130372
130425
  const targetData = valueData(context, target.id);
130373
130426
  const actualClassId = targetData && typeof targetData.classId === "string" ? targetData.classId : null;
130374
- if (expectedClassId && actualClassId && !classAssignableToClass2(context, actualClassId, expectedClassId)) {
130427
+ if (expectedClassId && actualClassId && !classAssignableToClass(context, actualClassId, expectedClassId)) {
130375
130428
  throw new Error(
130376
130429
  `Lookup member ${member.name} target ${target.id} is ${classDisplayName2(context, actualClassId)}, but collection ${collectionMemberName2(context, member)} holds ${classDisplayName2(context, expectedClassId)}.`
130377
130430
  );
130378
130431
  }
130379
130432
  const declaredClassId = lookupDeclaredClassId2(context, member);
130380
- if (declaredClassId && actualClassId && !classAssignableToClass2(context, actualClassId, declaredClassId)) {
130433
+ if (declaredClassId && actualClassId && !classAssignableToClass(context, actualClassId, declaredClassId)) {
130381
130434
  const narrowedFrom = expectedClassId === null ? `the collection ${collectionMemberName2(context, member)}` : `the collection ${collectionMemberName2(context, member)} holds ${classDisplayName2(context, expectedClassId)}`;
130382
130435
  throw new Error(
130383
130436
  `Lookup member ${member.name} target ${target.id} is ${classDisplayName2(context, actualClassId)}, but the member declares ${classDisplayName2(context, declaredClassId)} \u2014 ${narrowedFrom} and this member narrows it. Point it at a ${classDisplayName2(context, declaredClassId)} row.`
@@ -130437,7 +130490,7 @@ function referenceTypeNameAssignable(context, actualName, expectedName) {
130437
130490
  const actualClass = context.classesByName.get(actualName);
130438
130491
  const expectedClass = context.classesByName.get(expectedName);
130439
130492
  if (actualClass && expectedClass) {
130440
- return classAssignableToClass2(context, actualClass.id, expectedClass.id);
130493
+ return classAssignableToClass(context, actualClass.id, expectedClass.id);
130441
130494
  }
130442
130495
  const expectedInterfaceId = context.interfaceIdsByName.get(expectedName);
130443
130496
  return actualClass && expectedInterfaceId ? classImplementsInterface2(
@@ -130721,7 +130774,7 @@ function lookupEntryClassId2(context, member) {
130721
130774
  const entry = collection?.kind === "list" || collection?.kind === "dictionary" ? context.members.get(collection.entryMemberId) : null;
130722
130775
  return entry?.kind === "class" ? entry.classId : null;
130723
130776
  }
130724
- function classAssignableToClass2(context, actualClassId, expectedClassId) {
130777
+ function classAssignableToClass(context, actualClassId, expectedClassId) {
130725
130778
  let current = actualClassId;
130726
130779
  const visited = /* @__PURE__ */ new Set();
130727
130780
  while (current && !visited.has(current)) {
@@ -135969,11 +136022,7 @@ function lowerProjectSchemaV4(base, analysis, options = {}) {
135969
136022
  analysis.schema.classes.flatMap(
135970
136023
  (ownerClass) => ownerClass.members.map(
135971
136024
  (member) => [
135972
- materializedId(
135973
- member,
135974
- "member",
135975
- `${ownerClass.name}.${member.name}`
135976
- ),
136025
+ materializedMemberId(ownerClass, member),
135977
136026
  { ownerClass, member }
135978
136027
  ]
135979
136028
  )
@@ -137676,6 +137725,7 @@ function emitProse(context, textId, rawVariables, nodeBindings, primaryAlias) {
137676
137725
  );
137677
137726
  const variables = isObjectRecord2(rawVariables) ? rawVariables : {};
137678
137727
  const pieces = [];
137728
+ let pointerResolver;
137679
137729
  let cursor = 0;
137680
137730
  const pattern = /\{\{neo-var:([^}]+)\}\}/g;
137681
137731
  for (let match = pattern.exec(text); match !== null; match = pattern.exec(text)) {
@@ -137687,12 +137737,25 @@ function emitProse(context, textId, rawVariables, nodeBindings, primaryAlias) {
137687
137737
  cursor = pattern.lastIndex;
137688
137738
  continue;
137689
137739
  }
137690
- const sourcePath = authoredVariablePath(
137691
- variable2.sourcePath,
137692
- nodeBindings,
137693
- context.bindings,
137694
- context.memberNames
137695
- );
137740
+ let sourcePath;
137741
+ if (isObjectRecord2(variable2.pointer) && variable2.pointer.type !== "value" && variable2.sourcePath.includes(".@getter:") || variable2.sourcePath.startsWith(`ref:${PENDING_ID_PREFIX}`) || variable2.sourcePath.startsWith(`linked:${PENDING_ID_PREFIX}`)) {
137742
+ pointerResolver ??= {
137743
+ primaryAlias,
137744
+ bindingNameByValueId: {
137745
+ get: (valueId) => (nodeBindings.get(valueId) ?? context.bindings.get(valueId))?.name
137746
+ },
137747
+ memberNameById: context.memberNames,
137748
+ staticMemberExpressionById: context.staticMemberExpressions,
137749
+ enumOptionNameById: context.enumOptionNames
137750
+ };
137751
+ sourcePath = pointerSource2(variable2.pointer, pointerResolver);
137752
+ } else {
137753
+ sourcePath = authoredVariablePath(
137754
+ variable2.sourcePath,
137755
+ nodeBindings,
137756
+ context.bindings
137757
+ );
137758
+ }
137696
137759
  if (sourcePath === null) {
137697
137760
  pieces.push(`{MissingVariable(${quote5(variableId)})}`);
137698
137761
  cursor = pattern.lastIndex;
@@ -137737,27 +137800,14 @@ function recoverableProse(context, textId, rawVariables, owner, nodeBindings, pr
137737
137800
  return { source: recoveryProse(reason), reason };
137738
137801
  }
137739
137802
  }
137740
- function authoredVariablePath(sourcePath, nodeBindings, dialogueBindings, memberNames) {
137803
+ function authoredVariablePath(sourcePath, nodeBindings, dialogueBindings) {
137741
137804
  const persisted = PERSISTED_VARIABLE_PATH.exec(sourcePath);
137742
137805
  const lexicalPath = persisted ? (() => {
137743
137806
  const valueId = persisted[1];
137744
137807
  const binding = nodeBindings.get(valueId) ?? dialogueBindings.get(valueId);
137745
137808
  return binding ? `${binding.name}${persisted[2] ?? ""}` : null;
137746
137809
  })() : sourcePath;
137747
- if (lexicalPath === null) return null;
137748
- let missingMember = false;
137749
- const authored = lexicalPath.replace(
137750
- /\.@getter:([^.]+)/gu,
137751
- (_match, memberId) => {
137752
- const memberName = memberNames.get(memberId);
137753
- if (memberName === void 0) {
137754
- missingMember = true;
137755
- return "";
137756
- }
137757
- return `.${memberName}`;
137758
- }
137759
- );
137760
- return missingMember ? null : authored;
137810
+ return lexicalPath;
137761
137811
  }
137762
137812
  function recoveryProse(reason) {
137763
137813
  return `"""
@@ -138123,6 +138173,8 @@ var PERSISTED_VARIABLE_PATH, DIALOGUE_SYSTEM_TYPE_NAMES, ValuePlacementIndex, Un
138123
138173
  var init_dialogue_sources = __esm({
138124
138174
  "src/project-source/dialogue-sources.ts"() {
138125
138175
  "use strict";
138176
+ init_pending_id();
138177
+ init_ui_action_source();
138126
138178
  init_generated_csharp_identifiers();
138127
138179
  init_dialogue_group_symbols();
138128
138180
  init_language_spec();
@@ -191439,7 +191491,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
191439
191491
  async function main() {
191440
191492
  const args = parseArgs(process.argv.slice(2));
191441
191493
  if (args.command === "--version") {
191442
- console.log("0.73.1");
191494
+ console.log("0.73.2");
191443
191495
  return;
191444
191496
  }
191445
191497
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
@@ -55288,7 +55288,7 @@ var SPECIALIZED_RELATION_KINDS = /* @__PURE__ */ new Set([
55288
55288
 
55289
55289
  // ../packages/manifest/schema-contract/registry.mjs
55290
55290
  var PROJECT_SCHEMA_CONTRACT = Object.freeze({
55291
- cliVersion: "0.73.1",
55291
+ cliVersion: "0.73.2",
55292
55292
  projectFileUploadBatchSize: 32,
55293
55293
  documentRecords: {
55294
55294
  member: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.73.1",
3
+ "version": "0.73.2",
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.73.1 -->
12
+ <!-- reviewed-through-cli: 0.73.2 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -118,7 +118,7 @@ wrappers.
118
118
  The marker near the top of `SKILL.md` must exactly match the package version:
119
119
 
120
120
  ```html
121
- <!-- reviewed-through-cli: 0.73.1 -->
121
+ <!-- reviewed-through-cli: 0.73.2 -->
122
122
  ```
123
123
 
124
124
  The quoted version above is checked too, so this instruction cannot go stale
@@ -440,3 +440,9 @@ Populated unordered member defaults, such as `@settings(kind: .Unordered)` with
440
440
  `List<Entry> Entries = [new Entry()]`, are constructed by an initializer for
441
441
  each instance. A declaration has no container value row to own unordered entries.
442
442
  Nested unordered lists already have container rows and retain their stored values.
443
+
444
+ A lookup's declared class must be assignable to the entry class of its
445
+ `@settings(collection: Owner.Member)` collection. A subclass may narrow the
446
+ selection. Constructor arguments and member initializers must select compatible
447
+ targets too. An `NPC` lookup cannot select from `List<Quest>`, even when its
448
+ initializer is typed `NPC`; status reports the conflicting collection annotation.
@@ -283,3 +283,7 @@ Pull/push compare server-verified SHA-256, not storage ETags. A divergent
283
283
  binary keeps local bytes and writes the verified remote side under
284
284
  `.neo/conflicts/files/<file-id>/`. A retained declaration with a missing binary
285
285
  is an error; remove the declaration to request deletion.
286
+
287
+ New schema getters referenced by NeoFlow interpolation need no `@id`. Export and
288
+ `neo dev` assign the same identity to the declaration and its references, including
289
+ inherited getters. Repeated exports and the next push reuse the export identity ledger.