@neocompose/cli 0.10.4 → 0.10.5

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.10.5] - 2026-07-26
4
+
5
+ ### Changed
6
+
7
+ - Stop writing a second `@id` above every static and project-root initializer.
8
+ A member owns exactly one value row, so that row's identity is a function of
9
+ the declaration the annotation sat under and never needed to be authored.
10
+ `neo pull` now emits the binding without it, and lowering resolves the row
11
+ itself. An `@id` left in a file is accepted while it agrees with the row the
12
+ member already owns, so existing workspaces keep working until their next
13
+ pull; one that disagrees is rejected rather than pushing a create for a
14
+ second row.
15
+ - Derive the row id for a binding that does not have one yet, instead of
16
+ minting it. A member declared for the first time has no durable id to derive
17
+ from, so it carries a `__pending__:member-value:` token that resolves to the
18
+ derivation once the push assigns the member; the server re-derives it rather
19
+ than accepting the client's answer. Rows that already exist keep the ids
20
+ they were minted with -- P39 moves those onto the derivation.
21
+
3
22
  ## [0.10.4] - 2026-07-26
4
23
 
5
24
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -42179,6 +42179,27 @@ var init_dialogue_sources = __esm({
42179
42179
  }
42180
42180
  });
42181
42181
 
42182
+ // ../src/models/members/member-value-id.ts
42183
+ function derivedMemberValueId(memberId) {
42184
+ return v5_default(memberId, NEO_MEMBER_VALUE_NAMESPACE);
42185
+ }
42186
+ function pendingMemberValueId(pendingMemberId) {
42187
+ return `${PENDING_MEMBER_VALUE_PREFIX}${encodeURIComponent(pendingMemberId)}`;
42188
+ }
42189
+ function pendingMemberValueMemberId(token) {
42190
+ if (!token.startsWith(PENDING_MEMBER_VALUE_PREFIX)) return null;
42191
+ return decodeURIComponent(token.slice(PENDING_MEMBER_VALUE_PREFIX.length));
42192
+ }
42193
+ var NEO_MEMBER_VALUE_NAMESPACE, PENDING_MEMBER_VALUE_PREFIX;
42194
+ var init_member_value_id = __esm({
42195
+ "../src/models/members/member-value-id.ts"() {
42196
+ "use strict";
42197
+ init_dist_node();
42198
+ NEO_MEMBER_VALUE_NAMESPACE = "7f2b9c14-58d6-5a07-b3e1-4c9d0a6f8b25";
42199
+ PENDING_MEMBER_VALUE_PREFIX = "__pending__:member-value:";
42200
+ }
42201
+ });
42202
+
42182
42203
  // src/project-source/value-sources.ts
