@neocompose/cli 0.7.5 → 0.8.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
@@ -7,6 +7,13 @@
7
7
  - Document the final relation-only world layer-link contract and keep the
8
8
  format-4 Hello World corpus free of the retired value-side binding field.
9
9
 
10
+ ## [0.7.6] - 2026-07-22
11
+
12
+ ### Fixed
13
+
14
+ - Regenerate readable NeoFlow source names during force and reset pulls, and
15
+ allow explicit regeneration during a normal pull.
16
+
10
17
  ## [0.7.5] - 2026-07-22
11
18
 
12
19
  ### Fixed
package/README.md CHANGED
@@ -338,7 +338,7 @@ neo dialogue new CapitolColdBoot --primary Outpost=Assets.Capitol --group Capito
338
338
  | `login` / `whoami` | Authenticate and inspect the selected profile. |
339
339
  | `init --project <id> [--version <id>]` | Create a format-4 working copy and perform its first reset pull. |
340
340
  | `doctor` | Validate format/compiler/editor/source/file contracts; no .NET discovery. |
341
- | `pull [--force\|--reset]` | Merge remote changes or regenerate canonical source and binaries. |
341
+ | `pull [--force\|--reset] [--regenerate-source-names]` | Merge remote changes or regenerate canonical source, names, and binaries. |
342
342
  | `status [--json]` / `diff [--json]` | Compile source and show semantic records, spans, digests, and upload intent. |
343
343
  | `push [--dry-run] [--accept-bump]` | Validate or commit one atomic compare-and-swap transaction. |
344
344
  | `dev [--push]` | Watch remote/local changes; pushing remains opt-in. |
@@ -362,12 +362,12 @@ security boundary.
362
362
 
363
363
  ## Regenerating dialogue source names
364
364
 
365
- Normal pull preserves source filenames and symbols by stable record ID. To
366
- deliberately replace older machine-generated dialogue names with readable
367
- names derived from the editor, run:
365
+ Normal pull preserves source filenames and symbols by stable record ID. Force
366
+ and reset pulls always derive readable dialogue names from authoritative
367
+ records. To deliberately refresh those names during a normal merge, run:
368
368
 
369
369
  ```sh
370
- neo pull --reset --regenerate-source-names
370
+ neo pull --regenerate-source-names
371
371
  neo status
372
372
  neo push --dry-run
373
373
  ```
