@neocompose/cli 0.41.0 → 0.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.42.1] - 2026-09-02
4
+
5
+ ### Fixed
6
+
7
+ - `neo status` reported a phantom parent update plus a child create for every
8
+ packed child of a row authored directly in a List or Dictionary member's
9
+ declaration default (`PlacementTiles = [ new NeoObjectPlacementTile { Cell =
10
+ new(0, 1) } ]` in a class file). The shared packed-value fold decides what
11
+ packs by walking the value graph from its roots, and that walk seeded a
12
+ declaration default only for Class members, so an entry row's children had
13
+ no placement and stayed sparse where the server had packed them. The walk now
14
+ seeds List and Dictionary declaration defaults too.
15
+
16
+ ## [0.42.0] - 2026-09-02
17
+
18
+ ### Fixed
19
+
20
+ - `neo pull --reset` and `neo pull --regenerate-source-names` rewrote every
21
+ dialogue binding to its type name. Binding names are derived from a value's
22
+ `Name` child, and the placement index read the pulled rows as stored rather
23
+ than expanding packed subtree storage first, so a packed `Name` resolved to
24
+ nothing and `Outpost CaelusAnchorpoint` came back as `Outpost Outpost`. Every
25
+ linked dialogue and node then showed up as an update in `neo status` whose
26
+ only difference was the regenerated name. The index now expands packed
27
+ children into the logical rows they are.
28
+ - `neo pull` left a member declared by more than one class disagreeing with
29
+ itself. A changed record was rewritten in the single file the emission
30
+ attributes it to, so a change to a shared member updated one class and
31
+ froze the others at their previously emitted text, and the next command
32
+ refused the CLI's own output with "Shared member id … has inconsistent
33
+ declarations." Pull now rewrites every file that declares a changed record.
34
+
35
+ ### Removed
36
+
37
+ - `neo migrate rekey`. The canonical value-id migration it served has run on
38
+ every deployment and the server no longer serves the old-to-canonical
39
+ mapping page it read, so the command had nothing left to rewrite.
40
+ `neo migrate` keeps `new | list | check | run | prune`.
41
+
3
42
  ## [0.41.0] - 2026-09-01
4
43
 
5
44
  ### Added
