@neocompose/cli 0.41.0 → 0.42.0

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,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.42.0] - 2026-09-02
4
+
5
+ ### Fixed
6
+
7
+ - `neo pull --reset` and `neo pull --regenerate-source-names` rewrote every
8
+ dialogue binding to its type name. Binding names are derived from a value's
9
+ `Name` child, and the placement index read the pulled rows as stored rather
10
+ than expanding packed subtree storage first, so a packed `Name` resolved to
11
+ nothing and `Outpost CaelusAnchorpoint` came back as `Outpost Outpost`. Every
12
+ linked dialogue and node then showed up as an update in `neo status` whose
13
+ only difference was the regenerated name. The index now expands packed
14
+ children into the logical rows they are.
15
+ - `neo pull` left a member declared by more than one class disagreeing with
16
+ itself. A changed record was rewritten in the single file the emission
17
+ attributes it to, so a change to a shared member updated one class and
18
+ froze the others at their previously emitted text, and the next command
19
+ refused the CLI's own output with "Shared member id … has inconsistent
20
+ declarations." Pull now rewrites every file that declares a changed record.
21
+
22
+ ### Removed
23
+
24
+ - `neo migrate rekey`. The canonical value-id migration it served has run on
25
+ every deployment and the server no longer serves the old-to-canonical
26
+ mapping page it read, so the command had nothing left to rewrite.
27
+ `neo migrate` keeps `new | list | check | run | prune`.
28
+
3
29
  ## [0.41.0] - 2026-09-01
4
30
 
5
31
  ### 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
  );
@@ -70102,7 +70113,7 @@ function withEvaluationRuntime(ctx, writes) {
70102
70113
  ctx.__runtimeSessionValues
70103
70114
  );
70104
70115
  const referencesAlreadyRemapped = ctx.__valueOverlay !== void 0 && ctx.__runtimeReferenceRemap !== void 0;