package/dist/neo.mjs CHANGED
@@ -11812,7 +11812,7 @@ var init_project_schema_contract_generated = __esm({
11812
11812
  "../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
11813
11813
  "use strict";
11814
11814
  PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
11815
- PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.3";
11815
+ PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.4";
11816
11816
  NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
11817
11817
  "recordFields": {
11818
11818
  "member": [
@@ -12041,11 +12041,13 @@ var init_project_schema_contract_generated = __esm({
12041
12041
  "Audio",
12042
12042
  "Generic"
12043
12043
  ],
12044
- "NeoSystemDisallowedOperation": [
12045
- "EditRecord",
12046
- "DeleteRecord",
12047
- "SelectRecord",
12048
- "ReplaceValue"
12044
+ "NeoSystemProtectionKind": [
12045
+ "WorldAuthoring",
12046
+ "DialogueMemorySchema",
12047
+ "DialogueMemoryContainer",
12048
+ "DialoguePriorityDefault",
12049
+ "PolicyImmutable",
12050
+ "PolicyDeleteBlocked"
12049
12051
  ],
12050
12052
  "NeoWorldKind": [
12051
12053
  "None",
@@ -12354,23 +12356,17 @@ var init_project_schema_contract_generated = __esm({
12354
12356
  ],
12355
12357
  "constructor": [
12356
12358
  {
12357
- "type": "NeoSystemDisallowedOperation[]",
12358
- "name": "disallow",
12359
- "modifier": "params",
12360
- "assigns": "Disallow"
12359
+ "type": "NeoSystemProtectionKind",
12360
+ "name": "kind",
12361
+ "assigns": "Kind"
12361
12362
  }
12362
12363
  ],
12363
12364
  "properties": [
12364
12365
  {
12365
- "type": "NeoSystemDisallowedOperation[]",
12366
- "name": "Disallow",
12366
+ "type": "NeoSystemProtectionKind",
12367
+ "name": "Kind",
12367
12368
  "access": "get"
12368
12369
  },
12369
- {
12370
- "type": "string?",
12371
- "name": "Reason",
12372
- "access": "set"
12373
- },
12374
12370
  {
12375
12371
  "type": "NeoWorldKind",
12376
12372
  "name": "WorldKind",
@@ -13257,13 +13253,9 @@ var init_project_schema_contract_generated = __esm({
13257
13253
  "constructors": [],
13258
13254
  "properties": [
13259
13255
  {
13260
- "type": "IReadOnlyList<NeoSystemDisallowedOperation>",
13261
- "name": "Disallow",
13262
- "default": "new List<NeoSystemDisallowedOperation>()"
13263
- },
13264
- {
13265
- "type": "string?",
13266
- "name": "Reason"
13256
+ "type": "NeoSystemProtectionKind",
13257
+ "name": "Kind",
13258
+ "default": "NeoSystemProtectionKind.WorldAuthoring"
13267
13259
  },
13268
13260
  {
13269
13261
  "type": "NeoWorldKind?",
@@ -22797,8 +22789,7 @@ function documentValuesEqual(left, right) {
22797
22789
  function systemToDocument(system) {
22798
22790
  if (system === null) return void 0;
22799
22791
  return omitUndefined({
22800
- disallow: system.disallow,
22801
- reason: system.reason ?? void 0,
22792
+ kind: system.kind,
22802
22793
  worldKind: system.worldKind ?? void 0
22803
22794
  });
22804
22795
  }
@@ -23152,12 +23143,8 @@ function jsonValue(value, record3, path) {
23152
23143
  function systemFromDocument(value, record3, path) {
23153
23144
  if (value === null || value === void 0) return null;
23154
23145
  const system = requireRecordValue(value, record3, path);
23155
- const disallow = optionalArray(system.disallow).map(
23156
- (entry, index) => requiredStringValue(entry, record3, `${path}.disallow[${index}]`)
23157
- );
23158
23146
  const candidate = {
23159
- disallow,
23160
- reason: optionalStringOrNull(system.reason),
23147
+ kind: requiredStringValue(system.kind, record3, `${path}.kind`),
23161
23148
  worldKind: optionalStringOrNull(system.worldKind)
23162
23149
  };
23163
23150
  if (!isSchemaSystemMetadata(candidate)) {
@@ -23167,11 +23154,13 @@ function systemFromDocument(value, record3, path) {
23167
23154
  }
23168
23155
  function isSchemaSystemMetadata(value) {
23169
23156
  if (!isRecord2(value)) return false;
23170
- const operations = /* @__PURE__ */ new Set([
23171
- "editRecord",
23172
- "deleteRecord",
23173
- "selectRecord",
23174
- "replaceValue"
23157
+ const kinds = /* @__PURE__ */ new Set([
23158
+ "worldAuthoring",
23159
+ "dialogueMemorySchema",
23160
+ "dialogueMemoryContainer",
23161
+ "dialoguePriorityDefault",
23162
+ "policyImmutable",
23163
+ "policyDeleteBlocked"
23175
23164
  ]);
23176
23165
  const worlds = /* @__PURE__ */ new Set([
23177
23166
  "tileGrid",
@@ -23192,9 +23181,7 @@ function isSchemaSystemMetadata(value) {
23192
23181
  "smartTileRule",
23193
23182
  "smartTileNeighbor"
23194
23183
  ]);
23195
- return Array.isArray(value.disallow) && value.disallow.every(
23196
- (entry) => typeof entry === "string" && operations.has(entry)
23197
- ) && (value.reason === null || typeof value.reason === "string") && (value.worldKind === null || typeof value.worldKind === "string" && worlds.has(value.worldKind));
23184
+ return typeof value.kind === "string" && kinds.has(value.kind) && (value.worldKind === null || typeof value.worldKind === "string" && worlds.has(value.worldKind));
23198
23185
  }
23199
23186
  function genericBindingsFromDocument(value, record3, path) {
23200
23187
  if (value === void 0 || value === null) return {};
@@ -25019,11 +25006,8 @@ function assertPosition(value, path) {
25019
25006
  }
25020
25007
  function assertSystem(value, path) {
25021
25008
  if (value === null) return;
25022
- const system = objectAt(value, path, ["disallow", "reason", "worldKind"]);
25023
- arrayOf(system.disallow, `${path}.disallow`, (entry, entryPath) => {
25024
- stringIn(entry, SYSTEM_OPERATIONS, entryPath);
25025
- });
25026
- nullableString2(system.reason, `${path}.reason`);
25009
+ const system = objectAt(value, path, ["kind", "worldKind"]);
25010
+ stringIn(system.kind, SYSTEM_PROTECTION_KINDS, `${path}.kind`);
25027
25011
  if (system.worldKind !== null) {
25028
25012
  stringIn(system.worldKind, WORLD_KINDS, `${path}.worldKind`);
25029
25013
  }
@@ -26243,7 +26227,7 @@ function exactValue(value, expected, path) {
26243
26227
  function invalid(path, message) {
26244
26228
  throw new ProjectSchemaManifestValidationError(path, message);
26245
26229
  }
26246
- var ProjectSchemaManifestValidationError, WORLD_RELATION_CONTRACTS, MANIFEST_ENDPOINT_KINDS, PROJECT_RECORD_KINDS, SOURCE_KINDS, SYSTEM_OPERATIONS, WORLD_KINDS, MEMBER_COMMON_KEYS, MEMBER_KEYS_BY_KIND, PRIMITIVE_TYPE_KINDS, TEXTURE_TYPES, ALPHA_SOURCES, NPOT_SCALES, WRAP_MODES, RESIZE_ALGORITHMS, TEXTURE_COMPRESSIONS, PLATFORM_FORMATS, SPRITE_ALIGNMENTS;
26230
+ var ProjectSchemaManifestValidationError, WORLD_RELATION_CONTRACTS, MANIFEST_ENDPOINT_KINDS, PROJECT_RECORD_KINDS, SOURCE_KINDS, SYSTEM_PROTECTION_KINDS, WORLD_KINDS, MEMBER_COMMON_KEYS, MEMBER_KEYS_BY_KIND, PRIMITIVE_TYPE_KINDS, TEXTURE_TYPES, ALPHA_SOURCES, NPOT_SCALES, WRAP_MODES, RESIZE_ALGORITHMS, TEXTURE_COMPRESSIONS, PLATFORM_FORMATS, SPRITE_ALIGNMENTS;
26247
26231
  var init_validate = __esm({
26248
26232
  "src/project-manifest/validate.ts"() {
26249
26233
  "use strict";
@@ -26404,11 +26388,13 @@ var init_validate = __esm({
26404
26388
  "localizationStatus",
26405
26389
  "internalRecordRelation"
26406
26390
  ]);
26407
- SYSTEM_OPERATIONS = /* @__PURE__ */ new Set([
26408
- "editRecord",
26409
- "deleteRecord",
26410
- "selectRecord",
26411
- "replaceValue"
26391
+ SYSTEM_PROTECTION_KINDS = /* @__PURE__ */ new Set([
26392
+ "worldAuthoring",
26393
+ "dialogueMemorySchema",
26394
+ "dialogueMemoryContainer",
26395
+ "dialoguePriorityDefault",
26396
+ "policyImmutable",
26397
+ "policyDeleteBlocked"
26412
26398
  ]);
26413
26399
  WORLD_KINDS = /* @__PURE__ */ new Set([
26414
26400
  "tileGrid",
@@ -27022,15 +27008,13 @@ function contextualEnumArgument(value, name) {
27022
27008
  function systemMetadata(annotations) {
27023
27009
  const system = annotation(annotations, "system");
27024
27010
  if (!system) return null;
27025
- const disallowRaw = argument(system, "disallow");
27026
- const disallow = disallowRaw ? parseExpression(disallowRaw) : null;
27027
- const operations = disallow?.kind === "litList" ? disallow.elements.filter(
27028
- (entry) => entry.kind === "contextualEnum"
27029
- ).map((entry) => lowerFirst2(entry.name)) : [];
27011
+ const kind = contextualEnumArgument(system, "kind");
27012
+ if (kind === null) {
27013
+ throw new Error("@system requires a kind inferred enum argument.");
27014
+ }
27030
27015
  const worldKind = contextualEnumArgument(system, "worldKind");
27031
27016
  return {
27032
- disallow: operations,
27033
- reason: stringArgument(system, "reason"),
27017
+ kind: lowerFirst2(kind),
27034
27018
  worldKind: worldKind ? lowerFirst2(worldKind) : null
27035
27019
  };
27036
27020
  }
@@ -30753,11 +30737,8 @@ function genericName(context, idValue) {
30753
30737
  }
30754
30738
  function systemAnnotation(system) {
30755
30739
  const args = [
30756
- ...system.worldKind ? [`worldKind: .${enumCase(system.worldKind)}`] : [],
30757
- ...system.disallow.length ? [
30758
- `disallow: [${system.disallow.map((entry) => `.${enumCase(entry)}`).join(", ")}]`
30759
- ] : [],
30760
- ...system.reason ? [`reason: ${quote(system.reason)}`] : []
30740
+ `kind: .${enumCase(system.kind)}`,
30741
+ ...system.worldKind ? [`worldKind: .${enumCase(system.worldKind)}`] : []
30761
30742
  ];
30762
30743
  return `@system(${args.join(", ")})`;
30763
30744
  }
@@ -32846,15 +32827,12 @@ function reference(value, names, type) {
32846
32827
  return names.get(value) ?? `Reference<${type}>(id: ${quote2(value)})`;
32847
32828
  }
32848
32829
  function emitSystemAnnotation(system) {
32849
- const disallow = Array.isArray(system.disallow) ? system.disallow.filter(
32850
- (entry) => typeof entry === "string"
32851
- ) : [];
32830
+ if (typeof system.kind !== "string") {
32831
+ throw new Error("System metadata requires a protection kind.");
32832
+ }
32852
32833
  const args = [
32853
- ...typeof system.worldKind === "string" ? [`worldKind: .${enumCase2(system.worldKind)}`] : [],
32854
- ...disallow.length > 0 ? [
32855
- `disallow: [${disallow.map((entry) => `.${enumCase2(entry)}`).join(", ")}]`
32856
- ] : [],
32857
- ...typeof system.reason === "string" ? [`reason: ${quote2(system.reason)}`] : []
32834
+ `kind: .${enumCase2(system.kind)}`,
32835
+ ...typeof system.worldKind === "string" ? [`worldKind: .${enumCase2(system.worldKind)}`] : []
32858
32836
  ];
32859
32837
  return `@system(${args.join(", ")})`;
32860
32838
  }
@@ -32867,26 +32845,16 @@ function lowerSystemMetadata(annotations) {
32867
32845
  )?.expression;
32868
32846
  return raw === void 0 ? void 0 : parseExpression(raw);
32869
32847
  };
32870
- const disallowExpression = argument2("disallow");
32871
- const disallow = disallowExpression?.kind === "litList" ? disallowExpression.elements.map((entry) => {
32872
- if (entry.kind !== "contextualEnum") {
32873
- throw new Error("@system disallow entries must be inferred enums.");
32874
- }
32875
- return lowerFirst3(entry.name);
32876
- }) : [];
32877
- const reasonExpression = argument2("reason");
32878
- const worldKindExpression = argument2("worldKind");
32879
- if (reasonExpression !== void 0 && reasonExpression.kind !== "litString" && reasonExpression.kind !== "litNull") {
32880
- throw new Error("@system reason must be a string or null.");
32848
+ const kindExpression = argument2("kind");
32849
+ if (kindExpression?.kind !== "contextualEnum") {
32850
+ throw new Error("@system kind must be an inferred enum.");
32881
32851
  }
32852
+ const worldKindExpression = argument2("worldKind");
32882
32853
  if (worldKindExpression !== void 0 && worldKindExpression.kind !== "contextualEnum" && worldKindExpression.kind !== "litNull") {
32883
32854
  throw new Error("@system worldKind must be an inferred enum or null.");
32884
32855
  }
32885
32856
  return {
32886
- ...disallowExpression === void 0 ? {} : { disallow },
32887
- ...reasonExpression === void 0 ? {} : {
32888
- reason: reasonExpression.kind === "litString" ? reasonExpression.value : null
32889
- },
32857
+ kind: lowerFirst3(kindExpression.name),
32890
32858
  ...worldKindExpression === void 0 ? {} : {
32891
32859
  worldKind: worldKindExpression.kind === "contextualEnum" ? lowerFirst3(worldKindExpression.name) : null
32892
32860
  }
@@ -32949,8 +32917,8 @@ function isEpochMillis(value) {
32949
32917
  if (typeof value !== "number") return false;
32950
32918
  return Number.isFinite(value);
32951
32919
  }
32952
- function isSystemDisallowedOperation(value) {
32953
- return value === SystemDisallowedOperation.EditRecord || value === SystemDisallowedOperation.DeleteRecord || value === SystemDisallowedOperation.SelectRecord || value === SystemDisallowedOperation.ReplaceValue;
32920
+ function isSystemProtectionKind(value) {
32921
+ return value === SystemProtectionKind.WorldAuthoring || value === SystemProtectionKind.DialogueMemorySchema || value === SystemProtectionKind.DialogueMemoryContainer || value === SystemProtectionKind.DialoguePriorityDefault || value === SystemProtectionKind.PolicyImmutable || value === SystemProtectionKind.PolicyDeleteBlocked;
32954
32922
  }
32955
32923
  function isNeoWorldSystemClassKind(value) {
32956
32924
  return value === NeoWorldSystemClassKind.TileGrid || value === NeoWorldSystemClassKind.TileLayer || value === NeoWorldSystemClassKind.ObjectLayer || value === NeoWorldSystemClassKind.Tile || value === NeoWorldSystemClassKind.ObjectBase || value === NeoWorldSystemClassKind.LayerGroupBase || value === NeoWorldSystemClassKind.SpriteObject || value === NeoWorldSystemClassKind.Object || value === NeoWorldSystemClassKind.TileLayerLink || value === NeoWorldSystemClassKind.ObjectLayerLink || value === NeoWorldSystemClassKind.ObjectPlacementTile || value === NeoWorldSystemClassKind.TileInstance || value === NeoWorldSystemClassKind.ObjectCollider || value === NeoWorldSystemClassKind.SortingLayer || value === NeoWorldSystemClassKind.SmartTile || value === NeoWorldSystemClassKind.SmartTileRule || value === NeoWorldSystemClassKind.SmartTileNeighbor;
@@ -32959,11 +32927,7 @@ function isSystemMetadata(value) {
32959
32927
  const v = value;
32960
32928
  if (typeof v !== "object") return false;
32961
32929
  if (v === null) return false;
32962
- if (!Array.isArray(v.disallow)) return false;
32963
- if (!v.disallow.every(isSystemDisallowedOperation)) return false;
32964
- if (v.reason !== void 0 && v.reason !== null) {
32965
- if (typeof v.reason !== "string") return false;
32966
- }
32930
+ if (!isSystemProtectionKind(v.kind)) return false;
32967
32931
  if (v.worldKind !== void 0 && v.worldKind !== null) {
32968
32932
  return isNeoWorldSystemClassKind(v.worldKind);
32969
32933
  }
@@ -32972,27 +32936,17 @@ function isSystemMetadata(value) {
32972
32936
  function isWithName(value) {
32973
32937
  return typeof value?.name === "string";
32974
32938
  }
32975
- var SystemDisallowedOperation, NeoWorldSystemClassKind;
32939
+ var SystemProtectionKind, NeoWorldSystemClassKind;
32976
32940
  var init_core_types = __esm({
32977
32941
  "../src/models/core/core-types.ts"() {
32978
32942
  "use strict";
32979
- SystemDisallowedOperation = {
32980
- /**
32981
- * Blocks project-author edits to the record's schema/configuration.
32982
- */
32983
- EditRecord: "editRecord",
32984
- /**
32985
- * Blocks project-author deletion of the record.
32986
- */
32987
- DeleteRecord: "deleteRecord",
32988
- /**
32989
- * Removes the record from normal creation/selection affordances.
32990
- */
32991
- SelectRecord: "selectRecord",
32992
- /**
32993
- * Blocks replacing the value row attached to a member as a whole.
32994
- */
32995
- ReplaceValue: "replaceValue"
32943
+ SystemProtectionKind = {
32944
+ WorldAuthoring: "worldAuthoring",
32945
+ DialogueMemorySchema: "dialogueMemorySchema",
32946
+ DialogueMemoryContainer: "dialogueMemoryContainer",
32947
+ DialoguePriorityDefault: "dialoguePriorityDefault",
32948
+ PolicyImmutable: "policyImmutable",
32949
+ PolicyDeleteBlocked: "policyDeleteBlocked"
32996
32950
  };
32997
32951
  NeoWorldSystemClassKind = {
32998
32952
  TileGrid: "tileGrid",
@@ -48051,11 +48005,6 @@ import {
48051
48005
  } from "node:fs";
48052
48006
  import { dirname as dirname5, join as join8 } from "node:path";
48053
48007
  async function runPull(workspace, options) {
48054
- if (options.regenerateSourceNames && !options.reset) {
48055
- throw new Error(
48056
- "--regenerate-source-names requires --reset because source-name regeneration rewrites the managed source tree."
48057
- );
48058
- }
48059
48008
  const destructive = options.force || options.reset;
48060
48009
  const hasBaseline = Object.keys(workspace.state.records).length > 0;
48061
48010
  let localByKey = /* @__PURE__ */ new Map();
@@ -48084,7 +48033,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
48084
48033
  ])
48085
48034
  );
48086
48035
  }
48087
- if (!destructive && workspace.state.headTransactionHash !== void 0) {
48036
+ if (!destructive && !options.regenerateSourceNames && workspace.state.headTransactionHash !== void 0) {
48088
48037
  const convex = await createConvexClient(workspace);
48089
48038
  const signal = await convex.query(api2.projectExportData.schemaSignal, {
48090
48039
  projectId: workspace.config.projectId,
@@ -48112,7 +48061,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
48112
48061
  destructive: true
48113
48062
  });
48114
48063
  const reset = resetWorkspaceToProjectSourcesV4(workspace, document, {
48115
- regenerateSourceNames: options.regenerateSourceNames
48064
+ regenerateSourceNames: true
48116
48065
  });
48117
48066
  for (const [key, state] of binaries.states) {
48118
48067
  const record3 = workspace.state.records[key];
@@ -48252,7 +48201,8 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
48252
48201
  conflictCount,
48253
48202
  conflictKeys,
48254
48203
  localStatus,
48255
- destructive
48204
+ destructive,
48205
+ regenerateSourceNames: destructive || options.regenerateSourceNames
48256
48206
  });
48257
48207
  }
48258
48208
  async function finishFormat4Pull(args) {
@@ -48264,11 +48214,17 @@ async function finishFormat4Pull(args) {
48264
48214
  conflictCount,
48265
48215
  conflictKeys,
48266
48216
  localStatus,
48267
- destructive
48217
+ destructive,
48218
+ regenerateSourceNames
48268
48219
  } = args;
48269
- const localResult = emitProjectDocumentFilesV4(
48270
- buildEmitRecordSet(document, plans, "emit")
48220
+ const plannedLocalRecords = buildEmitRecordSet(document, plans, "emit");
48221
+ const localRecords = regenerateSourceNames ? regenerateDialogueSourceNamesV4(plannedLocalRecords) : plannedLocalRecords;
48222
+ const regeneratedRecordKeys = new Set(
48223
+ [...plannedLocalRecords].flatMap(
48224
+ ([key, record3]) => localRecords.get(key) === record3 ? [] : [key]
48225
+ )
48271
48226
  );
48227
+ const localResult = emitProjectDocumentFilesV4(localRecords);
48272
48228
  const serverResult = emitProjectDocumentFilesV4(
48273
48229
  buildEmitRecordSet(document, plans, "server")
48274
48230
  );
@@ -48305,6 +48261,10 @@ async function finishFormat4Pull(args) {
48305
48261
  emittedPaths,
48306
48262
  mainLocale: workspaceMainLocale(workspace.state.records)
48307
48263
  });
48264
+ for (const key of regeneratedRecordKeys) {
48265
+ const path = localResult.recordFiles.get(key);
48266
+ if (path !== void 0) rewritePaths.add(path);
48267
+ }
48308
48268
  let written = 0;
48309
48269
  for (const path of emittedPaths) {
48310
48270
  const local = localByPath.get(path)?.content;
@@ -48533,6 +48493,7 @@ var init_pull = __esm({
48533
48493
  init_project_manifest();
48534
48494
  init_project_documents();
48535
48495
  init_project_file_pull();
48496
+ init_dialogue_sources();
48536
48497
  }
48537
48498
  });
48538
48499
 
@@ -65732,9 +65693,9 @@ ${h("Usage")}
65732
65693
  neo pull ${d("[--force|--reset] [--regenerate-source-names]")}
65733
65694
 
65734
65695
  ${h("Flags")}
65735
- --force ${d("Discard local edits and take the current server schema.")}
65736
- --reset ${d("Destructively regenerate the entire working copy and schema marker scaffold, even when the sync head is unchanged.")}
65737
- --regenerate-source-names ${d("With --reset, derive readable dialogue symbols from editor names and stable graph order.")}
65696
+ --force ${d("Discard local edits, take the current server schema, and regenerate readable dialogue symbols.")}
65697
+ --reset ${d("Destructively regenerate the entire working copy, binaries, and readable dialogue symbols, even when the sync head is unchanged.")}
65698
+ --regenerate-source-names ${d("Regenerate readable dialogue symbols during an otherwise normal pull.")}
65738
65699
 
65739
65700
  Use ${h("--reset")} to reconstruct every managed ${h(".neo")}/${h(".neoflow")} source file
65740
65701
  and tracked project binary from the authoritative server records.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.7.5",
3
+ "version": "0.8.0",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -62,8 +62,11 @@ neo init --project <id> [--version <id>] [--dir neo]
62
62
  ```
63
63
 
64
64
  For an existing format-4 workspace, `neo pull --reset` regenerates canonical
65
- source and managed binaries. `neo pull --force` discards local edits in favor
66
- of the server. Use neither casually.
65
+ source, readable dialogue names, and managed binaries. `neo pull --force`
66
+ discards local edits in favor of the server and also regenerates readable
67
+ dialogue names. Use neither casually. A normal
68
+ `neo pull --regenerate-source-names` refreshes only source naming as local
69
+ authored changes while retaining normal merge behavior.
67
70
 
68
71
  Neo never installs, discovers, or requires .NET. `neo doctor` validates the
69
72
  format-4 browser compiler, VS Code analysis contract/cache, source bundle, and
@@ -103,8 +106,9 @@ neo/
103
106
 
104
107
  All non-hidden `.neo`, `.neoflow`, and supported managed binaries are tracked.
105
108
  `.neo/` is ignored private state. Normal pull preserves declaration placement
106
- and spelling by stable ID when possible. Reset may regroup source into the
107
- canonical layout.
109
+ and spelling by stable ID when possible. Force and reset derive readable
110
+ dialogue names from authoritative records; reset may also regroup source into
111
+ the canonical layout.
108
112
 
109
113
  ## Native project declarations
110
114