@neocompose/cli 0.36.7 → 0.36.9

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,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.36.9] - 2026-08-20
4
+
5
+ ### Fixed
6
+
7
+ - Preserve shared aggregate constructor arguments as value references during
8
+ canonical pull emission, preventing web-created placements from duplicating
9
+ catalog rows or reporting false value-containment cycles.
10
+
11
+ ## [0.36.8] - 2026-08-20
12
+
13
+ ### Fixed
14
+
15
+ - Ignore server-compiled initializer IR when deciding whether both sides of a
16
+ pull changed authored value source, preventing compiler-only refreshes from
17
+ producing false conflicts.
18
+ - Let `neo resolve --mine` and `neo resolve --theirs` clear metadata-only
19
+ record conflicts retained by older pulls even when no textual marker was
20
+ written.
21
+
3
22
  ## [0.36.7] - 2026-08-20
4
23
 
5
24
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -45228,6 +45228,21 @@ function findSchemaPlacement(memberId, classes) {
45228
45228
  }
45229
45229
  return null;
45230
45230
  }
45231
+ function findNearestAncestorSchemaPlacement(ownerClass, schemaKey, classesById) {
45232
+ const visited = /* @__PURE__ */ new Set([ownerClass.id]);
45233
+ let ancestorId = ownerClass.extendsClassId;
45234
+ while (typeof ancestorId === "string") {
45235
+ if (visited.has(ancestorId)) return null;
45236
+ visited.add(ancestorId);
45237
+ const ancestor = classesById.get(ancestorId);
45238
+ if (ancestor === void 0) return null;
45239
+ if (typeof ancestor.schema[schemaKey] === "string") {
45240
+ return { ownerClass: ancestor, schemaKey };
45241
+ }
45242
+ ancestorId = ancestor.extendsClassId;
45243
+ }
45244
+ return null;
45245
+ }
45231
45246
  function walkExtendsMemberChain(startId, members, pick, options) {
45232
45247
  const requireKind = options?.requireKind;
45233
45248
  const maxHops = options?.maxHops ?? 16;
@@ -57224,6 +57239,104 @@ var init_dialogue_sources = __esm({
57224
57239
  }
57225
57240
  });
57226
57241
 
57242
+ // ../src/models/variants/variants.ts
57243
+ function isNonEmptyString2(value) {
57244
+ if (typeof value !== "string") return false;
57245
+ return value.length > 0;
57246
+ }
57247
+ function isNeoClassVariant(value) {
57248
+ if (typeof value !== "object" || value === null) return false;
57249
+ if (Array.isArray(value)) return false;
57250
+ const v = value;
57251
+ if (!isNonEmptyString2(v.id)) return false;
57252
+ if (!isNonEmptyString2(v.classId)) return false;
57253
+ if (!isNonEmptyString2(v.name)) return false;
57254
+ if (!isNonEmptyString2(v.valueId)) return false;
57255
+ if (v.folderId !== null && !isNonEmptyString2(v.folderId)) return false;
57256
+ return true;
57257
+ }
57258
+ function isNeoClassVariantFolder(value) {
57259
+ if (typeof value !== "object" || value === null) return false;
57260
+ if (Array.isArray(value)) return false;
57261
+ const v = value;
57262
+ if (!isNonEmptyString2(v.id)) return false;
57263
+ if (!isNonEmptyString2(v.classId)) return false;
57264
+ if (typeof v.path !== "string") return false;
57265
+ if (v.binding === void 0 || v.binding === null) return v.path.length > 0;
57266
+ if (typeof v.binding !== "object" || Array.isArray(v.binding)) return false;
57267
+ const binding = v.binding;
57268
+ if (!isNonEmptyString2(binding.collectionMemberId)) return false;
57269
+ if (!isNonEmptyString2(binding.collectionValueId)) return false;
57270
+ return true;
57271
+ }
57272
+ var NEO_VARIANT_INITIALIZE_SCHEMA_KEY, NEO_VARIANT_APPLY_SCHEMA_KEY, NEO_VARIANT_OVERRIDES_SCHEMA_KEY, NEO_VARIANT_CHILD_OVERRIDES_SCHEMA_KEY;
57273
+ var init_variants = __esm({
57274
+ "../src/models/variants/variants.ts"() {
57275
+ "use strict";
57276
+ NEO_VARIANT_INITIALIZE_SCHEMA_KEY = "Initialize";
57277
+ NEO_VARIANT_APPLY_SCHEMA_KEY = "Apply";
57278
+ NEO_VARIANT_OVERRIDES_SCHEMA_KEY = "Overrides";
57279
+ NEO_VARIANT_CHILD_OVERRIDES_SCHEMA_KEY = "ChildOverrides";
57280
+ }
57281
+ });
57282
+
57283
+ // ../src/models/variants/variant-member.ts
57284
+ function neoVariantSystemClass(classes, lookup = false) {
57285
+ const declared = classes.find(
57286
+ (item) => item.system?.worldKind === (lookup ? NeoWorldSystemClassKind.LookupVariant : NeoWorldSystemClassKind.Variant)
57287
+ );
57288
+ if (declared === void 0) return null;
57289
+ const targetParamId = declared.genericParams?.[0]?.id;
57290
+ if (targetParamId === void 0) return null;
57291
+ const valueParamId = declared.genericParams?.[1]?.id;
57292
+ return {
57293
+ classId: declared.id,
57294
+ targetParamId,
57295
+ ...valueParamId === void 0 ? {} : { valueParamId }
57296
+ };
57297
+ }
57298
+ var init_variant_member = __esm({
57299
+ "../src/models/variants/variant-member.ts"() {
57300
+ "use strict";
57301
+ init_core();
57302
+ init_member_kind_enum();
57303
+ }
57304
+ });
57305
+
57306
+ // ../src/models/variants/variant-naming.ts
57307
+ var init_variant_naming = __esm({
57308
+ "../src/models/variants/variant-naming.ts"() {
57309
+ "use strict";
57310
+ }
57311
+ });
57312
+
57313
+ // ../src/models/variants/variant-write.ts
57314
+ var init_variant_write = __esm({
57315
+ "../src/models/variants/variant-write.ts"() {
57316
+ "use strict";
57317
+ }
57318
+ });
57319
+
57320
+ // ../src/models/variants/variant-initialize-source.ts
57321
+ var init_variant_initialize_source = __esm({
57322
+ "../src/models/variants/variant-initialize-source.ts"() {
57323
+ "use strict";
57324
+ init_member_kind_enum();
57325
+ }
57326
+ });
57327
+
57328
+ // ../src/models/variants/index.ts
57329
+ var init_variants2 = __esm({
57330
+ "../src/models/variants/index.ts"() {
57331
+ "use strict";
57332
+ init_variants();
57333
+ init_variant_member();
57334
+ init_variant_naming();
57335
+ init_variant_write();
57336
+ init_variant_initialize_source();
57337
+ }
57338
+ });
57339
+
57227
57340
  // src/project-source/lower-support.ts