42183
42204
  function inferredGenericClassBinding(classId) {
42184
42205
  return `${INFERRED_GENERIC_CLASS_PREFIX}${classId}`;
@@ -42240,7 +42261,10 @@ function emitStoredValueBindingSourcesV4(records2, memberIds, options) {
42240
42261
  initializers.set(
42241
42262
  memberId,
42242
42263
  emitValue(context, member, member.valueId, {
42243
- exposeIdentity: true,
42264
+ definitionSite: true,
42265
+ // The row is `derivedMemberValueId(memberId)` and the declaration
42266
+ // above it already carries `@id(memberId)`.
42267
+ writeIdentity: false,
42244
42268
  targetTyped: options.targetTypedRoot === true,
42245
42269
  visited
42246
42270
  })
@@ -42689,8 +42713,8 @@ function lowerStoredBinding(context, binding, memberValueIds, seeds) {
42689
42713
  preserveReboundValue(context, currentValueId, referenced, binding);
42690
42714
  return;
42691
42715
  }
42692
- const annotatedId = annotatedValue(expression).id;
42693
- const valueId = annotatedId ?? currentValueId ?? pendingValueId(binding, binding.label);
42716
+ const valueId = currentValueId ?? memberValueId(binding.memberId);
42717
+ assertAuthoredBindingIdMatches(expression, binding, valueId);
42694
42718
  memberValueIds.set(binding.memberId, valueId);
42695
42719
  if (currentValueId === valueId) {
42696
42720
  const existingReconstructedKeys = new Set(context.reconstructed.keys());
@@ -42738,6 +42762,16 @@ function lowerStoredBinding(context, binding, memberValueIds, seeds) {
42738
42762
  const seed = lowerStaticSeed(context, member, expression, binding, valueId);
42739
42763
  seeds.set(binding.memberId, { ...seed, valueId });
42740
42764
  }
42765
+ function assertAuthoredBindingIdMatches(expression, binding, valueId) {
42766
+ const authoredId = annotatedValue(expression).id;
42767
+ if (authoredId === null || authoredId === valueId) return;
42768
+ throw new Error(
42769
+ `Binding ${binding.label} is annotated with value id ${authoredId}, but the member owns value ${valueId}. Remove the @id \u2014 \`neo pull\` rewrites this file without it.`
42770
+ );
42771
+ }
42772
+ function memberValueId(memberId) {
42773
+ return isPendingId(memberId) ? pendingMemberValueId(memberId) : derivedMemberValueId(memberId);
42774
+ }
42741
42775
  function reconstructedOrStateValue(context, valueId) {
42742
42776
  return context.reconstructed.get(`value:${valueId}`)?.fileFields ?? valueBase(context, valueId);
42743
42777
  }
@@ -44429,7 +44463,7 @@ function projectMainLocaleFromState(state) {
44429
44463
  }
44430
44464
  function emitValue(context, member, valueId, options) {
44431
44465
  const externalSymbol = context.symbolsByValueId.get(valueId);
44432
- if (!options.exposeIdentity && externalSymbol !== void 0) {
44466
+ if (!options.definitionSite && externalSymbol !== void 0) {
44433
44467
  return externalSymbol;
44434
44468
  }
44435
44469
  if (options.visited.has(valueId)) {
@@ -44453,7 +44487,7 @@ function emitValue(context, member, valueId, options) {
44453
44487
  options.targetTyped ?? false,
44454
44488
  options.environment
44455
44489
  );
44456
- const prefix = options.exposeIdentity ? `@id(${quote4(valueId)})
44490
+ const prefix = options.writeIdentity ? `@id(${quote4(valueId)})
44457
44491
  ` : "";
44458
44492
  return `${prefix}${expression}`;
44459
44493
  }
@@ -44537,7 +44571,8 @@ function classValue(context, member, value, visited, targetTyped, outerEnvironme
44537
44571
  fields.push(
44538
44572
  `${key} = ${emitValue(context, emittedChildMember, childId, {
44539
44573
  environment,
44540
- exposeIdentity: !context.symbolsByValueId.has(childId) && context.referencedValueIds.has(childId),
44574
+ definitionSite: !context.symbolsByValueId.has(childId),
44575
+ writeIdentity: !context.symbolsByValueId.has(childId) && context.referencedValueIds.has(childId),
44541
44576
  visited
44542
44577
  })}`
44543
44578
  );
@@ -44845,7 +44880,8 @@ ${ids.map(
44845
44880
  (id2) => indentNeoSourceNonEmptyLines(
44846
44881
  emitValue(context, entryMember, id2, {
44847
44882
  environment,
44848
- exposeIdentity: context.symbolsByValueId.get(id2) === void 0,
44883
+ definitionSite: context.symbolsByValueId.get(id2) === void 0,
44884
+ writeIdentity: context.symbolsByValueId.get(id2) === void 0,
44849
44885
  visited
44850
44886
  }),
44851
44887
  2
@@ -44871,7 +44907,8 @@ ${entries.flatMap(
44871
44907
  indentNeoSourceNonEmptyLines(
44872
44908
  `${quote4(key)}: ${emitValue(context, entryMember, id2, {
44873
44909
  environment,
44874
- exposeIdentity: !context.symbolsByValueId.has(id2) && context.referencedValueIds.has(id2),
44910
+ definitionSite: !context.symbolsByValueId.has(id2),
44911
+ writeIdentity: !context.symbolsByValueId.has(id2) && context.referencedValueIds.has(id2),
44875
44912
  visited
44876
44913
  })}`,
44877
44914
  2
@@ -45088,6 +45125,7 @@ var init_value_sources = __esm({
45088
45125
  init_lower_members();
45089
45126
  init_source_format();
45090
45127
  init_world_system_classes();
45128
+ init_member_value_id();
45091
45129
  INFERRED_GENERIC_CLASS_PREFIX = "__inferred_class__:";
45092
45130
  MEMBER_KIND_DICTIONARY = 5;
45093
45131
  MEMBER_KIND_LIST = 6;
@@ -45217,7 +45255,8 @@ function validateProjectRootEnvelopeV4(state, analysis) {
45217
45255
  const expression = parseExpression(slot.initializer);
45218
45256
  const annotation2 = expression.kind === "annotated" ? expression.annotations.find((entry) => entry.name === "id") : void 0;
45219
45257
  const authoredValueId = annotation2?.args[0];
45220
- if (authoredValueId?.kind !== "litString" || authoredValueId.value !== memberData.valueId) {
45258
+ if (authoredValueId === void 0) return;
45259
+ if (authoredValueId.kind !== "litString" || authoredValueId.value !== memberData.valueId) {
45221
45260
  throw new Error(
45222
45261
  `Root value root.${expected.name} must retain stable value id ${memberData.valueId}.`
45223
45262
  );
@@ -66552,6 +66591,13 @@ function assignPendingIds(changes, staticValueSeeds, reconstructed3) {
66552
66591
  const assign = (pendingId2) => {
66553
66592
  const existing = assigned.get(pendingId2);
66554
66593
  if (existing !== void 0) return existing;
66594
+ const memberLocator = pendingMemberValueMemberId(pendingId2);
66595
+ if (memberLocator !== null) {
66596
+ const memberId = isPendingId(memberLocator) ? assign(memberLocator) : memberLocator;
66597
+ const derived = derivedMemberValueId(memberId);
66598
+ assigned.set(pendingId2, derived);
66599
+ return derived;
66600
+ }
66555
66601
  const fresh = randomUUID5();
66556
66602
  assigned.set(pendingId2, fresh);
66557
66603
  return fresh;
@@ -68569,6 +68615,7 @@ var init_push = __esm({
68569
68615
  init_project_documents();
68570
68616
  init_workspace_status();
68571
68617
  init_lower_support();
68618
+ init_member_value_id();
68572
68619
  init_source_diagnostics();
68573
68620
  init_projection();
68574
68621
  init_project_file_push();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.10.4",
3
+ "version": "0.10.5",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",