package/dist/neo.mjs CHANGED
@@ -59305,6 +59305,7 @@ var init_dialogue_sources = __esm({
59305
59305
  "use strict";
59306
59306
  init_src();
59307
59307
  init_dialogue();
59308
+ init_members();
59308
59309
  init_projection();
59309
59310
  init_member_records();
59310
59311
  init_neoscript_source_rewrite();
@@ -59340,6 +59341,16 @@ var init_dialogue_sources = __esm({
59340
59341
  else if (record3.recordKind === "localized-text")
59341
59342
  this.localizedTexts.set(record3.recordId, recordData2(record3));
59342
59343
  }
59344
+ const physicalValues = [
59345
+ ...this.values.values()
59346
+ ];
59347
+ const logicalValues = expandPackedValueRows(physicalValues);
59348
+ if (logicalValues !== physicalValues) {
59349
+ for (const row of logicalValues) {
59350
+ const id2 = optionalString2(row.id);
59351
+ if (id2) this.values.set(id2, row);
59352
+ }
59353
+ }
59343
59354
  const localization = records2.find(
59344
59355
  (record3) => record3.recordKind === "localization-config"
59345
59356
  );
@@ -67127,6 +67138,21 @@ function findOwningMembersForValues(document, valueIds, additionalRoots, travers
67127
67138
  rows.push(value);
67128
67139
  }
67129
67140
  }
67141
+ let declaringClassIdByMemberId = null;
67142
+ const declaringClassEnv = (memberId) => {
67143
+ if (declaringClassIdByMemberId === null) {
67144
+ declaringClassIdByMemberId = /* @__PURE__ */ new Map();
67145
+ for (const schemaClass2 of document.classes) {
67146
+ for (const declaredId of Object.values(schemaClass2.schema)) {
67147
+ if (declaringClassIdByMemberId.has(declaredId)) continue;
67148
+ declaringClassIdByMemberId.set(declaredId, schemaClass2.id);
67149
+ }
67150
+ }
67151
+ }
67152
+ const classId = declaringClassIdByMemberId.get(memberId);
67153
+ if (classId === void 0) return envFromStamp(void 0);
67154
+ return resolveInstanceEnv(classId, void 0, document.classes);
67155
+ };
67130
67156
  const queue = [];
67131
67157
  const enqueueClassInstanceChildren = (args) => {
67132
67158
  const merged = mergeStoredInstanceSchema(
@@ -67180,18 +67206,57 @@ function findOwningMembersForValues(document, valueIds, additionalRoots, travers
67180
67206
  }
67181
67207
  const defaultValue = member.defaultValue;
67182
67208
  if (defaultValue == null) continue;
67183
- if (!isMemberClassBase(member)) continue;
67184
- if (!isRecordValue(defaultValue.value)) continue;
67185
- enqueueClassInstanceChildren({
67186
- member,
67187
- record: defaultValue.value,
67188
- effectiveClassId: defaultValue.classId ?? member.classId,
67189
- // A declaration default is never itself an override graph (D10).
67190
- insideAnimationOverrideGraph: false,
67191
- // The default graph hangs off the MEMBER record, so its children have no
67192
- // owning value row (P76: they stay physically sparse).
67193
- parentValueId: null
67194
- });
67209
+ if (isMemberClassBase(member)) {
67210
+ if (!isRecordValue(defaultValue.value)) continue;
67211
+ enqueueClassInstanceChildren({
67212
+ member,
67213
+ record: defaultValue.value,
67214
+ effectiveClassId: defaultValue.classId ?? member.classId,
67215
+ // A declaration default is never itself an override graph (D10).
67216
+ insideAnimationOverrideGraph: false,
67217
+ // The default graph hangs off the MEMBER record, so its children have
67218
+ // no owning value row (P76: they stay physically sparse).
67219
+ parentValueId: null
67220
+ });
67221
+ continue;
67222
+ }
67223
+ let entryMemberId;
67224
+ let entryValueIds;
67225
+ if (isMemberDictionaryBase(member)) {
67226
+ if (!isRecordValue(defaultValue.value)) continue;
67227
+ entryMemberId = member.entryMemberId;
67228
+ entryValueIds = Object.values(defaultValue.value);
67229
+ } else if (isMemberListBase(member)) {
67230
+ if (listKindOf(member) === 1 /* Unordered */) continue;
67231
+ if (!isStringListValue(defaultValue.value)) continue;
67232
+ entryMemberId = member.entryMemberId;
67233
+ entryValueIds = defaultValue.value;
67234
+ } else {
67235
+ continue;
67236
+ }
67237
+ const entryMemberRecord = membersById2.get(entryMemberId);
67238
+ if (entryMemberRecord === void 0) continue;
67239
+ let entryMember;
67240
+ try {
67241
+ entryMember = substituteMember(
67242
+ entryMemberRecord,
67243
+ declaringClassEnv(member.id),
67244
+ document.members
67245
+ );
67246
+ } catch {
67247
+ continue;
67248
+ }
67249
+ for (const entryValueId of entryValueIds) {
67250
+ queue.push({
67251
+ member: entryMember,
67252
+ memberRecordId: entryMemberRecord.id,
67253
+ id: entryValueId,
67254
+ // A declaration default is never itself an override graph (D10).
67255
+ insideAnimationOverrideGraph: false,
67256
+ // Reached from the MEMBER record: no owning value row.
67257
+ parentValueId: null
67258
+ });
67259
+ }
67195
67260
  }
67196
67261
  const visited = /* @__PURE__ */ new Set();
67197
67262
  for (let cursor = 0; cursor < queue.length; cursor += 1) {
@@ -70102,7 +70167,7 @@ function withEvaluationRuntime(ctx, writes) {
70102
70167
  ctx.__runtimeSessionValues
70103
70168
  );
70104
70169
  const referencesAlreadyRemapped = ctx.__valueOverlay !== void 0 && ctx.__runtimeReferenceRemap !== void 0;
70105
- const remap2 = (value) => referencesAlreadyRemapped ? value : remapRuntimeReferences(
70170
+ const remap = (value) => referencesAlreadyRemapped ? value : remapRuntimeReferences(
70106
70171
  value,
70107
70172
  overlay,
70108
70173
  referenceRemap,
@@ -70110,11 +70175,11 @@ function withEvaluationRuntime(ctx, writes) {
70110
70175
  );
70111
70176
  return {
70112
70177
  ...ctx,
70113
- thisValue: remap2(ctx.thisValue),
70114
- rootValue: remap2(ctx.rootValue),
70178
+ thisValue: remap(ctx.thisValue),
70179
+ rootValue: remap(ctx.rootValue),
70115
70180
  dialogueContext: ctx.dialogueContext === void 0 || ctx.dialogueContext === null ? ctx.dialogueContext : {
70116
- primary: remap2(ctx.dialogueContext.primary),
70117
- trigger: remap2(ctx.dialogueContext.trigger)
70181
+ primary: remap(ctx.dialogueContext.primary),
70182
+ trigger: remap(ctx.dialogueContext.trigger)
70118
70183
  },
70119
70184
  __runtimeSessionValues: runtimeSessionValues,
70120
70185
  __saveStaticBindings: ctx.__saveStaticBindings ?? staticBindingMap(ctx.saveStaticBindings),
@@ -79776,12 +79841,12 @@ function sparsifyConstructedInstance(args) {
79776
79841
  ) ?? virtualId
79777
79842
  );
79778
79843
  }
79779
- const remap2 = (value) => {
79844
+ const remap = (value) => {
79780
79845
  if (typeof value === "string") return nextIdById.get(value) ?? value;
79781
- if (Array.isArray(value)) return value.map(remap2);
79846
+ if (Array.isArray(value)) return value.map(remap);
79782
79847
  if (typeof value !== "object" || value === null) return value;
79783
79848
  return Object.fromEntries(
79784
- Object.entries(value).map(([key, entry]) => [key, remap2(entry)])
79849
+ Object.entries(value).map(([key, entry]) => [key, remap(entry)])
79785
79850
  );
79786
79851
  };
79787
79852
  const rewrite = (row) => {
@@ -79789,9 +79854,9 @@ function sparsifyConstructedInstance(args) {
79789
79854
  return {
79790
79855
  ...literal2,
79791
79856
  id: nextIdById.get(row.id) ?? row.id,
79792
- value: remap2(updatedValueById.get(row.id) ?? literal2.value),
79857
+ value: remap(updatedValueById.get(row.id) ?? literal2.value),
79793
79858
  ...literal2.constructorArgs === void 0 ? {} : {
79794
- constructorArgs: remap2(literal2.constructorArgs)
79859
+ constructorArgs: remap(literal2.constructorArgs)
79795
79860
  },
79796
79861
  ...typeof row.containerId === "string" ? { containerId: nextIdById.get(row.containerId) ?? row.containerId } : {}
79797
79862
  };
@@ -116639,20 +116704,20 @@ async function finishFormat4Pull(args) {
116639
116704
  ...[...conflictPaths].filter((path) => serverByPath.has(path)),
116640
116705
  ...authoredLocalConflictKeysByPath.keys()
116641
116706
  ]);
116707
+ const localRecordFiles = declaringSourcePathsV4(localResult);
116642
116708
  const rewritePaths = projectSourcePathsRequiringRewriteV4({
116643
116709
  destructive,
116644
116710
  localStatus,
116645
116711
  plans,
116646
- localRecordFiles: localResult.recordFiles,
116647
- serverRecordFiles: serverResult?.recordFiles ?? /* @__PURE__ */ new Map(),
116712
+ localRecordFiles,
116713
+ serverRecordFiles: serverResult === null ? /* @__PURE__ */ new Map() : declaringSourcePathsV4(serverResult),
116648
116714
  previousRecords: workspace.state.records,
116649
116715
  conflictPaths,
116650
116716
  emittedPaths,
116651
116717
  mainLocale: workspaceMainLocale(workspace.state.records)
116652
116718
  });
116653
116719
  for (const key of regeneratedRecordKeys) {
116654
- const path = localResult.recordFiles.get(key);
116655
- if (path !== void 0) rewritePaths.add(path);
116720
+ for (const path of localRecordFiles.get(key) ?? []) rewritePaths.add(path);
116656
116721
  }
116657
116722
  const resolveSourcePath = createWorkspaceSourcePathResolver(workspace.root);
116658
116723
  let written = 0;
@@ -116949,14 +117014,30 @@ function cursorsEqual(left, right) {
116949
117014
  (transactionId, index) => transactionId === right.transactionIds[index]
116950
117015
  );
116951
117016
  }
117017
+ function declaringSourcePathsV4(emission) {
117018
+ const paths = /* @__PURE__ */ new Map();
117019
+ const add = (key, path) => {
117020
+ const existing = paths.get(key);
117021
+ if (existing === void 0) {
117022
+ paths.set(key, [path]);
117023
+ return;
117024
+ }
117025
+ if (!existing.includes(path)) existing.push(path);
117026
+ };
117027
+ for (const file of emission.files) {
117028
+ for (const key of file.recordKeys) add(key, file.path);
117029
+ }
117030
+ for (const [key, path] of emission.recordFiles) add(key, path);
117031
+ return paths;
117032
+ }
116952
117033
  function projectSourcePathsRequiringRewriteV4(args) {
116953
117034
  if (args.destructive || args.localStatus === null) {
116954
117035
  return new Set(args.emittedPaths);
116955
117036
  }
116956
117037
  const result = new Set(args.conflictPaths);
116957
117038
  for (const [key, plan] of args.plans) {
116958
- const path = args.localRecordFiles.get(key) ?? args.serverRecordFiles.get(key);
116959
- if (path === void 0) continue;
117039
+ const paths = args.localRecordFiles.get(key) ?? args.serverRecordFiles.get(key);
117040
+ if (paths === void 0) continue;
116960
117041
  const local = args.localStatus.reconstructed.get(key)?.fullData;
116961
117042
  const kind = args.previousRecords[key]?.recordKind ?? key.split(":", 1)[0] ?? "";
116962
117043
  if (plan.emitData === void 0 ? local !== void 0 : local === void 0 || !sourceAuthoredRecordsSemanticallyEqual(
@@ -116965,7 +117046,7 @@ function projectSourcePathsRequiringRewriteV4(args) {
116965
117046
  local,
116966
117047
  args.mainLocale
116967
117048
  )) {
116968
- result.add(path);
117049
+ for (const path of paths) result.add(path);
116969
117050
  }
116970
117051
  }
116971
117052
  for (const [key, previous] of Object.entries(args.previousRecords)) {
@@ -124160,7 +124241,7 @@ var init_registry2 = __esm({
124160
124241
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
124161
124242
  formatVersion: 4,
124162
124243
  contractVersion: "4.1",
124163
- cliVersion: "0.41.0",
124244
+ cliVersion: "0.42.1",
124164
124245
  projectFileUploadBatchSize: 32,
124165
124246
  documentRecords: {
124166
124247
  member: {
@@ -127632,440 +127713,6 @@ var init_doctor = __esm({
127632
127713
  }
127633
127714
  });
127634
127715
 
127635
- // ../src/database/p76-canonical-value-id-plan.ts
127636
- function rewriteP76CanonicalValueIds(args) {
127637
- if (args.newByOldValueId.size === 0) return args.data;
127638
- return rewriteRecord(args.recordKind, args.data, args.newByOldValueId);
127639
- }
127640
- function rewriteRecord(recordKind, data, newByOldValueId) {
127641
- if (!isPlainRecord5(data)) return data;
127642
- return mapRecord(data, (field, child) => {
127643
- if (field === "id") {
127644
- return recordKind === ProjectRecordKind.Value ? remap(child, newByOldValueId) : child;
127645
- }
127646
- if (field === "sourceValueId") return child;
127647
- if (ROW_CONTENT_FIELDS.has(field)) {
127648
- return rewriteRowContent(child, newByOldValueId);
127649
- }
127650
- if (isRelationEndpoint(recordKind, data, field)) {
127651
- return remap(child, newByOldValueId);
127652
- }
127653
- return rewriteByFieldName(child, field, newByOldValueId);
127654
- });
127655
- }
127656
- function isRelationEndpoint(recordKind, data, field) {
127657
- if (recordKind !== ProjectRecordKind.InternalRecordRelation) return false;
127658
- if (field === "sourceRecordId") {
127659
- return data.sourceRecordKind === ProjectRecordKind.Value;
127660
- }
127661
- if (field === "targetRecordId") {
127662
- return data.targetRecordKind === ProjectRecordKind.Value;
127663
- }
127664
- return false;
127665
- }
127666
- function rewriteRowContent(node, newByOldValueId) {
127667
- if (typeof node === "string") return remap(node, newByOldValueId);
127668
- if (Array.isArray(node)) {
127669
- return mapArray(node, (entry) => rewriteRowContent(entry, newByOldValueId));
127670
- }
127671
- if (!isPlainRecord5(node)) return node;
127672
- if (Object.hasOwn(node, STRUCTURED_LEAF_PARTIAL_KEY)) return node;
127673
- const packed = node[PACKED_VALUE_ENTRY_KEY];
127674
- if (packed !== void 0) {
127675
- const rewritten = rewritePackedEntry(packed, newByOldValueId);
127676
- if (rewritten === packed) return node;
127677
- return { ...node, [PACKED_VALUE_ENTRY_KEY]: rewritten };
127678
- }
127679
- return mapRecord(
127680
- node,
127681
- (_field, child) => rewriteRowContent(child, newByOldValueId)
127682
- );
127683
- }
127684
- function rewritePackedEntry(entry, newByOldValueId) {
127685
- if (!isPlainRecord5(entry)) return entry;
127686
- return mapRecord(entry, (field, child) => {
127687
- if (field === "id") return remap(child, newByOldValueId);
127688
- if (field === "sourceValueId") return child;
127689
- if (ROW_CONTENT_FIELDS.has(field)) {
127690
- return rewriteRowContent(child, newByOldValueId);
127691
- }
127692
- return rewriteByFieldName(child, field, newByOldValueId);
127693
- });
127694
- }
127695
- function rewriteByFieldName(node, field, newByOldValueId) {
127696
- if (typeof node === "string") {
127697
- if (isCompilerReferenceField(field)) return remap(node, newByOldValueId);
127698
- if (AUTHORED_VALUE_ID_FIELDS.has(field)) {
127699
- return remap(node, newByOldValueId);
127700
- }
127701
- return node;
127702
- }
127703
- if (Array.isArray(node)) {
127704
- return mapArray(
127705
- node,
127706
- (entry) => rewriteByFieldName(entry, field, newByOldValueId)
127707
- );
127708
- }
127709
- if (!isPlainRecord5(node)) return node;
127710
- if (Object.hasOwn(node, STRUCTURED_LEAF_PARTIAL_KEY)) return node;
127711
- return mapRecord(node, (childField, child) => {
127712
- if (childField === "sourceValueId") return child;
127713
- if (ROW_CONTENT_FIELDS.has(childField)) {
127714
- return rewriteRowContent(child, newByOldValueId);
127715
- }
127716
- return rewriteByFieldName(child, childField, newByOldValueId);
127717
- });
127718
- }
127719
- function remap(node, newByOldValueId) {
127720
- if (typeof node !== "string") return node;
127721
- return newByOldValueId.get(node) ?? node;
127722
- }
127723
- function mapRecord(record3, rewrite) {
127724
- let changed = false;
127725
- const next = {};
127726
- for (const [field, child] of Object.entries(record3)) {
127727
- const rewritten = rewrite(field, child);
127728
- if (rewritten !== child) changed = true;
127729
- next[field] = rewritten;
127730
- }
127731
- return changed ? next : record3;
127732
- }
127733
- function mapArray(entries, rewrite) {
127734
- let changed = false;
127735
- const next = new Array(entries.length);
127736
- for (const [index, entry] of entries.entries()) {
127737
- const rewritten = rewrite(entry);
127738
- if (rewritten !== entry) changed = true;
127739
- next[index] = rewritten;
127740
- }
127741
- return changed ? next : entries;
127742
- }
127743
- function isPlainRecord5(value) {
127744
- if (typeof value !== "object" || value === null) return false;
127745
- return !Array.isArray(value);
127746
- }
127747
- var P76_CANONICAL_VALUE_ID_USE_SITES, AUTHORED_VALUE_ID_FIELDS, ROW_CONTENT_FIELDS;
127748
- var init_p76_canonical_value_id_plan = __esm({
127749
- "../src/database/p76-canonical-value-id-plan.ts"() {
127750
- "use strict";
127751
- init_inheritance();
127752
- init_instance_provenance();
127753
- init_member_kinds();
127754
- init_member_value_id();
127755
- init_packed_value_encoding();
127756
- init_stored_value_placement_index();
127757
- init_structured_leaf_fields();
127758
- init_project2();
127759
- init_neo_script_recompile_scope();
127760
- init_virtual_instance_values();
127761
- P76_CANONICAL_VALUE_ID_USE_SITES = [
127762
- "value.id",
127763
- "value.containerId",
127764
- "value.instanceVariantRowValueId",
127765
- "value.sourceValueId",
127766
- "value.constructorArgs.*",
127767
- "value.value.*",
127768
- `value.value.${PACKED_VALUE_ENTRY_KEY}.id`,
127769
- `value.value.${PACKED_VALUE_ENTRY_KEY}.value.*`,
127770
- `value.value.${PACKED_VALUE_ENTRY_KEY}.constructorArgs.*`,
127771
- `value.value.${PACKED_VALUE_ENTRY_KEY}.instanceVariantRowValueId`,
127772
- `value.value.${PACKED_VALUE_ENTRY_KEY}.sourceValueId`,
127773
- "value.init.**",
127774
- "member.valueId",
127775
- "member.collectionValueId",
127776
- "member.defaultValue.*",
127777
- "member.getter.**",
127778
- "member.setter.**",
127779
- "member.action.**",
127780
- "member.uiAction.**",
127781
- "variant.valueId",
127782
- "variant-folder.binding.collectionValueId",
127783
- "constructor.action.**",
127784
- "constructor.compiledBaseArguments.**",
127785
- "constructor.compiledBaseInitializerFields.**",
127786
- "dialogue.primaryLinkedValueId",
127787
- "dialogue.linkedValues.*.valueId",
127788
- "dialogue-node.primaryLinkedValueId",
127789
- "dialogue-node.linkedValues.*.valueId",
127790
- "dialogue-node.dialogueGroupSettings.lookupValueId",
127791
- "dialogue-node.**",
127792
- "dialogue-group.collectionValueId",
127793
- "dialogue-group.conditions.**",
127794
- "localized-text.links.*.valueId",
127795
- "internal-record-relation.sourceRecordId",
127796
- "internal-record-relation.targetRecordId"
127797
- ];
127798
- AUTHORED_VALUE_ID_FIELDS = /* @__PURE__ */ new Set([
127799
- "assetValueId",
127800
- "containerId",
127801
- "instanceVariantRowValueId",
127802
- "lookupValueId",
127803
- "rowValueId"
127804
- ]);
127805
- ROW_CONTENT_FIELDS = /* @__PURE__ */ new Set([
127806
- "value",
127807
- "constructorArgs"
127808
- ]);
127809
- }
127810
- });
127811
-
127812
- // src/commands/migrate-rekey.ts
127813
- import { readFileSync as readFileSync18, rmSync as rmSync8, writeFileSync as writeFileSync12 } from "node:fs";
127814
- import { join as join17, relative as relative8, sep as sep8 } from "node:path";
127815
- import { ConvexError as ConvexError2 } from "convex/values";
127816
- function rekeyCanonicalValueIdsInSource(text, newByOldValueId) {
127817
- let pins = 0;
127818
- let references = 0;
127819
- const pinned = text.replace(
127820
- ID_PIN_PATTERN,
127821
- (match, open, oldId, close) => {
127822
- const newId = newByOldValueId.get(oldId);
127823
- if (newId === void 0) return match;
127824
- pins += 1;
127825
- return `${open}${newId}${close}`;
127826
- }
127827
- );
127828
- const rewritten = pinned.replace(
127829
- REFERENCE_ID_PATTERN,
127830
- (match, open, oldId, close) => {
127831
- const newId = newByOldValueId.get(oldId);
127832
- if (newId === void 0) return match;
127833
- references += 1;
127834
- return `${open}${newId}${close}`;
127835
- }
127836
- );
127837
- return { text: rewritten, pins, references };
127838
- }
127839
- function assertNoOldValueIdsInSource(files, oldValueIds) {
127840
- for (const file of files) {
127841
- for (const match of file.text.matchAll(QUOTED_STRING_PATTERN)) {
127842
- const quoted = match[1];
127843
- if (quoted === void 0) continue;
127844
- if (!oldValueIds.has(quoted)) continue;
127845
- const line = file.text.slice(0, match.index).split("\n").length;
127846
- throw new Error(
127847
- `${file.path}:${String(line)} still quotes pre-migration value id "${quoted}" outside an @id pin or Reference(id:) literal. Rewrite that use by hand, then rerun "neo migrate rekey".`
127848
- );
127849
- }
127850
- }
127851
- }
127852
- function rekeyWorkspaceState(state, newByOldValueId) {
127853
- const nextRecords = {};
127854
- let recordsRekeyed = 0;
127855
- let recordsDataRewritten = 0;
127856
- for (const [key, record3] of Object.entries(state.records)) {
127857
- if (!isProjectRecordKind(record3.recordKind)) {
127858
- throw new Error(
127859
- `Workspace state entry "${key}" has unknown record kind "${record3.recordKind}".`
127860
- );
127861
- }
127862
- const data = rewriteP76CanonicalValueIds({
127863
- recordKind: record3.recordKind,
127864
- data: record3.data,
127865
- newByOldValueId
127866
- });
127867
- if (data !== record3.data) recordsDataRewritten += 1;
127868
- const newValueId = record3.recordKind === ProjectRecordKind.Value ? newByOldValueId.get(record3.recordId) : void 0;
127869
- if (newValueId === void 0) {
127870
- nextRecords[key] = { ...record3, data };
127871
- continue;
127872
- }
127873
- const nextKey = recordStateKey(record3.recordKind, newValueId);
127874
- if (Object.hasOwn(state.records, nextKey)) {
127875
- throw new Error(
127876
- `Workspace state entry "${key}" rekeys to "${nextKey}", which the working copy already tracks.`
127877
- );
127878
- }
127879
- if (Object.hasOwn(nextRecords, nextKey)) {
127880
- throw new Error(
127881
- `Workspace state entry "${key}" rekeys to "${nextKey}", which another entry already claimed.`
127882
- );
127883
- }
127884
- nextRecords[nextKey] = { ...record3, data, recordId: newValueId };
127885
- recordsRekeyed += 1;
127886
- }
127887
- state.records = nextRecords;
127888
- delete state.documentRevisionCursor;
127889
- delete state.headTransactionHash;
127890
- return { recordsRekeyed, recordsDataRewritten };
127891
- }
127892
- async function runMigrateRekey(workspace, dependencies = {}) {
127893
- const mappings = await (dependencies.fetchMappings ?? fetchCanonicalValueIdMappings)(workspace);
127894
- if (mappings.length === 0) {
127895
- console.log("Nothing to rekey.");
127896
- return;
127897
- }
127898
- const newByOldValueId = new Map(
127899
- mappings.map((mapping) => [mapping.oldValueId, mapping.newValueId])
127900
- );
127901
- const status = (dependencies.computeStatus ?? computeWorkspaceStatus2)(
127902
- workspace
127903
- );
127904
- if (status.conflictedFiles.length > 0) {
127905
- throw new Error(
127906
- `Resolve conflict markers before rekeying canonical value ids: ${status.conflictedFiles.join(", ")}`
127907
- );
127908
- }
127909
- for (const [key, record3] of Object.entries(workspace.state.records)) {
127910
- if (record3.conflictServerHash === void 0) continue;
127911
- throw new Error(
127912
- `Workspace state entry "${key}" holds an unresolved pull conflict; run "neo resolve" before rekeying canonical value ids.`
127913
- );
127914
- }
127915
- const rewrites = rewriteTrackedSources(workspace.root, newByOldValueId);
127916
- assertNoOldValueIdsInSource(
127917
- rewrites.map((rewrite) => ({
127918
- path: rewrite.path,
127919
- text: rewrite.text
127920
- })),
127921
- new Set(newByOldValueId.keys())
127922
- );
127923
- const changedFiles = rewrites.filter(
127924
- (rewrite) => rewrite.text !== rewrite.original
127925
- );
127926
- if (changedFiles.length > 0) {
127927
- assertRekeyedSourceCompiles(rewrites, newByOldValueId);
127928
- }
127929
- const stateResult = rekeyWorkspaceState(workspace.state, newByOldValueId);
127930
- if (changedFiles.length === 0 && stateResult.recordsRekeyed === 0 && stateResult.recordsDataRewritten === 0) {
127931
- console.log("Already rekeyed \u2014 no pre-migration value ids remain.");
127932
- return;
127933
- }
127934
- for (const rewrite of changedFiles) {
127935
- writeFileSync12(join17(workspace.root, rewrite.path), rewrite.text, "utf8");
127936
- }
127937
- writeWorkspaceState(workspace.root, workspace.state);
127938
- for (const path of DERIVED_CACHE_PATHS) {
127939
- rmSync8(join17(workspace.root, path), { force: true });
127940
- }
127941
- let pins = 0;
127942
- let references = 0;
127943
- for (const file of changedFiles) {
127944
- pins += file.pins;
127945
- references += file.references;
127946
- }
127947
- console.log(
127948
- `Rekeyed ${String(changedFiles.length)} source file(s): ${String(pins)} @id pin(s), ${String(references)} Reference(id:) literal(s).`
127949
- );
127950
- console.log(
127951
- `Rekeyed ${String(stateResult.recordsRekeyed)} state record(s) and rewrote ids in ${String(stateResult.recordsDataRewritten)}. Run "neo pull" next.`
127952
- );
127953
- }
127954
- function rewriteTrackedSources(root, newByOldValueId) {
127955
- const rewrites = [];
127956
- const collect = (absolutePaths, production) => {
127957
- for (const absolutePath of absolutePaths) {
127958
- const original = readFileSync18(absolutePath, "utf8");
127959
- rewrites.push({
127960
- path: relative8(root, absolutePath).split(sep8).join("/"),
127961
- original,
127962
- production,
127963
- ...rekeyCanonicalValueIdsInSource(original, newByOldValueId)
127964
- });
127965
- }
127966
- };
127967
- collect(listProjectSourceFilesV4(root), true);
127968
- collect(listProjectTestFilesV1(root), false);
127969
- return rewrites;
127970
- }
127971
- function assertRekeyedSourceCompiles(rewrites, newByOldValueId) {
127972
- const production = rewrites.filter((rewrite) => rewrite.production);
127973
- const inputs = production.map((rewrite) => ({
127974
- uri: rewrite.path,
127975
- kind: requiredProjectSourceKindV4(rewrite.path),
127976
- text: rewrite.original
127977
- }));
127978
- const before = new Set(
127979
- blockingDiagnostics(compileNeoProjectSources(inputs)).map(
127980
- (diagnostic) => diagnosticSignature(diagnostic, newByOldValueId)
127981
- )
127982
- );
127983
- const introduced = blockingDiagnostics(
127984
- compileNeoProjectSources(
127985
- inputs.map((input, index) => ({
127986
- ...input,
127987
- text: production[index].text
127988
- }))
127989
- )
127990
- ).filter(
127991
- (diagnostic) => !before.has(diagnosticSignature(diagnostic, newByOldValueId))
127992
- );
127993
- if (introduced.length === 0) return;
127994
- throw new Error(
127995
- `Canonical value-id rekey produced invalid source:
127996
- ${introduced.map(
127997
- (diagnostic) => ` ${diagnostic.uri}:${String(diagnostic.range.start.line + 1)}:${String(diagnostic.range.start.character + 1)} ${diagnostic.message}`
127998
- ).join("\n")}`
127999
- );
128000
- }
128001
- function blockingDiagnostics(analysis) {
128002
- return analysis.diagnostics.filter(
128003
- (diagnostic) => diagnostic.severity === "error" && !isPullRecoveryDiagnosticCode(diagnostic.code)
128004
- );
128005
- }
128006
- function diagnosticSignature(diagnostic, newByOldValueId) {
128007
- const message = diagnostic.message.replace(
128008
- /[A-Za-z0-9_-]+/g,
128009
- (token) => newByOldValueId.get(token) ?? token
128010
- );
128011
- return `${diagnostic.uri} ${diagnostic.code ?? ""} ${message}`;
128012
- }
128013
- async function fetchCanonicalValueIdMappings(workspace) {
128014
- const convex = await createConvexClient(workspace);
128015
- const mappings = [];
128016
- let cursor = null;
128017
- for (; ; ) {
128018
- const page = await queryMappingsPage(convex, workspace, cursor);
128019
- for (const mapping of page.page) mappings.push(mapping);
128020
- if (page.isDone) break;
128021
- cursor = page.continueCursor;
128022
- }
128023
- return mappings;
128024
- }
128025
- async function queryMappingsPage(convex, workspace, cursor) {
128026
- try {
128027
- return await convex.query(
128028
- api2.projectDocuments.getCanonicalValueIdMappingsPage,
128029
- {
128030
- projectId: workspace.config.projectId,
128031
- versionId: workspace.config.versionId,
128032
- paginationOpts: { cursor, numItems: MAPPING_PAGE_SIZE }
128033
- }
128034
- );
128035
- } catch (error) {
128036
- if (error instanceof ConvexError2 && typeof error.data === "string") {
128037
- throw new Error(error.data);
128038
- }
128039
- throw error;
128040
- }
128041
- }
128042
- var MAPPING_PAGE_SIZE, ID_PIN_PATTERN, REFERENCE_ID_PATTERN, QUOTED_STRING_PATTERN, DERIVED_CACHE_PATHS;
128043
- var init_migrate_rekey = __esm({
128044
- "src/commands/migrate-rekey.ts"() {
128045
- "use strict";
128046
- init_src();
128047
- init_p76_canonical_value_id_plan();
128048
- init_project2();
128049
- init_convex();
128050
- init_materialized_construction_cache();
128051
- init_project_document_cache();
128052
- init_project_documents();
128053
- init_source_diagnostics();
128054
- init_workspace_status();
128055
- init_workspace();
128056
- MAPPING_PAGE_SIZE = 512;
128057
- ID_PIN_PATTERN = /(@id\s*\(\s*")([^"]*)("\s*\))/g;
128058
- REFERENCE_ID_PATTERN = /(Reference\s*\(\s*id\s*:\s*")([^"]*)(")/g;
128059
- QUOTED_STRING_PATTERN = /"([^"\n]*)"/g;
128060
- DERIVED_CACHE_PATHS = [
128061
- PROJECT_SOURCE_ANALYSIS_V4_CACHE_PATH,
128062
- PROJECT_SOURCE_BUILD_CACHE_PATH,
128063
- PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_PATH,
128064
- MATERIALIZED_CONSTRUCTION_BUILD_CACHE_PATH
128065
- ];
128066
- }
128067
- });
128068
-
128069
127716
  // src/commands/migrate.ts
128070
127717
  var migrate_exports = {};
128071
127718
  __export(migrate_exports, {
@@ -128076,8 +127723,8 @@ __export(migrate_exports, {
128076
127723
  runMigrate: () => runMigrate
128077
127724
  });
128078
127725
  import { randomUUID as randomUUID4 } from "node:crypto";
128079
- import { existsSync as existsSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync6, writeFileSync as writeFileSync13 } from "node:fs";
128080
- import { join as join18 } from "node:path";
127726
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync6, writeFileSync as writeFileSync12 } from "node:fs";
127727
+ import { join as join17 } from "node:path";
128081
127728
  async function runMigrate(workspace, subcommand, positional, targetRef, json, dependencies = {}) {
128082
127729
  if (subcommand === "new") {
128083
127730
  const name = positional[0];
@@ -128086,7 +127733,7 @@ async function runMigrate(workspace, subcommand, positional, targetRef, json, de
128086
127733
  "Usage: neo migrate new <name> [--target <ClassName|project>]"
128087
127734
  );
128088
127735
  }
128089
- const migrationsDir = join18(workspace.root, "Migrations");
127736
+ const migrationsDir = join17(workspace.root, "Migrations");
128090
127737
  mkdirSync12(migrationsDir, { recursive: true });
128091
127738
  let nextOrder = 1;
128092
127739
  if (existsSync15(migrationsDir)) {
@@ -128098,7 +127745,7 @@ async function runMigrate(workspace, subcommand, positional, targetRef, json, de
128098
127745
  }
128099
127746
  }
128100
127747
  const relPath = migrationFileName(nextOrder, name);
128101
- const absolute = join18(workspace.root, relPath);
127748
+ const absolute = join17(workspace.root, relPath);
128102
127749
  if (existsSync15(absolute)) {
128103
127750
  throw new Error(`"${relPath}" already exists.`);
128104
127751
  }
@@ -128110,18 +127757,11 @@ async function runMigrate(workspace, subcommand, positional, targetRef, json, de
128110
127757
  target === "project" ? "// Runs once with root context. Write the NeoScript action below." : `// Runs once per ${target} value; \`this\` is the instance.`,
128111
127758
  ""
128112
127759
  ].join("\n");
128113
- writeFileSync13(absolute, template, "utf8");
127760
+ writeFileSync12(absolute, template, "utf8");
128114
127761
  console.log(`Created ${relPath} \u2014 edit the action body, then "neo push".`);
128115
127762
  console.log("(The id is assigned at push, same as schema creates.)");
128116
127763
  return;
128117
127764
  }
128118
- if (subcommand === "rekey") {
128119
- await runMigrateRekey(workspace, {
128120
- ...dependencies.fetchCanonicalValueIdMappings === void 0 ? {} : { fetchMappings: dependencies.fetchCanonicalValueIdMappings },
128121
- ...dependencies.computeStatus === void 0 ? {} : { computeStatus: dependencies.computeStatus }
128122
- });
128123
- return;
128124
- }
128125
127765
  const { raw } = await (dependencies.fetchDocument ?? fetchProjectDocument)(
128126
127766
  workspace
128127
127767
  );
@@ -129244,7 +128884,6 @@ var init_migrate = __esm({
129244
128884
  init_virtual_instance_values();
129245
128885
  init_script();
129246
128886
  init_project_migration_created_values();
129247
- init_migrate_rekey();
129248
128887
  }
129249
128888
  });
129250
128889
 
@@ -129857,7 +129496,7 @@ __export(content_exports, {
129857
129496
  makeContentContext: () => makeContentContext,
129858
129497
  runLoc: () => runLoc
129859
129498
  });
129860
- import { readFileSync as readFileSync19 } from "node:fs";
129499
+ import { readFileSync as readFileSync18 } from "node:fs";
129861
129500
  import { randomUUID as randomUUID5 } from "node:crypto";
129862
129501
  function versionPath2(workspace, suffix) {
129863
129502
  return `/api/projects/${workspace.config.projectId}/versions/${workspace.config.versionId}/${suffix}`;
@@ -129865,9 +129504,9 @@ function versionPath2(workspace, suffix) {
129865
129504
  function readBatch(file) {
129866
129505
  let raw = null;
129867
129506
  if (file !== null) {
129868
- raw = readFileSync19(file, "utf8");
129507
+ raw = readFileSync18(file, "utf8");
129869
129508
  } else if (!process.stdin.isTTY) {
129870
- raw = readFileSync19(0, "utf8");
129509
+ raw = readFileSync18(0, "utf8");
129871
129510
  if (raw.trim().length === 0) raw = null;
129872
129511
  }
129873
129512
  if (raw === null) return null;
@@ -130899,8 +130538,8 @@ var export_exports = {};
130899
130538
  __export(export_exports, {
130900
130539
  runExportUnity: () => runExportUnity
130901
130540
  });
130902
- import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync14 } from "node:fs";
130903
- import { join as join19 } from "node:path";
130541
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "node:fs";
130542
+ import { join as join18 } from "node:path";
130904
130543
  async function runExportUnity(workspace, outDir) {
130905
130544
  if (outDir === null) {
130906
130545
  throw new Error(
@@ -130912,23 +130551,23 @@ async function runExportUnity(workspace, outDir) {
130912
130551
  `/api/projects/${workspace.config.projectId}/export`,
130913
130552
  { versionId: workspace.config.versionId }
130914
130553
  );
130915
- const resourcesDir = join19(outDir, "Resources", "Neo");
130916
- const localizationDir = join19(resourcesDir, "Localization");
130917
- const scriptsDir = join19(outDir, "Scripts", "Neo");
130554
+ const resourcesDir = join18(outDir, "Resources", "Neo");
130555
+ const localizationDir = join18(resourcesDir, "Localization");
130556
+ const scriptsDir = join18(outDir, "Scripts", "Neo");
130918
130557
  mkdirSync13(localizationDir, { recursive: true });
130919
130558
  mkdirSync13(scriptsDir, { recursive: true });
130920
- writeFileSync14(join19(resourcesDir, "project.json"), response.projectJson);
130921
- writeFileSync14(
130922
- join19(scriptsDir, "NeoGeneratedTypes.cs"),
130559
+ writeFileSync13(join18(resourcesDir, "project.json"), response.projectJson);
130560
+ writeFileSync13(
130561
+ join18(scriptsDir, "NeoGeneratedTypes.cs"),
130923
130562
  response.generatedTypes
130924
130563
  );
130925
130564
  for (const file of response.localizationFiles ?? []) {
130926
- writeFileSync14(join19(localizationDir, file.fileName), file.content);
130565
+ writeFileSync13(join18(localizationDir, file.fileName), file.content);
130927
130566
  }
130928
- console.log(`wrote ${join19(resourcesDir, "project.json")}`);
130929
- console.log(`wrote ${join19(scriptsDir, "NeoGeneratedTypes.cs")}`);
130567
+ console.log(`wrote ${join18(resourcesDir, "project.json")}`);
130568
+ console.log(`wrote ${join18(scriptsDir, "NeoGeneratedTypes.cs")}`);
130930
130569
  for (const file of response.localizationFiles ?? []) {
130931
- console.log(`wrote ${join19(localizationDir, file.fileName)}`);
130570
+ console.log(`wrote ${join18(localizationDir, file.fileName)}`);
130932
130571
  }
130933
130572
  const diagnostics = response.diagnostics ?? [];
130934
130573
  for (const diagnostic of diagnostics) {
@@ -130951,7 +130590,7 @@ __export(dev_exports, {
130951
130590
  runDev: () => runDev
130952
130591
  });
130953
130592
  import { watch } from "node:fs";
130954
- import { join as join20 } from "node:path";
130593
+ import { join as join19 } from "node:path";
130955
130594
  import { emitKeypressEvents } from "node:readline";
130956
130595
  import { ConvexClient } from "convex/browser";
130957
130596
  function isSchemaSignal(value) {
@@ -131061,7 +130700,7 @@ async function runDev(workspace, options) {
131061
130700
  };
131062
130701
  for (const dir of ["Classes", "Enums"]) {
131063
130702
  try {
131064
- watch(join20(workspace.root, dir), { persistent: true }, onFileChange);
130703
+ watch(join19(workspace.root, dir), { persistent: true }, onFileChange);
131065
130704
  } catch {
131066
130705
  }
131067
130706
  }
@@ -131116,16 +130755,16 @@ __export(resolve_exports, {
131116
130755
  runResolve: () => runResolve,
131117
130756
  workspaceFilePath: () => workspaceFilePath
131118
130757
  });
131119
- import { readFileSync as readFileSync20, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
131120
- import { join as join21 } from "node:path";
130758
+ import { readFileSync as readFileSync19, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "node:fs";
130759
+ import { join as join20 } from "node:path";
131121
130760
  function runResolve(workspace, side) {
131122
130761
  const resolvedRecords = adoptServerConflictBases(workspace);
131123
130762
  let resolvedFiles = 0;
131124
130763
  for (const filePath of listProjectSourceFilesV4(workspace.root)) {
131125
- const source = readFileSync20(filePath, "utf8");
130764
+ const source = readFileSync19(filePath, "utf8");
131126
130765
  if (detectConflictMarkers(source) === null) continue;
131127
130766
  const resolved = resolveMarkers(source, side);
131128
- writeFileSync15(filePath, resolved, "utf8");
130767
+ writeFileSync14(filePath, resolved, "utf8");
131129
130768
  resolvedFiles += 1;
131130
130769
  }
131131
130770
  let resolvedBinaries = 0;
@@ -131133,22 +130772,22 @@ function runResolve(workspace, side) {
131133
130772
  const binary = state.projectBinary;
131134
130773
  const conflict2 = binary?.conflict;
131135
130774
  if (binary === void 0 || conflict2 === void 0) continue;
131136
- const destination = join21(workspace.root, binary.path);
130775
+ const destination = join20(workspace.root, binary.path);
131137
130776
  if (side === "theirs") {
131138
130777
  if (conflict2.remoteSha256 !== null && conflict2.artifactPath !== void 0) {
131139
130778
  writeVerifiedBinaryDownloadV4(
131140
130779
  destination,
131141
- readFileSync20(join21(workspace.root, conflict2.artifactPath)),
130780
+ readFileSync19(join20(workspace.root, conflict2.artifactPath)),
131142
130781
  conflict2.remoteSha256
131143
130782
  );
131144
130783
  binary.sha256 = conflict2.remoteSha256;
131145
130784
  } else {
131146
- rmSync9(destination, { force: true });
130785
+ rmSync8(destination, { force: true });
131147
130786
  binary.sha256 = null;
131148
130787
  }
131149
130788
  }
131150
130789
  if (conflict2.artifactPath !== void 0) {
131151
- rmSync9(join21(workspace.root, conflict2.artifactPath), { force: true });
130790
+ rmSync8(join20(workspace.root, conflict2.artifactPath), { force: true });
131152
130791
  }
131153
130792
  delete binary.conflict;
131154
130793
  resolvedBinaries += 1;
@@ -131217,7 +130856,7 @@ function resolveMarkers(source, side) {
131217
130856
  return output.join("\n");
131218
130857
  }
131219
130858
  function workspaceFilePath(workspace, file) {
131220
- return join21(workspace.root, file);
130859
+ return join20(workspace.root, file);
131221
130860
  }
131222
130861
  var init_resolve = __esm({
131223
130862
  "src/commands/resolve.ts"() {
@@ -131288,7 +130927,7 @@ ${h("Content & scripts")}
131288
130927
  loc ${d("locales | list | set | create | delete | archive | restore | ...")}
131289
130928
  dialogue ${d("dryrun <ref> [--json]")}
131290
130929
  script ${d("check | eval | compile [--mode getter|action|setter|nsfunction] [--member <id-or-name>]")}
131291
- migrate ${d("new | list | check | run | prune | rekey")}
130930
+ migrate ${d("new | list | check | run | prune")}
131292
130931
  export ${d("unity [--out <path>]")}
131293
130932
 
131294
130933
  Run any command with missing arguments in a terminal and ${h("neo")} will ask.
@@ -131422,7 +131061,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
131422
131061
  async function main() {
131423
131062
  const args = parseArgs(process.argv.slice(2));
131424
131063
  if (args.command === "--version") {
131425
- console.log("0.41.0");
131064
+ console.log("0.42.1");
131426
131065
  return;
131427
131066
  }
131428
131067
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
@@ -131539,7 +131178,7 @@ async function main() {
131539
131178
  const sub = args.positional[0];
131540
131179
  if (sub === void 0) {
131541
131180
  throw new Error(
131542
- "neo migrate requires a subcommand: new | list | check | run | prune | rekey."
131181
+ "neo migrate requires a subcommand: new | list | check | run | prune."
131543
131182
  );
131544
131183
  }
131545
131184
  const { runMigrate: runMigrate2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.41.0",
3
+ "version": "0.42.1",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.41.0 -->
12
+ <!-- reviewed-through-cli: 0.42.1 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -83,7 +83,7 @@ wrappers.
83
83
  The marker near the top of `SKILL.md` must exactly match the package version:
84
84
 
85
85
  ```html
86
- <!-- reviewed-through-cli: 0.41.0 -->
86
+ <!-- reviewed-through-cli: 0.42.1 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -329,15 +329,5 @@ neo migrate run [--dry-run] [--skip-invalid]
329
329
  neo migrate prune
330
330
  ```
331
331
 
332
- `neo migrate rekey` is different: a one-time source refactor, not an action.
333
- After the server's canonical value-id migration, it reads the version's
334
- old-to-canonical id mapping, rewrites `@id` pins and `Reference(id: ...)`
335
- literals in tracked `.neo` and `.spec.neo` source, and moves `.neo/state.json`
336
- bases onto the new ids, so the next `pull` merges field by field instead of
337
- reporting every rekeyed value as a delete plus a create. It writes nothing
338
- while conflict markers or unresolved pull conflicts remain, when an old id
339
- survives outside those two positions, or when the rewrite would introduce a
340
- source error. A second run is a no-op.
341
-
342
332
  Run checks before migration execution. Review storage ownership and every write
343
333
  intent; do not assume an action body is writable merely because it compiled.