57228
57341
  function identityMap(declarations, kind) {
57229
57342
  return new Map(
@@ -61184,99 +61297,6 @@ var init_member_value_id = __esm({
61184
61297
  }
61185
61298
  });
61186
61299
 
61187
- // ../src/models/variants/variants.ts
61188
- function isNonEmptyString2(value) {
61189
- if (typeof value !== "string") return false;
61190
- return value.length > 0;
61191
- }
61192
- function isNeoClassVariant(value) {
61193
- if (typeof value !== "object" || value === null) return false;
61194
- if (Array.isArray(value)) return false;
61195
- const v = value;
61196
- if (!isNonEmptyString2(v.id)) return false;
61197
- if (!isNonEmptyString2(v.classId)) return false;
61198
- if (!isNonEmptyString2(v.name)) return false;
61199
- if (!isNonEmptyString2(v.valueId)) return false;
61200
- if (v.folderId !== null && !isNonEmptyString2(v.folderId)) return false;
61201
- return true;
61202
- }
61203
- function isNeoClassVariantFolder(value) {
61204
- if (typeof value !== "object" || value === null) return false;
61205
- if (Array.isArray(value)) return false;
61206
- const v = value;
61207
- if (!isNonEmptyString2(v.id)) return false;
61208
- if (!isNonEmptyString2(v.classId)) return false;
61209
- if (typeof v.path !== "string") return false;
61210
- if (v.binding === void 0 || v.binding === null) return v.path.length > 0;
61211
- if (typeof v.binding !== "object" || Array.isArray(v.binding)) return false;
61212
- const binding = v.binding;
61213
- if (!isNonEmptyString2(binding.collectionMemberId)) return false;
61214
- if (!isNonEmptyString2(binding.collectionValueId)) return false;
61215
- return true;
61216
- }
61217
- var init_variants = __esm({
61218
- "../src/models/variants/variants.ts"() {
61219
- "use strict";
61220
- }
61221
- });
61222
-
61223
- // ../src/models/variants/variant-member.ts
61224
- function neoVariantSystemClass(classes, lookup = false) {
61225
- const declared = classes.find(
61226
- (item) => item.system?.worldKind === (lookup ? NeoWorldSystemClassKind.LookupVariant : NeoWorldSystemClassKind.Variant)
61227
- );
61228
- if (declared === void 0) return null;
61229
- const targetParamId = declared.genericParams?.[0]?.id;
61230
- if (targetParamId === void 0) return null;
61231
- const valueParamId = declared.genericParams?.[1]?.id;
61232
- return {
61233
- classId: declared.id,
61234
- targetParamId,
61235
- ...valueParamId === void 0 ? {} : { valueParamId }
61236
- };
61237
- }
61238
- var init_variant_member = __esm({
61239
- "../src/models/variants/variant-member.ts"() {
61240
- "use strict";
61241
- init_core();
61242
- init_member_kind_enum();
61243
- }
61244
- });
61245
-
61246
- // ../src/models/variants/variant-naming.ts
61247
- var init_variant_naming = __esm({
61248
- "../src/models/variants/variant-naming.ts"() {
61249
- "use strict";
61250
- }
61251
- });
61252
-
61253
- // ../src/models/variants/variant-write.ts
61254
- var init_variant_write = __esm({
61255
- "../src/models/variants/variant-write.ts"() {
61256
- "use strict";
61257
- }
61258
- });
61259
-
61260
- // ../src/models/variants/variant-initialize-source.ts
61261
- var init_variant_initialize_source = __esm({
61262
- "../src/models/variants/variant-initialize-source.ts"() {
61263
- "use strict";
61264
- init_member_kind_enum();
61265
- }
61266
- });
61267
-
61268
- // ../src/models/variants/index.ts
61269
- var init_variants2 = __esm({
61270
- "../src/models/variants/index.ts"() {
61271
- "use strict";
61272
- init_variants();
61273
- init_variant_member();
61274
- init_variant_naming();
61275
- init_variant_write();
61276
- init_variant_initialize_source();
61277
- }
61278
- });
61279
-
61280
61300
  // ../src/models/project/project-root-members.ts
61281
61301
  function buildRootStorageMap(project) {
61282
61302
  const map = /* @__PURE__ */ new Map();
@@ -76389,6 +76409,23 @@ var init_workspace = __esm({
76389
76409
  }
76390
76410
  });
76391
76411
 
76412
+ // src/project-sync/value-record-comparison.ts
76413
+ function valueRecordComparisonBody(value) {
76414
+ if (!isObjectRecord2(value)) return value;
76415
+ const init = value.init;
76416
+ const body = value.value;
76417
+ const normalizedInit = isObjectRecord2(init) && init.compiled !== void 0 ? { ...init, compiled: void 0 } : init;
76418
+ const normalizedBody = isObjectRecord2(body) && typeof body.code === "string" && body.action !== void 0 ? { ...body, action: void 0 } : body;
76419
+ if (normalizedInit === init && normalizedBody === body) return value;
76420
+ return { ...value, init: normalizedInit, value: normalizedBody };
76421
+ }
76422
+ var init_value_record_comparison = __esm({
76423
+ "src/project-sync/value-record-comparison.ts"() {
76424
+ "use strict";
76425
+ init_projection();
76426
+ }
76427
+ });
76428
+
76392
76429
  // src/project-source/lower-configuration.ts
76393
76430
  function lowerConfiguration(base, analysis) {
76394
76431
  const globals = analysis.configuration.globals;
@@ -89747,6 +89784,97 @@ var init_localizable_member_value_writes = __esm({
89747
89784
  });
89748
89785
 
89749
89786
  // ../src/database/project-version-schema-commit.ts
89787
+ function indexRecordsById(records2) {
89788
+ const recordsById2 = /* @__PURE__ */ new Map();
89789
+ for (const record3 of records2) recordsById2.set(record3.id, record3);
89790
+ return recordsById2;
89791
+ }
89792
+ function indexLiveContentHashesByRecordId(heads, recordKind) {
89793
+ const hashes = /* @__PURE__ */ new Map();
89794
+ for (const head of heads) {
89795
+ if (head.recordKind !== recordKind || head.deleted) continue;
89796
+ hashes.set(head.recordId, head.contentHash);
89797
+ }
89798
+ return hashes;
89799
+ }
89800
+ function indexLiveContentHashesByRecordKey(heads) {
89801
+ const hashes = /* @__PURE__ */ new Map();
89802
+ for (const head of heads) {
89803
+ if (head.deleted) continue;
89804
+ hashes.set(`${head.recordKind}:${head.recordId}`, head.contentHash);
89805
+ }
89806
+ return hashes;
89807
+ }
89808
+ function indexChangesByRecordId(changes, recordKind) {
89809
+ const indexes = /* @__PURE__ */ new Map();
89810
+ for (let index = 0; index < changes.length; index += 1) {
89811
+ const change = changes[index];
89812
+ if (change?.recordKind === recordKind) indexes.set(change.recordId, index);
89813
+ }
89814
+ return indexes;
89815
+ }
89816
+ function reconcileDirectOverrideChains(args) {
89817
+ if (!args.changes.some(
89818
+ (change) => change.recordKind === "class" || change.recordKind === "member"
89819
+ )) {
89820
+ return;
89821
+ }
89822
+ const postDocument = applyProjectVersionWriteChanges(
89823
+ args.document,
89824
+ args.changes
89825
+ );
89826
+ const postClassesById = indexRecordsById(postDocument.classes);
89827
+ const postMembersById = indexRecordsById(postDocument.members);
89828
+ const changeIndexByMemberId = indexChangesByRecordId(args.changes, "member");
89829
+ let baseHashByMemberId = null;
89830
+ for (const schemaClass2 of postDocument.classes) {
89831
+ for (const [schemaKey, memberId] of Object.entries(schemaClass2.schema)) {
89832
+ const member = postMembersById.get(memberId);
89833
+ if (member === void 0 || typeof member.extendsMemberId !== "string") {
89834
+ continue;
89835
+ }
89836
+ const expectedPlacement = findNearestAncestorSchemaPlacement(
89837
+ schemaClass2,
89838
+ schemaKey,
89839
+ postClassesById
89840
+ );
89841
+ const expected = expectedPlacement?.ownerClass.schema[expectedPlacement.schemaKey];
89842
+ if (expected === member.extendsMemberId) continue;
89843
+ if (typeof expected !== "string") continue;
89844
+ const nextMember = { ...member, extendsMemberId: expected };
89845
+ postMembersById.set(member.id, nextMember);
89846
+ const existingIndex = changeIndexByMemberId.get(member.id);
89847
+ if (existingIndex !== void 0) {
89848
+ const existing = args.changes[existingIndex];
89849
+ if (existing !== void 0) {
89850
+ args.changes[existingIndex] = { ...existing, nextData: nextMember };
89851
+ }
89852
+ continue;
89853
+ }
89854
+ baseHashByMemberId ??= indexLiveContentHashesByRecordId(
89855
+ args.contentHashHeads,
89856
+ "member"
89857
+ );
89858
+ const expectedBaseContentHash = baseHashByMemberId.get(member.id);
89859
+ if (expectedBaseContentHash === void 0) {
89860
+ throw new Error(
89861
+ `Cannot safely repair override chain for member "${member.name}" (${member.id}): its current content hash is unavailable.`
89862
+ );
89863
+ }
89864
+ changeIndexByMemberId.set(member.id, args.changes.length);
89865
+ args.changes.push({
89866
+ recordKind: "member",
89867
+ recordId: member.id,
89868
+ operation: "update",
89869
+ nextData: nextMember,
89870
+ expectedBaseContentHash,
89871
+ intent: createProjectVersionIntent("member.update", {
89872
+ source: "server-direct-override-chain-reconcile"
89873
+ })
89874
+ });
89875
+ }
89876
+ }
89877
+ }
89750
89878
  function prepareServerOwnedSchemaCommit(args) {
89751
89879
  if (args.forceRecompile === true) clearNeoScriptBodyCompileCache();
89752
89880
  assertUniqueChanges(args.changes);
@@ -89767,6 +89895,18 @@ function prepareServerOwnedSchemaCommit(args) {
89767
89895
  ),
89768
89896
  changes: authoredChanges
89769
89897
  });
89898
+ const explicitlyChangedMemberIds = /* @__PURE__ */ new Set();
89899
+ for (const change of authoredChanges) {
89900
+ if (change.recordKind !== "member" || change.operation === "delete") {
89901
+ continue;
89902
+ }
89903
+ explicitlyChangedMemberIds.add(change.recordId);
89904
+ }
89905
+ reconcileDirectOverrideChains({
89906
+ document: args.document,
89907
+ changes: authoredChanges,
89908
+ contentHashHeads: args.contentHashHeads
89909
+ });
89770
89910
  assertNoLegacyWorldLayerBindingFields(authoredChanges);
89771
89911
  const hasSchemaChange = authoredChanges.some(
89772
89912
  (change) => SCHEMA_RECORD_KINDS.has(change.recordKind)
@@ -89795,11 +89935,6 @@ function prepareServerOwnedSchemaCommit(args) {
89795
89935
  additionalImpactedIds: args.additionalImpactedIds,
89796
89936
  forceRecompile: args.forceRecompile
89797
89937
  });
89798
- const explicitlyChangedMemberIds = new Set(
89799
- authoredChanges.filter(
89800
- (change) => change.recordKind === "member" && change.operation !== "delete"
89801
- ).map((change) => change.recordId)
89802
- );
89803
89938
  const currentById = new Map(
89804
89939
  args.document.members.map((member) => [member.id, member])
89805
89940
  );
@@ -89858,9 +89993,12 @@ function prepareServerOwnedSchemaCommit(args) {
89858
89993
  const compiledById = new Map(
89859
89994
  sourceMembers.map((member) => [member.id, member])
89860
89995
  );
89861
- const explicitMemberIds = new Set(
89862
- authoredChanges.filter((change) => change.recordKind === "member").map((change) => change.recordId)
89863
- );
89996
+ const explicitMemberIds = /* @__PURE__ */ new Set();
89997
+ for (const change of authoredChanges) {
89998
+ if (change.recordKind === "member") {
89999
+ explicitMemberIds.add(change.recordId);
90000
+ }
90001
+ }
89864
90002
  const prepared = authoredChanges.map((change) => {
89865
90003
  if (change.recordKind !== "member" || change.operation === "delete") {
89866
90004
  return change;
@@ -89873,9 +90011,7 @@ function prepareServerOwnedSchemaCommit(args) {
89873
90011
  }
89874
90012
  return { ...change, nextData: compiled };
89875
90013
  });
89876
- const hashByKey = new Map(
89877
- args.contentHashHeads.filter((head) => !head.deleted).map((head) => [`${head.recordKind}:${head.recordId}`, head.contentHash])
89878
- );
90014
+ const hashByKey = indexLiveContentHashesByRecordKey(args.contentHashHeads);
89879
90015
  for (const compiled of sourceMembers) {
89880
90016
  if (!recompileTargets.memberIds.has(compiled.id)) continue;
89881
90017
  if (explicitMemberIds.has(compiled.id)) continue;
@@ -93192,32 +93328,17 @@ function reconcileVariantConstructorArgs(args) {
93192
93328
  );
93193
93329
  const variants = postDocument.variants ?? [];
93194
93330
  if (variants.length === 0) return;
93195
- const valueById = new Map(
93196
- postDocument.values.map((value) => [value.id, value])
93197
- );
93198
- const classById = new Map(
93199
- postDocument.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
93200
- );
93201
- const memberById = new Map(
93202
- postDocument.members.map((member) => [member.id, member])
93203
- );
93204
- const constructorById = new Map(
93205
- (postDocument.constructors ?? []).map((record3) => [record3.id, record3])
93206
- );
93207
- const changeIndexByValueId = /* @__PURE__ */ new Map();
93208
- args.prepared.forEach((change, index) => {
93209
- if (change.recordKind !== "value") return;
93210
- changeIndexByValueId.set(change.recordId, index);
93211
- });
93212
- const baseHashByValueId = new Map(
93213
- args.contentHashHeads.filter((head) => head.recordKind === "value" && !head.deleted).map((head) => [head.recordId, head.contentHash])
93214
- );
93331
+ const valueById = indexRecordsById(postDocument.values);
93332
+ const classById = indexRecordsById(postDocument.classes);
93333
+ const memberById = indexRecordsById(postDocument.members);
93334
+ const constructorById = indexRecordsById(postDocument.constructors ?? []);
93335
+ const changeIndexByValueId = indexChangesByRecordId(args.prepared, "value");
93336
+ let baseHashByValueId = null;
93215
93337
  for (const variant of variants) {
93216
93338
  const root = valueById.get(variant.valueId);
93217
93339
  if (root === void 0) continue;
93218
93340
  if (!isLiteralValueContent(root)) continue;
93219
- const existingArgs = root.constructorArgs;
93220
- if (existingArgs === void 0 || existingArgs === null) continue;
93341
+ const existingArgs = root.constructorArgs ?? {};
93221
93342
  const rootClassId = root.classId;
93222
93343
  if (typeof rootClassId !== "string") continue;
93223
93344
  const schemaClass2 = classById.get(rootClassId);
@@ -93228,37 +93349,46 @@ function reconcileVariantConstructorArgs(args) {
93228
93349
  if (constructorRecord === void 0) continue;
93229
93350
  if (typeof root.value !== "object" || root.value === null) continue;
93230
93351
  if (Array.isArray(root.value)) continue;
93231
- const nextArgs = { ...existingArgs };
93232
- let changed = false;
93233
- constructorRecord.argumentTypes.forEach((argument2, index) => {
93352
+ const nextArgs = {};
93353
+ for (let index = 0; index < constructorRecord.argumentTypes.length; index += 1) {
93354
+ const argument2 = constructorRecord.argumentTypes[index];
93355
+ if (argument2 === void 0) continue;
93234
93356
  const parameterId = constructorActionParameterId(
93235
93357
  constructorRecord,
93236
93358
  index
93237
93359
  );
93238
- if (!(parameterId in nextArgs)) return;
93239
- const schemaKey = Object.keys(schemaClass2.schema).find(
93240
- (key) => key.toLowerCase() === argument2.name.toLowerCase()
93360
+ const schemaKey = NEO_VARIANT_SCHEMA_KEY_BY_ARGUMENT_NAME.get(
93361
+ argument2.name.toLowerCase()
93241
93362
  );
93242
- if (schemaKey === void 0) return;
93363
+ if (schemaKey === void 0) continue;
93243
93364
  const memberId = schemaClass2.schema[schemaKey];
93244
93365
  const member = memberId === void 0 ? void 0 : memberById.get(memberId);
93245
- if (member?.kind !== 25 /* NSDelegate */) return;
93366
+ if (member === void 0) continue;
93246
93367
  const childId = root.value[schemaKey];
93247
- if (typeof childId !== "string") return;
93368
+ if (typeof childId !== "string") continue;
93248
93369
  const childRow = valueById.get(childId);
93249
- if (childRow === void 0 || !isLiteralValueContent(childRow)) return;
93370
+ if (childRow === void 0 || !isLiteralValueContent(childRow)) continue;
93250
93371
  const rowValue = childRow.value;
93251
- if (typeof rowValue !== "object" || rowValue === null) return;
93252
- if (Array.isArray(rowValue)) return;
93253
- const rowCode = rowValue.code;
93254
- if (typeof rowCode !== "string") return;
93255
- const derived = { code: rowCode };
93256
- if (canonicalJsonStringify(nextArgs[parameterId]) === canonicalJsonStringify(derived)) {
93257
- return;
93372
+ if (variantConstructorArgumentIsRestValue(schemaKey, rowValue)) {
93373
+ continue;
93258
93374
  }
93259
- nextArgs[parameterId] = derived;
93260
- changed = true;
93261
- });
93375
+ if (member.kind === 25 /* NSDelegate */) {
93376
+ if (typeof rowValue !== "object" || rowValue === null) continue;
93377
+ if (Array.isArray(rowValue)) continue;
93378
+ const rowCode = rowValue.code;
93379
+ if (typeof rowCode !== "string") continue;
93380
+ nextArgs[parameterId] = { code: rowCode };
93381
+ continue;
93382
+ }
93383
+ if (member.kind === 7 /* Class */ || member.kind === 22 /* Interface */ || member.kind === 21 /* Generic */ || member.kind === 6 /* List */ || member.kind === 5 /* Dictionary */) {
93384
+ nextArgs[parameterId] = childId;
93385
+ continue;
93386
+ }
93387
+ const defaultValue = argument2.defaultValue?.value;
93388
+ if (canonicallyEqual2(rowValue, defaultValue)) continue;
93389
+ nextArgs[parameterId] = rowValue;
93390
+ }
93391
+ const changed = !canonicallyEqual2(existingArgs, nextArgs);
93262
93392
  if (!changed) continue;
93263
93393
  const nextRoot = { ...root, constructorArgs: nextArgs };
93264
93394
  const existingIndex = changeIndexByValueId.get(root.id);
@@ -93269,8 +93399,13 @@ function reconcileVariantConstructorArgs(args) {
93269
93399
  }
93270
93400
  continue;
93271
93401
  }
93402
+ baseHashByValueId ??= indexLiveContentHashesByRecordId(
93403
+ args.contentHashHeads,
93404
+ "value"
93405
+ );
93272
93406
  const baseContentHash = baseHashByValueId.get(root.id);
93273
93407
  if (baseContentHash === void 0) continue;
93408
+ changeIndexByValueId.set(root.id, args.prepared.length);
93274
93409
  args.prepared.push({
93275
93410
  recordKind: "value",
93276
93411
  recordId: root.id,
@@ -93283,6 +93418,13 @@ function reconcileVariantConstructorArgs(args) {
93283
93418
  });
93284
93419
  }
93285
93420
  }
93421
+ function variantConstructorArgumentIsRestValue(schemaKey, value) {
93422
+ if (value === null) return true;
93423
+ if (schemaKey === NEO_VARIANT_OVERRIDES_SCHEMA_KEY) {
93424
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0;
93425
+ }
93426
+ return schemaKey === NEO_VARIANT_CHILD_OVERRIDES_SCHEMA_KEY && Array.isArray(value) && value.length === 0;
93427
+ }
93286
93428
  function appendVariantGraphCascadeDeletes(args) {
93287
93429
  const deletedVariantIds = /* @__PURE__ */ new Set();
93288
93430
  for (const change of args.prepared) {
@@ -93296,11 +93438,13 @@ function appendVariantGraphCascadeDeletes(args) {
93296
93438
  variants: args.document.variants ?? [],
93297
93439
  variantIds: deletedVariantIds
93298
93440
  });
93299
- const alreadyChanged = new Set(
93300
- args.prepared.filter((change) => change.recordKind === "value").map((change) => change.recordId)
93301
- );
93302
- const baseHashByValueId = new Map(
93303
- args.contentHashHeads.filter((head) => head.recordKind === "value").map((head) => [head.recordId, head.contentHash])
93441
+ const alreadyChanged = /* @__PURE__ */ new Set();
93442
+ for (const change of args.prepared) {
93443
+ if (change.recordKind === "value") alreadyChanged.add(change.recordId);
93444
+ }
93445
+ const baseHashByValueId = indexLiveContentHashesByRecordId(
93446
+ args.contentHashHeads,
93447
+ "value"
93304
93448
  );
93305
93449
  for (const valueId of valueIds) {
93306
93450
  if (alreadyChanged.has(valueId)) continue;
@@ -93322,7 +93466,7 @@ function appendVariantGraphCascadeDeletes(args) {
93322
93466
  });
93323
93467
  }
93324
93468
  }
93325
- var SERVER_COMPILATION_PROJECT_CACHE_LIMIT, serverCompilationProjectCache, READ_ONLY_SOURCE_CONVERSION_INTENT_SOURCE, SCHEMA_RECORD_KINDS, DIALOGUE_SOURCE_RECORD_KINDS;
93469
+ var SERVER_COMPILATION_PROJECT_CACHE_LIMIT, serverCompilationProjectCache, READ_ONLY_SOURCE_CONVERSION_INTENT_SOURCE, SCHEMA_RECORD_KINDS, DIALOGUE_SOURCE_RECORD_KINDS, NEO_VARIANT_SCHEMA_KEY_BY_ARGUMENT_NAME;
93326
93470
  var init_project_version_schema_commit = __esm({
93327
93471
  "../src/database/project-version-schema-commit.ts"() {
93328
93472
  "use strict";
@@ -93335,6 +93479,7 @@ var init_project_version_schema_commit = __esm({
93335
93479
  init_project2();
93336
93480
  init_member_access_modifier_validation();
93337
93481
  init_variant_value_graph();
93482
+ init_variants2();
93338
93483
  init_localization2();
93339
93484
  init_internal_record_relations();
93340
93485
  init_project_content_hash();
@@ -93376,6 +93521,12 @@ var init_project_version_schema_commit = __esm({
93376
93521
  "dialogue-node",
93377
93522
  "dialogue-group"
93378
93523
  ]);
93524
+ NEO_VARIANT_SCHEMA_KEY_BY_ARGUMENT_NAME = /* @__PURE__ */ new Map([
93525
+ ["initialize", NEO_VARIANT_INITIALIZE_SCHEMA_KEY],
93526
+ ["apply", NEO_VARIANT_APPLY_SCHEMA_KEY],
93527
+ ["overrides", NEO_VARIANT_OVERRIDES_SCHEMA_KEY],
93528
+ ["childoverrides", NEO_VARIANT_CHILD_OVERRIDES_SCHEMA_KEY]
93529
+ ]);
93379
93530
  }
93380
93531
  });
93381
93532
 
@@ -96308,15 +96459,6 @@ function recordsSemanticallyEqual(recordKind, left, right) {
96308
96459
  }
96309
96460
  return canonicallyEqual(left, right);
96310
96461
  }
96311
- function valueRecordComparisonBody(value) {
96312
- if (!isObjectRecord2(value)) return value;
96313
- const init = value.init;
96314
- const body = value.value;
96315
- const normalizedInit = isObjectRecord2(init) && init.compiled !== void 0 ? { ...init, compiled: void 0 } : init;
96316
- const normalizedBody = isObjectRecord2(body) && typeof body.code === "string" && body.action !== void 0 ? { ...body, action: void 0 } : body;
96317
- if (normalizedInit === init && normalizedBody === body) return value;
96318
- return { ...value, init: normalizedInit, value: normalizedBody };
96319
- }
96320
96462
  function describeChange(change) {
96321
96463
  const name = isObjectRecord2(change.nextData) && typeof change.nextData.name === "string" ? change.nextData.name : isObjectRecord2(change.baseData) && typeof change.baseData.name === "string" ? change.baseData.name : change.recordId;
96322
96464
  const location3 = change.file === null ? "" : ` (${change.file})`;
@@ -96347,6 +96489,7 @@ var init_workspace_status_core = __esm({
96347
96489
  init_source_diagnostics();
96348
96490
  init_migration_files();
96349
96491
  init_projection();
96492
+ init_value_record_comparison();
96350
96493
  init_project_manifest();
96351
96494
  init_src();
96352
96495
  init_lower_schema();
@@ -97817,15 +97960,15 @@ function emitVariantValueSourcesV4(records2, manifest) {
97817
97960
  visited
97818
97961
  });
97819
97962
  };
97820
- const initialize = argument2("Initialize");
97963
+ const initialize = argument2(NEO_VARIANT_INITIALIZE_SCHEMA_KEY);
97821
97964
  if (initialize === null) {
97822
97965
  throw new Error(
97823
97966
  `Variant "${variant.id}" has no Initialize row; every variant constructs a fresh instance.`
97824
97967
  );
97825
97968
  }
97826
- const apply = argument2("Apply");
97827
- const overrides = argument2("Overrides");
97828
- const childOverrides = argument2("ChildOverrides");
97969
+ const apply = argument2(NEO_VARIANT_APPLY_SCHEMA_KEY);
97970
+ const overrides = argument2(NEO_VARIANT_OVERRIDES_SCHEMA_KEY);
97971
+ const childOverrides = argument2(NEO_VARIANT_CHILD_OVERRIDES_SCHEMA_KEY);
97829
97972
  const authored = [["initialize", initialize]];
97830
97973
  if (apply !== null && apply !== "null") authored.push(["apply", apply]);
97831
97974
  if (overrides !== null && overrides !== "new {}") {
@@ -102878,6 +103021,12 @@ function storedConstructorCallSource(context, schemaClass2, value, className, en
102878
103021
  `Stored construction for ${className} is missing evaluated argument ${key}.`
102879
103022
  );
102880
103023
  }
103024
+ const settledMember = settledMemberForConstructorArgument(
103025
+ context,
103026
+ schemaClass2,
103027
+ value,
103028
+ constructorArgs[key]
103029
+ );
102881
103030
  return `${argument2.name}: ${storedConstructorArgumentSource(
102882
103031
  context,
102883
103032
  argument2.type,
@@ -102885,24 +103034,23 @@ function storedConstructorCallSource(context, schemaClass2, value, className, en
102885
103034
  environment,
102886
103035
  visited,
102887
103036
  cloneAggregateArguments,
102888
- settledMemberIsPartial(context, schemaClass2, value, constructorArgs[key])
103037
+ settledMember?.partial === true,
103038
+ settledMember !== void 0
102889
103039
  )}`;
102890
103040
  });
102891
103041
  return argumentsValue.length === 0 && targetTyped ? "new()" : constructorCallSource(`new ${className}`, argumentsValue);
102892
103042
  }
102893
- function settledMemberIsPartial(context, schemaClass2, value, argument2) {
102894
- if (typeof argument2 !== "string") return false;
103043
+ function settledMemberForConstructorArgument(context, schemaClass2, value, argument2) {
103044
+ if (typeof argument2 !== "string") return void 0;
102895
103045
  const body = value.value;
102896
- if (!isObjectRecord2(body)) return false;
103046
+ if (!isObjectRecord2(body)) return void 0;
102897
103047
  const schemaKey = Object.entries(body).find(
102898
103048
  ([, rowId]) => rowId === argument2
102899
103049
  )?.[0];
102900
- if (schemaKey === void 0) return false;
103050
+ if (schemaKey === void 0) return void 0;
102901
103051
  const schema = isObjectRecord2(schemaClass2.schema) ? schemaClass2.schema : {};
102902
103052
  const memberId = schema[schemaKey];
102903
- if (typeof memberId !== "string") return false;
102904
- const member = context.members.get(memberId);
102905
- return member?.partial === true;
103053
+ return typeof memberId === "string" ? context.members.get(memberId) : void 0;
102906
103054
  }
102907
103055
  function constructorCallSource(callee, argumentsValue) {
102908
103056
  const inline = `${callee}(${argumentsValue.join(", ")})`;
@@ -102941,7 +103089,7 @@ function storedValueConstructor(context, schemaClass2, constructorArgs) {
102941
103089
  }
102942
103090
  return selected;
102943
103091
  }
102944
- function storedConstructorArgumentSource(context, type, value, environment, visited, cloneAggregateArguments = false, partial = false) {
103092
+ function storedConstructorArgumentSource(context, type, value, environment, visited, cloneAggregateArguments = false, partial = false, constructorOwnsGraph = false) {
102945
103093
  if (value === null) {
102946
103094
  if (!type.nullable) {
102947
103095
  throw new Error("Required constructor argument stores null.");
@@ -103024,7 +103172,8 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
103024
103172
  environment,
103025
103173
  visited,
103026
103174
  false,
103027
- partial
103175
+ partial,
103176
+ constructorOwnsGraph
103028
103177
  );
103029
103178
  }
103030
103179
  case "generic": {
@@ -103048,7 +103197,8 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
103048
103197
  environment,
103049
103198
  visited,
103050
103199
  cloneAggregateArguments,
103051
- partial
103200
+ partial,
103201
+ constructorOwnsGraph
103052
103202
  );
103053
103203
  }
103054
103204
  case "interface":
@@ -103068,7 +103218,9 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
103068
103218
  value,
103069
103219
  environment,
103070
103220
  visited,
103071
- false
103221
+ false,
103222
+ false,
103223
+ constructorOwnsGraph
103072
103224
  );
103073
103225
  case "lookup":
103074
103226
  return referenceValue(
@@ -103342,7 +103494,7 @@ function storedSchemaTypeName(context, type, environment, valueId) {
103342
103494
  return "null";
103343
103495
  }
103344
103496
  }
103345
- function storedTypedRowSource(context, type, valueId, environment, visited, writeIdentity, partial = false) {
103497
+ function storedTypedRowSource(context, type, valueId, environment, visited, writeIdentity, partial = false, constructorOwnsGraph = false) {
103346
103498
  const symbol = context.symbolsByValueId.get(valueId);
103347
103499
  if (symbol !== void 0) return symbol;
103348
103500
  const row = context.values.get(valueId);
@@ -103351,6 +103503,9 @@ function storedTypedRowSource(context, type, valueId, environment, visited, writ
103351
103503
  `Stored ${type.kind} constructor argument references missing value row ${valueId}.`
103352
103504
  );
103353
103505
  }
103506
+ if (!constructorOwnsGraph && context.readMaterializedGraph().independentlyOwnedValueIds.has(valueId)) {
103507
+ return `Reference<${storedSchemaTypeName(context, type, environment, valueId)}>(id: ${quote5(valueId)})`;
103508
+ }
103354
103509
  if (visited.has(valueId)) {
103355
103510
  throw new Error(
103356
103511
  `Stored constructor argument containment cycle reaches ${valueId}.`
@@ -103401,7 +103556,9 @@ ${ids.map(
103401
103556
  id2,
103402
103557
  environment,
103403
103558
  visited,
103404
- true
103559
+ true,
103560
+ false,
103561
+ constructorOwnsGraph
103405
103562
  ),
103406
103563
  2
103407
103564
  )
@@ -103429,7 +103586,9 @@ ${entries.flatMap(
103429
103586
  id2,
103430
103587
  environment,
103431
103588
  visited,
103432
- false
103589
+ false,
103590
+ false,
103591
+ constructorOwnsGraph
103433
103592
  )}`,
103434
103593
  2
103435
103594
  )
@@ -104192,6 +104351,7 @@ var init_value_sources = __esm({
104192
104351
  "use strict";
104193
104352
  init_src();
104194
104353
  init_projection();
104354
+ init_variants2();
104195
104355
  init_project_file_source();
104196
104356
  init_lower_members();
104197
104357
  init_lower_variants();
@@ -105997,6 +106157,104 @@ var init_conflict_markers = __esm({
105997
106157
  }
105998
106158
  });
105999
106159
 
106160
+ // src/project-sync/source-record-comparison.ts
106161
+ function sourceAuthoredRecordsSemanticallyEqual(recordKind, left, right, mainLocale) {
106162
+ if (isSchemaRecordKindV4(recordKind)) {
106163
+ return schemaDocumentAuthoredSemanticallyEqual(recordKind, left, right);
106164
+ }
106165
+ return canonicallyEqual(
106166
+ sourceComparableRecord(recordKind, left, mainLocale),
106167
+ sourceComparableRecord(recordKind, right, mainLocale)
106168
+ );
106169
+ }
106170
+ function sourceComparableObjectRecord(recordKind, value, mainLocale) {
106171
+ const comparable = sourceComparableRecord(recordKind, value, mainLocale);
106172
+ if (!isObjectRecord2(comparable)) {
106173
+ throw new Error(
106174
+ `Cannot merge ${recordKind} record because its source-comparable payload is not an object.`
106175
+ );
106176
+ }
106177
+ return comparable;
106178
+ }
106179
+ function workspaceMainLocale(records2) {
106180
+ const config = Object.values(records2).find(
106181
+ (record3) => record3.recordKind === "localization-config"
106182
+ );
106183
+ const data = config?.data;
106184
+ return isObjectRecord2(data) && typeof data.mainLocale === "string" ? data.mainLocale : "en-US";
106185
+ }
106186
+ function acceptSourceEquivalentConflictBases(workspace, mainLocale = workspaceMainLocale(workspace.state.records)) {
106187
+ let accepted = 0;
106188
+ for (const [key, record3] of Object.entries(workspace.state.records)) {
106189
+ if (typeof record3.conflictServerHash !== "string") continue;
106190
+ if (!sourceAuthoredRecordsSemanticallyEqual(
106191
+ record3.recordKind,
106192
+ record3.data,
106193
+ record3.conflictServerData,
106194
+ mainLocale
106195
+ )) {
106196
+ continue;
106197
+ }
106198
+ const next = {
106199
+ ...record3,
106200
+ contentHash: record3.conflictServerHash,
106201
+ data: record3.conflictServerData
106202
+ };
106203
+ delete next.conflictServerHash;
106204
+ delete next.conflictServerData;
106205
+ workspace.state.records[key] = next;
106206
+ accepted += 1;
106207
+ }
106208
+ return accepted;
106209
+ }
106210
+ function sourceComparableRecord(recordKind, value, mainLocale) {
106211
+ return sourceComparableValue(
106212
+ recordKind,
106213
+ recordKind === "value" ? valueRecordComparisonBody(value) : value,
106214
+ mainLocale
106215
+ );
106216
+ }
106217
+ function sourceComparableValue(recordKind, value, mainLocale) {
106218
+ if (Array.isArray(value)) {
106219
+ return value.map(
106220
+ (entry) => sourceComparableValue(recordKind, entry, mainLocale)
106221
+ );
106222
+ }
106223
+ if (!isObjectRecord2(value)) return value;
106224
+ const result = {};
106225
+ const hasAuthoredCode = typeof value.code === "string" || typeof value.setterCode === "string";
106226
+ for (const [key, entry] of Object.entries(value)) {
106227
+ if (key === "projectId" || key === "createdAt" || key === "updatedAt") {
106228
+ continue;
106229
+ }
106230
+ if (recordKind === "dialogue-node" && key === "layout") continue;
106231
+ if (hasAuthoredCode && (key === "getter" || key === "setter" || key === "action")) {
106232
+ continue;
106233
+ }
106234
+ if (recordKind === "localized-text" && key === "localeValues" && isObjectRecord2(entry)) {
106235
+ result[key] = Object.hasOwn(entry, mainLocale) ? {
106236
+ [mainLocale]: sourceComparableValue(
106237
+ recordKind,
106238
+ entry[mainLocale],
106239
+ mainLocale
106240
+ )
106241
+ } : {};
106242
+ continue;
106243
+ }
106244
+ result[key] = sourceComparableValue(recordKind, entry, mainLocale);
106245
+ }
106246
+ return result;
106247
+ }
106248
+ var init_source_record_comparison = __esm({
106249
+ "src/project-sync/source-record-comparison.ts"() {
106250
+ "use strict";
106251
+ init_project_manifest();
106252
+ init_project_documents();
106253
+ init_projection();
106254
+ init_value_record_comparison();
106255
+ }
106256
+ });
106257
+
106000
106258
  // src/project-source/reset.ts
106001
106259
  import {
106002
106260
  existsSync as existsSync5,
@@ -107162,77 +107420,6 @@ function projectSourcePathsRequiringRewriteV4(args) {
107162
107420
  }
107163
107421
  return result;
107164
107422
  }
107165
- function sourceAuthoredRecordsSemanticallyEqual(recordKind, left, right, mainLocale) {
107166
- if (isSchemaRecordKindV4(recordKind)) {
107167
- return schemaDocumentAuthoredSemanticallyEqual(recordKind, left, right);
107168
- }
107169
- return canonicallyEqual(
107170
- sourceComparableRecord(recordKind, left, mainLocale),
107171
- sourceComparableRecord(recordKind, right, mainLocale)
107172
- );
107173
- }
107174
- function sourceComparableRecord(recordKind, value, mainLocale) {
107175
- if (Array.isArray(value)) {
107176
- return value.map(
107177
- (entry) => sourceComparableRecord(recordKind, entry, mainLocale)
107178
- );
107179
- }
107180
- if (!isObjectRecord2(value)) return value;
107181
- const result = {};
107182
- const hasAuthoredCode = typeof value.code === "string" || typeof value.setterCode === "string";
107183
- for (const [key, entry] of Object.entries(value)) {
107184
- if (key === "projectId" || key === "createdAt" || key === "updatedAt") {
107185
- continue;
107186
- }
107187
- if (recordKind === "dialogue-node" && key === "layout") continue;
107188
- if (hasAuthoredCode && (key === "getter" || key === "setter" || key === "action")) {
107189
- continue;
107190
- }
107191
- if (recordKind === "localized-text" && key === "localeValues" && isObjectRecord2(entry)) {
107192
- result[key] = Object.hasOwn(entry, mainLocale) ? {
107193
- [mainLocale]: sourceComparableRecord(
107194
- recordKind,
107195
- entry[mainLocale],
107196
- mainLocale
107197
- )
107198
- } : {};
107199
- continue;
107200
- }
107201
- result[key] = sourceComparableRecord(recordKind, entry, mainLocale);
107202
- }
107203
- return result;
107204
- }
107205
- function acceptSourceEquivalentConflictBases(workspace, mainLocale) {
107206
- let accepted = 0;
107207
- for (const [key, record3] of Object.entries(workspace.state.records)) {
107208
- if (typeof record3.conflictServerHash !== "string") continue;
107209
- if (!sourceAuthoredRecordsSemanticallyEqual(
107210
- record3.recordKind,
107211
- record3.data,
107212
- record3.conflictServerData,
107213
- mainLocale
107214
- )) {
107215
- continue;
107216
- }
107217
- const next = {
107218
- ...record3,
107219
- contentHash: record3.conflictServerHash,
107220
- data: record3.conflictServerData
107221
- };
107222
- delete next.conflictServerHash;
107223
- delete next.conflictServerData;
107224
- workspace.state.records[key] = next;
107225
- accepted += 1;
107226
- }
107227
- return accepted;
107228
- }
107229
- function workspaceMainLocale(records2) {
107230
- const config = Object.values(records2).find(
107231
- (record3) => record3.recordKind === "localization-config"
107232
- );
107233
- const data = config?.data;
107234
- return isObjectRecord2(data) && typeof data.mainLocale === "string" ? data.mainLocale : "en-US";
107235
- }
107236
107423
  function mergeProjectDocumentRecord(recordKind, base, server, local, mainLocale) {
107237
107424
  if (isSchemaRecordKindV4(recordKind)) {
107238
107425
  return mergeSchemaDocumentRecord(recordKind, base, server, local);
@@ -107246,15 +107433,6 @@ function mergeProjectDocumentRecord(recordKind, base, server, local, mainLocale)
107246
107433
  }
107247
107434
  });
107248
107435
  }
107249
- function sourceComparableObjectRecord(recordKind, value, mainLocale) {
107250
- const comparable = sourceComparableRecord(recordKind, value, mainLocale);
107251
- if (!isObjectRecord2(comparable)) {
107252
- throw new Error(
107253
- `Cannot merge ${recordKind} record because its source-comparable payload is not an object.`
107254
- );
107255
- }
107256
- return comparable;
107257
- }
107258
107436
  function buildEmitRecordSet(document, plans, side) {
107259
107437
  const records2 = /* @__PURE__ */ new Map();
107260
107438
  for (const [key, plan] of plans) {
@@ -107313,6 +107491,7 @@ var init_pull = __esm({
107313
107491
  init_conflict_markers();
107314
107492
  init_merge();
107315
107493
  init_projection();
107494
+ init_source_record_comparison();
107316
107495
  init_reset();
107317
107496
  init_project_documents();
107318
107497
  init_project_document_cache();
@@ -114157,7 +114336,7 @@ var init_registry2 = __esm({
114157
114336
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
114158
114337
  formatVersion: 3,
114159
114338
  contractVersion: "3.14",
114160
- cliVersion: "0.36.7",
114339
+ cliVersion: "0.36.9",
114161
114340
  projectFileUploadBatchSize: 32,
114162
114341
  documentRecords: {
114163
114342
  member: {
@@ -120473,6 +120652,7 @@ __export(resolve_exports, {
120473
120652
  import { readFileSync as readFileSync19, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "node:fs";
120474
120653
  import { join as join21 } from "node:path";
120475
120654
  function runResolve(workspace, side) {
120655
+ const resolvedRecords = acceptSourceEquivalentConflictBases(workspace);
120476
120656
  let resolvedFiles = 0;
120477
120657
  for (const filePath of listProjectSourceFilesV4(workspace.root)) {
120478
120658
  const source = readFileSync19(filePath, "utf8");
@@ -120506,15 +120686,15 @@ function runResolve(workspace, side) {
120506
120686
  delete binary.conflict;
120507
120687
  resolvedBinaries += 1;
120508
120688
  }
120509
- if (resolvedBinaries > 0) {
120689
+ if (resolvedRecords > 0 || resolvedBinaries > 0) {
120510
120690
  writeWorkspaceState(workspace.root, workspace.state);
120511
120691
  }
120512
- if (resolvedFiles === 0 && resolvedBinaries === 0) {
120513
- console.log("No conflict markers found.");
120692
+ if (resolvedFiles === 0 && resolvedRecords === 0 && resolvedBinaries === 0) {
120693
+ console.log("No conflicts found.");
120514
120694
  return;
120515
120695
  }
120516
120696
  console.log(
120517
- `Resolved ${resolvedFiles} source file(s) and ${resolvedBinaries} binary file(s) keeping the "${side}" side. Review with "neo diff", then "neo push".`
120697
+ `Resolved ${resolvedFiles} source file(s), ${resolvedRecords} record conflict(s), and ${resolvedBinaries} binary file(s) keeping the "${side}" side. Review with "neo diff", then "neo push".`
120518
120698
  );
120519
120699
  }
120520
120700
  function resolveMarkers(source, side) {
@@ -120563,6 +120743,7 @@ var init_resolve = __esm({
120563
120743
  init_workspace_status();
120564
120744
  init_source_diagnostics();
120565
120745
  init_project_files();
120746
+ init_source_record_comparison();
120566
120747
  }
120567
120748
  });
120568
120749
 
@@ -120759,7 +120940,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
120759
120940
  async function main() {
120760
120941
  const args = parseArgs(process.argv.slice(2));
120761
120942
  if (args.command === "--version") {
120762
- console.log("0.36.7");
120943
+ console.log("0.36.9");
120763
120944
  return;
120764
120945
  }
120765
120946
  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.36.7",
3
+ "version": "0.36.9",
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.36.7 -->
12
+ <!-- reviewed-through-cli: 0.36.9 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -210,6 +210,11 @@ Conflict source deliberately fails compilation. Edit the desired final source,
210
210
  or use `neo resolve --mine|--theirs` as a whole-side convenience. Then pull,
211
211
  review, dry-run, and push again.
212
212
 
213
+ Server-derived compilation metadata is not authored source and does not create
214
+ a pull conflict by itself. If an older CLI retained such a metadata-only
215
+ conflict without writing source markers, either `neo resolve` side accepts the
216
+ newer server metadata as the base while preserving any real local source edit.
217
+
213
218
  `neo push` sends the authenticated semantic diff plus a deterministic source
214
219
  hash, while the server recompiles the changed NeoScript bodies and
215
220
  schema-affected callers and commits only that diff under CAS. Use
@@ -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.36.7 -->
86
+ <!-- reviewed-through-cli: 0.36.9 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -79,6 +79,11 @@ Resolve source conflicts by editing the final intended source. Use
79
79
  `neo resolve --mine` or `neo resolve --theirs` only for a deliberate whole-side
80
80
  choice. Pull, inspect, dry-run, and retry; there is no force-CAS path.
81
81
 
82
+ Compiled initializer IR is server-owned and does not participate in authored
83
+ three-way merge decisions. `neo resolve` also repairs metadata-only conflict
84
+ bookkeeping left by an older pull when no source marker exists; accepting the
85
+ newer server metadata does not overwrite the tracked source.
86
+
82
87
  For `base-hash-conflict`, pull and merge. For `version-bump-required`, inspect
83
88
  the classification and use `neo push --accept-bump` only when the bump is
84
89
  intended.