70105
- const remap2 = (value) => referencesAlreadyRemapped ? value : remapRuntimeReferences(
70116
+ const remap = (value) => referencesAlreadyRemapped ? value : remapRuntimeReferences(
70106
70117
  value,
70107
70118
  overlay,
70108
70119
  referenceRemap,
@@ -70110,11 +70121,11 @@ function withEvaluationRuntime(ctx, writes) {
70110
70121
  );
70111
70122
  return {
70112
70123
  ...ctx,
70113
- thisValue: remap2(ctx.thisValue),
70114
- rootValue: remap2(ctx.rootValue),
70124
+ thisValue: remap(ctx.thisValue),
70125
+ rootValue: remap(ctx.rootValue),
70115
70126
  dialogueContext: ctx.dialogueContext === void 0 || ctx.dialogueContext === null ? ctx.dialogueContext : {
70116
- primary: remap2(ctx.dialogueContext.primary),
70117
- trigger: remap2(ctx.dialogueContext.trigger)
70127
+ primary: remap(ctx.dialogueContext.primary),
70128
+ trigger: remap(ctx.dialogueContext.trigger)
70118
70129
  },
70119
70130
  __runtimeSessionValues: runtimeSessionValues,
70120
70131
  __saveStaticBindings: ctx.__saveStaticBindings ?? staticBindingMap(ctx.saveStaticBindings),
@@ -79776,12 +79787,12 @@ function sparsifyConstructedInstance(args) {
79776
79787
  ) ?? virtualId
79777
79788
  );
79778
79789
  }
79779
- const remap2 = (value) => {
79790
+ const remap = (value) => {
79780
79791
  if (typeof value === "string") return nextIdById.get(value) ?? value;
79781
- if (Array.isArray(value)) return value.map(remap2);
79792
+ if (Array.isArray(value)) return value.map(remap);
79782
79793
  if (typeof value !== "object" || value === null) return value;
79783
79794
  return Object.fromEntries(
79784
- Object.entries(value).map(([key, entry]) => [key, remap2(entry)])
79795
+ Object.entries(value).map(([key, entry]) => [key, remap(entry)])
79785
79796
  );
79786
79797
  };
79787
79798
  const rewrite = (row) => {
@@ -79789,9 +79800,9 @@ function sparsifyConstructedInstance(args) {
79789
79800
  return {
79790
79801
  ...literal2,
79791
79802
  id: nextIdById.get(row.id) ?? row.id,
79792
- value: remap2(updatedValueById.get(row.id) ?? literal2.value),
79803
+ value: remap(updatedValueById.get(row.id) ?? literal2.value),
79793
79804
  ...literal2.constructorArgs === void 0 ? {} : {
79794
- constructorArgs: remap2(literal2.constructorArgs)
79805
+ constructorArgs: remap(literal2.constructorArgs)
79795
79806
  },
79796
79807
  ...typeof row.containerId === "string" ? { containerId: nextIdById.get(row.containerId) ?? row.containerId } : {}
79797
79808
  };
@@ -116639,20 +116650,20 @@ async function finishFormat4Pull(args) {
116639
116650
  ...[...conflictPaths].filter((path) => serverByPath.has(path)),
116640
116651
  ...authoredLocalConflictKeysByPath.keys()
116641
116652
  ]);
116653
+ const localRecordFiles = declaringSourcePathsV4(localResult);
116642
116654
  const rewritePaths = projectSourcePathsRequiringRewriteV4({
116643
116655
  destructive,
116644
116656
  localStatus,
116645
116657
  plans,
116646
- localRecordFiles: localResult.recordFiles,
116647
- serverRecordFiles: serverResult?.recordFiles ?? /* @__PURE__ */ new Map(),
116658
+ localRecordFiles,
116659
+ serverRecordFiles: serverResult === null ? /* @__PURE__ */ new Map() : declaringSourcePathsV4(serverResult),
116648
116660
  previousRecords: workspace.state.records,
116649
116661
  conflictPaths,
116650
116662
  emittedPaths,
116651
116663
  mainLocale: workspaceMainLocale(workspace.state.records)
116652
116664
  });
116653
116665
  for (const key of regeneratedRecordKeys) {
116654
- const path = localResult.recordFiles.get(key);
116655
- if (path !== void 0) rewritePaths.add(path);
116666
+ for (const path of localRecordFiles.get(key) ?? []) rewritePaths.add(path);
116656
116667
  }
116657
116668
  const resolveSourcePath = createWorkspaceSourcePathResolver(workspace.root);
116658
116669
  let written = 0;
@@ -116949,14 +116960,30 @@ function cursorsEqual(left, right) {
116949
116960
  (transactionId, index) => transactionId === right.transactionIds[index]
116950
116961
  );
116951
116962
  }
116963
+ function declaringSourcePathsV4(emission) {
116964
+ const paths = /* @__PURE__ */ new Map();
116965
+ const add = (key, path) => {
116966
+ const existing = paths.get(key);
116967
+ if (existing === void 0) {
116968
+ paths.set(key, [path]);
116969
+ return;
116970
+ }
116971
+ if (!existing.includes(path)) existing.push(path);
116972
+ };
116973
+ for (const file of emission.files) {
116974
+ for (const key of file.recordKeys) add(key, file.path);
116975
+ }
116976
+ for (const [key, path] of emission.recordFiles) add(key, path);
116977
+ return paths;
116978
+ }
116952
116979
  function projectSourcePathsRequiringRewriteV4(args) {
116953
116980
  if (args.destructive || args.localStatus === null) {
116954
116981
  return new Set(args.emittedPaths);
116955
116982
  }
116956
116983
  const result = new Set(args.conflictPaths);
116957
116984
  for (const [key, plan] of args.plans) {
116958
- const path = args.localRecordFiles.get(key) ?? args.serverRecordFiles.get(key);
116959
- if (path === void 0) continue;
116985
+ const paths = args.localRecordFiles.get(key) ?? args.serverRecordFiles.get(key);
116986
+ if (paths === void 0) continue;
116960
116987
  const local = args.localStatus.reconstructed.get(key)?.fullData;
116961
116988
  const kind = args.previousRecords[key]?.recordKind ?? key.split(":", 1)[0] ?? "";
116962
116989
  if (plan.emitData === void 0 ? local !== void 0 : local === void 0 || !sourceAuthoredRecordsSemanticallyEqual(
@@ -116965,7 +116992,7 @@ function projectSourcePathsRequiringRewriteV4(args) {
116965
116992
  local,
116966
116993
  args.mainLocale
116967
116994
  )) {
116968
- result.add(path);
116995
+ for (const path of paths) result.add(path);
116969
116996
  }
116970
116997
  }
116971
116998
  for (const [key, previous] of Object.entries(args.previousRecords)) {
@@ -124160,7 +124187,7 @@ var init_registry2 = __esm({
124160
124187
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
124161
124188
  formatVersion: 4,
124162
124189
  contractVersion: "4.1",
124163
- cliVersion: "0.41.0",
124190
+ cliVersion: "0.42.0",
124164
124191
  projectFileUploadBatchSize: 32,
124165
124192
  documentRecords: {
124166
124193
  member: {
@@ -127632,440 +127659,6 @@ var init_doctor = __esm({
127632
127659
  }
127633
127660
  });
127634
127661
 
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
127662
  // src/commands/migrate.ts
128070
127663
  var migrate_exports = {};
128071
127664
  __export(migrate_exports, {
@@ -128076,8 +127669,8 @@ __export(migrate_exports, {
128076
127669
  runMigrate: () => runMigrate
128077
127670
  });
128078
127671
  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";
127672
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync6, writeFileSync as writeFileSync12 } from "node:fs";
127673
+ import { join as join17 } from "node:path";
128081
127674
  async function runMigrate(workspace, subcommand, positional, targetRef, json, dependencies = {}) {
128082
127675
  if (subcommand === "new") {
128083
127676
  const name = positional[0];
@@ -128086,7 +127679,7 @@ async function runMigrate(workspace, subcommand, positional, targetRef, json, de
128086
127679
  "Usage: neo migrate new <name> [--target <ClassName|project>]"
128087
127680
  );
128088
127681
  }
128089
- const migrationsDir = join18(workspace.root, "Migrations");
127682
+ const migrationsDir = join17(workspace.root, "Migrations");
128090
127683
  mkdirSync12(migrationsDir, { recursive: true });
128091
127684
  let nextOrder = 1;
128092
127685
  if (existsSync15(migrationsDir)) {
@@ -128098,7 +127691,7 @@ async function runMigrate(workspace, subcommand, positional, targetRef, json, de
128098
127691
  }
128099
127692
  }
128100
127693
  const relPath = migrationFileName(nextOrder, name);
128101
- const absolute = join18(workspace.root, relPath);
127694
+ const absolute = join17(workspace.root, relPath);
128102
127695
  if (existsSync15(absolute)) {
128103
127696
  throw new Error(`"${relPath}" already exists.`);
128104
127697
  }
@@ -128110,18 +127703,11 @@ async function runMigrate(workspace, subcommand, positional, targetRef, json, de
128110
127703
  target === "project" ? "// Runs once with root context. Write the NeoScript action below." : `// Runs once per ${target} value; \`this\` is the instance.`,
128111
127704
  ""
128112
127705
  ].join("\n");
128113
- writeFileSync13(absolute, template, "utf8");
127706
+ writeFileSync12(absolute, template, "utf8");
128114
127707
  console.log(`Created ${relPath} \u2014 edit the action body, then "neo push".`);
128115
127708
  console.log("(The id is assigned at push, same as schema creates.)");
128116
127709
  return;
128117
127710
  }
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
127711
  const { raw } = await (dependencies.fetchDocument ?? fetchProjectDocument)(
128126
127712
  workspace
128127
127713
  );
@@ -129244,7 +128830,6 @@ var init_migrate = __esm({
129244
128830
  init_virtual_instance_values();
129245
128831
  init_script();
129246
128832
  init_project_migration_created_values();
129247
- init_migrate_rekey();
129248
128833
  }
129249
128834
  });
129250
128835
 
@@ -129857,7 +129442,7 @@ __export(content_exports, {
129857
129442
  makeContentContext: () => makeContentContext,
129858
129443
  runLoc: () => runLoc
129859
129444
  });
129860
- import { readFileSync as readFileSync19 } from "node:fs";
129445
+ import { readFileSync as readFileSync18 } from "node:fs";
129861
129446
  import { randomUUID as randomUUID5 } from "node:crypto";
129862
129447
  function versionPath2(workspace, suffix) {
129863
129448
  return `/api/projects/${workspace.config.projectId}/versions/${workspace.config.versionId}/${suffix}`;
@@ -129865,9 +129450,9 @@ function versionPath2(workspace, suffix) {
129865
129450
  function readBatch(file) {
129866
129451
  let raw = null;
129867
129452
  if (file !== null) {
129868
- raw = readFileSync19(file, "utf8");
129453
+ raw = readFileSync18(file, "utf8");
129869
129454
  } else if (!process.stdin.isTTY) {
129870
- raw = readFileSync19(0, "utf8");
129455
+ raw = readFileSync18(0, "utf8");
129871
129456
  if (raw.trim().length === 0) raw = null;
129872
129457
  }
129873
129458
  if (raw === null) return null;
@@ -130899,8 +130484,8 @@ var export_exports = {};
130899
130484
  __export(export_exports, {
130900
130485
  runExportUnity: () => runExportUnity
130901
130486
  });
130902
- import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync14 } from "node:fs";
130903
- import { join as join19 } from "node:path";
130487
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "node:fs";
130488
+ import { join as join18 } from "node:path";
130904
130489
  async function runExportUnity(workspace, outDir) {
130905
130490
  if (outDir === null) {
130906
130491
  throw new Error(
@@ -130912,23 +130497,23 @@ async function runExportUnity(workspace, outDir) {
130912
130497
  `/api/projects/${workspace.config.projectId}/export`,
130913
130498
  { versionId: workspace.config.versionId }
130914
130499
  );
130915
- const resourcesDir = join19(outDir, "Resources", "Neo");
130916
- const localizationDir = join19(resourcesDir, "Localization");
130917
- const scriptsDir = join19(outDir, "Scripts", "Neo");
130500
+ const resourcesDir = join18(outDir, "Resources", "Neo");
130501
+ const localizationDir = join18(resourcesDir, "Localization");
130502
+ const scriptsDir = join18(outDir, "Scripts", "Neo");
130918
130503
  mkdirSync13(localizationDir, { recursive: true });
130919
130504
  mkdirSync13(scriptsDir, { recursive: true });
130920
- writeFileSync14(join19(resourcesDir, "project.json"), response.projectJson);
130921
- writeFileSync14(
130922
- join19(scriptsDir, "NeoGeneratedTypes.cs"),
130505
+ writeFileSync13(join18(resourcesDir, "project.json"), response.projectJson);
130506
+ writeFileSync13(
130507
+ join18(scriptsDir, "NeoGeneratedTypes.cs"),
130923
130508
  response.generatedTypes
130924
130509
  );
130925
130510
  for (const file of response.localizationFiles ?? []) {
130926
- writeFileSync14(join19(localizationDir, file.fileName), file.content);
130511
+ writeFileSync13(join18(localizationDir, file.fileName), file.content);
130927
130512
  }
130928
- console.log(`wrote ${join19(resourcesDir, "project.json")}`);
130929
- console.log(`wrote ${join19(scriptsDir, "NeoGeneratedTypes.cs")}`);
130513
+ console.log(`wrote ${join18(resourcesDir, "project.json")}`);
130514
+ console.log(`wrote ${join18(scriptsDir, "NeoGeneratedTypes.cs")}`);
130930
130515
  for (const file of response.localizationFiles ?? []) {
130931
- console.log(`wrote ${join19(localizationDir, file.fileName)}`);
130516
+ console.log(`wrote ${join18(localizationDir, file.fileName)}`);
130932
130517
  }
130933
130518
  const diagnostics = response.diagnostics ?? [];
130934
130519
  for (const diagnostic of diagnostics) {
@@ -130951,7 +130536,7 @@ __export(dev_exports, {
130951
130536
  runDev: () => runDev
130952
130537
  });
130953
130538
  import { watch } from "node:fs";
130954
- import { join as join20 } from "node:path";
130539
+ import { join as join19 } from "node:path";
130955
130540
  import { emitKeypressEvents } from "node:readline";
130956
130541
  import { ConvexClient } from "convex/browser";
130957
130542
  function isSchemaSignal(value) {
@@ -131061,7 +130646,7 @@ async function runDev(workspace, options) {
131061
130646
  };
131062
130647
  for (const dir of ["Classes", "Enums"]) {
131063
130648
  try {
131064
- watch(join20(workspace.root, dir), { persistent: true }, onFileChange);
130649
+ watch(join19(workspace.root, dir), { persistent: true }, onFileChange);
131065
130650
  } catch {
131066
130651
  }
131067
130652
  }
@@ -131116,16 +130701,16 @@ __export(resolve_exports, {
131116
130701
  runResolve: () => runResolve,
131117
130702
  workspaceFilePath: () => workspaceFilePath
131118
130703
  });
131119
- import { readFileSync as readFileSync20, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
131120
- import { join as join21 } from "node:path";
130704
+ import { readFileSync as readFileSync19, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "node:fs";
130705
+ import { join as join20 } from "node:path";
131121
130706
  function runResolve(workspace, side) {
131122
130707
  const resolvedRecords = adoptServerConflictBases(workspace);
131123
130708
  let resolvedFiles = 0;
131124
130709
  for (const filePath of listProjectSourceFilesV4(workspace.root)) {
131125
- const source = readFileSync20(filePath, "utf8");
130710
+ const source = readFileSync19(filePath, "utf8");
131126
130711
  if (detectConflictMarkers(source) === null) continue;
131127
130712
  const resolved = resolveMarkers(source, side);
131128
- writeFileSync15(filePath, resolved, "utf8");
130713
+ writeFileSync14(filePath, resolved, "utf8");
131129
130714
  resolvedFiles += 1;
131130
130715
  }
131131
130716
  let resolvedBinaries = 0;
@@ -131133,22 +130718,22 @@ function runResolve(workspace, side) {
131133
130718
  const binary = state.projectBinary;
131134
130719
  const conflict2 = binary?.conflict;
131135
130720
  if (binary === void 0 || conflict2 === void 0) continue;
131136
- const destination = join21(workspace.root, binary.path);
130721
+ const destination = join20(workspace.root, binary.path);
131137
130722
  if (side === "theirs") {
131138
130723
  if (conflict2.remoteSha256 !== null && conflict2.artifactPath !== void 0) {
131139
130724
  writeVerifiedBinaryDownloadV4(
131140
130725
  destination,
131141
- readFileSync20(join21(workspace.root, conflict2.artifactPath)),
130726
+ readFileSync19(join20(workspace.root, conflict2.artifactPath)),
131142
130727
  conflict2.remoteSha256
131143
130728
  );
131144
130729
  binary.sha256 = conflict2.remoteSha256;
131145
130730
  } else {
131146
- rmSync9(destination, { force: true });
130731
+ rmSync8(destination, { force: true });
131147
130732
  binary.sha256 = null;
131148
130733
  }
131149
130734
  }
131150
130735
  if (conflict2.artifactPath !== void 0) {
131151
- rmSync9(join21(workspace.root, conflict2.artifactPath), { force: true });
130736
+ rmSync8(join20(workspace.root, conflict2.artifactPath), { force: true });
131152
130737
  }
131153
130738
  delete binary.conflict;
131154
130739
  resolvedBinaries += 1;
@@ -131217,7 +130802,7 @@ function resolveMarkers(source, side) {
131217
130802
  return output.join("\n");
131218
130803
  }
131219
130804
  function workspaceFilePath(workspace, file) {
131220
- return join21(workspace.root, file);
130805
+ return join20(workspace.root, file);
131221
130806
  }
131222
130807
  var init_resolve = __esm({
131223
130808
  "src/commands/resolve.ts"() {
@@ -131288,7 +130873,7 @@ ${h("Content & scripts")}
131288
130873
  loc ${d("locales | list | set | create | delete | archive | restore | ...")}
131289
130874
  dialogue ${d("dryrun <ref> [--json]")}
131290
130875
  script ${d("check | eval | compile [--mode getter|action|setter|nsfunction] [--member <id-or-name>]")}
131291
- migrate ${d("new | list | check | run | prune | rekey")}
130876
+ migrate ${d("new | list | check | run | prune")}
131292
130877
  export ${d("unity [--out <path>]")}
131293
130878
 
131294
130879
  Run any command with missing arguments in a terminal and ${h("neo")} will ask.
@@ -131422,7 +131007,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
131422
131007
  async function main() {
131423
131008
  const args = parseArgs(process.argv.slice(2));
131424
131009
  if (args.command === "--version") {
131425
- console.log("0.41.0");
131010
+ console.log("0.42.0");
131426
131011
  return;
131427
131012
  }
131428
131013
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
@@ -131539,7 +131124,7 @@ async function main() {
131539
131124
  const sub = args.positional[0];
131540
131125
  if (sub === void 0) {
131541
131126
  throw new Error(
131542
- "neo migrate requires a subcommand: new | list | check | run | prune | rekey."
131127
+ "neo migrate requires a subcommand: new | list | check | run | prune."
131543
131128
  );
131544
131129
  }
131545
131130
  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.0",
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.0 -->
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.0 -->
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.