@neocompose/cli 0.51.0 → 0.51.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,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.51.1] - 2026-09-16
|
|
4
|
+
|
|
5
|
+
- Refresh compiler-only changes with ordinary `neo pull` before compiling the local workspace. Preserve authored source, local edits, custom paths, and managed binaries while adopting the current server compilation.
|
|
6
|
+
- Refuse a normal pull when the baseline is missing but authored source files remain, preventing duplicate declarations and overwritten local edits. An explicit forced refresh recovers custom file paths from the existing declarations.
|
|
7
|
+
|
|
3
8
|
## [0.51.0] - 2026-09-15
|
|
4
9
|
|
|
5
10
|
Compiler revision 14 requires Unity SDK 0.37.0. The server migration recompiles stored scripts and retained history.
|
package/dist/neo.mjs
CHANGED
|
@@ -87329,6 +87329,44 @@ function stampUILogicBody(logic, bodyKey) {
|
|
|
87329
87329
|
body.compilerRevision = NEOSCRIPT_COMPILER_REVISION;
|
|
87330
87330
|
return true;
|
|
87331
87331
|
}
|
|
87332
|
+
function stampUILogicBodies(recordKind, data) {
|
|
87333
|
+
const record5 = asRecord2(data);
|
|
87334
|
+
if (record5 === null) return false;
|
|
87335
|
+
if (recordKind === "dialogue-group") {
|
|
87336
|
+
return stampConditionList(record5.conditions);
|
|
87337
|
+
}
|
|
87338
|
+
if (recordKind !== "dialogue-node") return false;
|
|
87339
|
+
let changed = stampConditionList(record5.conditions);
|
|
87340
|
+
if (Array.isArray(record5.actions)) {
|
|
87341
|
+
for (const actionValue2 of record5.actions) {
|
|
87342
|
+
const logic = asRecord2(asRecord2(actionValue2)?.logic);
|
|
87343
|
+
changed = stampUILogicBody(logic, "action") || changed;
|
|
87344
|
+
}
|
|
87345
|
+
}
|
|
87346
|
+
if (Array.isArray(record5.outcomes)) {
|
|
87347
|
+
for (const outcomeValue of record5.outcomes) {
|
|
87348
|
+
changed = stampConditionList(asRecord2(outcomeValue)?.conditions) || changed;
|
|
87349
|
+
}
|
|
87350
|
+
}
|
|
87351
|
+
const options = asRecord2(record5.optionSettings)?.options;
|
|
87352
|
+
if (Array.isArray(options)) {
|
|
87353
|
+
for (const optionValue of options) {
|
|
87354
|
+
const settings = asRecord2(asRecord2(optionValue)?.settings);
|
|
87355
|
+
if (settings === null) continue;
|
|
87356
|
+
changed = stampConditionList(settings.conditions) || changed;
|
|
87357
|
+
changed = stampConditionList(settings.selectableConditions) || changed;
|
|
87358
|
+
}
|
|
87359
|
+
}
|
|
87360
|
+
return changed;
|
|
87361
|
+
}
|
|
87362
|
+
function stampConditionList(value) {
|
|
87363
|
+
if (!Array.isArray(value)) return false;
|
|
87364
|
+
let changed = false;
|
|
87365
|
+
for (const conditionValue of value) {
|
|
87366
|
+
changed = stampUILogicBody(asRecord2(conditionValue), "getter") || changed;
|
|
87367
|
+
}
|
|
87368
|
+
return changed;
|
|
87369
|
+
}
|
|
87332
87370
|
function asRecord2(value) {
|
|
87333
87371
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
87334
87372
|
return null;
|
|
@@ -126661,6 +126699,14 @@ var init_convex = __esm({
|
|
|
126661
126699
|
// src/project-source/source-layout.ts
|
|
126662
126700
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
126663
126701
|
import { relative as relative4, sep as sep4 } from "node:path";
|
|
126702
|
+
function workspaceForSourceLayoutV4(workspace, document) {
|
|
126703
|
+
if (Object.keys(workspace.state.records).length > 0) return workspace;
|
|
126704
|
+
const records2 = {};
|
|
126705
|
+
for (const [key, record5] of document.records) {
|
|
126706
|
+
if (!record5.deleted) records2[key] = record5;
|
|
126707
|
+
}
|
|
126708
|
+
return { ...workspace, state: { ...workspace.state, records: records2 } };
|
|
126709
|
+
}
|
|
126664
126710
|
function readWorkspaceRecordFilesV4(workspace) {
|
|
126665
126711
|
const paths = /* @__PURE__ */ new Map();
|
|
126666
126712
|
const keysById = /* @__PURE__ */ new Map();
|
|
@@ -127446,17 +127492,7 @@ import {
|
|
|
127446
127492
|
import { dirname as dirname7, join as join8, relative as relative5, sep as sep5 } from "node:path";
|
|
127447
127493
|
function prepareWorkspaceResetV4(workspace, document, options = {}) {
|
|
127448
127494
|
const emissionRecords = options.regenerateSourceNames ? regenerateDialogueSourceNamesV4(document.records) : document.records;
|
|
127449
|
-
|
|
127450
|
-
if (Object.keys(workspace.state.records).length === 0) {
|
|
127451
|
-
const records2 = {};
|
|
127452
|
-
for (const [key, record5] of document.records) {
|
|
127453
|
-
if (!record5.deleted) records2[key] = record5;
|
|
127454
|
-
}
|
|
127455
|
-
layoutWorkspace = {
|
|
127456
|
-
...workspace,
|
|
127457
|
-
state: { ...workspace.state, records: records2 }
|
|
127458
|
-
};
|
|
127459
|
-
}
|
|
127495
|
+
const layoutWorkspace = workspaceForSourceLayoutV4(workspace, document);
|
|
127460
127496
|
const status = listProjectSourceFilesV4(workspace.root).length === 0 ? null : readWorkspaceLayoutStatusV4(layoutWorkspace);
|
|
127461
127497
|
const localValues = status?.localValues ?? workspace.state.localValues;
|
|
127462
127498
|
const emitted = emitProjectDocumentFilesV4(emissionRecords, {
|
|
@@ -127874,6 +127910,40 @@ var init_static_value_seed_records = __esm({
|
|
|
127874
127910
|
}
|
|
127875
127911
|
});
|
|
127876
127912
|
|
|
127913
|
+
// src/project-sync/compiler-metadata.ts
|
|
127914
|
+
function compilerMetadataChangedKeys(previous, document, changedKeys) {
|
|
127915
|
+
const keys = changedKeys ?? /* @__PURE__ */ new Set([...Object.keys(previous), ...document.records.keys()]);
|
|
127916
|
+
const refreshed = /* @__PURE__ */ new Set();
|
|
127917
|
+
for (const key of keys) {
|
|
127918
|
+
const before = previous[key];
|
|
127919
|
+
const after = document.records.get(key);
|
|
127920
|
+
if (before === void 0 || after === void 0 || after.deleted || before.recordId !== after.recordId || before.recordKind !== after.recordKind || !isProjectRecordKind(after.recordKind))
|
|
127921
|
+
return null;
|
|
127922
|
+
if (before.contentHash === after.contentHash) continue;
|
|
127923
|
+
if (!isObjectRecord2(before.data) || !isObjectRecord2(after.data) || !canonicallyEqual(
|
|
127924
|
+
authoredCompilerInput(after.recordKind, before.data),
|
|
127925
|
+
authoredCompilerInput(after.recordKind, after.data)
|
|
127926
|
+
))
|
|
127927
|
+
return null;
|
|
127928
|
+
refreshed.add(key);
|
|
127929
|
+
}
|
|
127930
|
+
return refreshed.size === 0 ? null : refreshed;
|
|
127931
|
+
}
|
|
127932
|
+
function authoredCompilerInput(kind, data) {
|
|
127933
|
+
const result = stripClientDerivedBodies(kind, data);
|
|
127934
|
+
stampUILogicBodies(kind, result);
|
|
127935
|
+
if (isObjectRecord2(result)) delete result.updatedAt;
|
|
127936
|
+
return result;
|
|
127937
|
+
}
|
|
127938
|
+
var init_compiler_metadata = __esm({
|
|
127939
|
+
"src/project-sync/compiler-metadata.ts"() {
|
|
127940
|
+
"use strict";
|
|
127941
|
+
init_project2();
|
|
127942
|
+
init_neo_script_derived_bodies();
|
|
127943
|
+
init_projection();
|
|
127944
|
+
}
|
|
127945
|
+
});
|
|
127946
|
+
|
|
127877
127947
|
// src/commands/pull.ts
|
|
127878
127948
|
var pull_exports = {};
|
|
127879
127949
|
__export(pull_exports, {
|
|
@@ -127903,7 +127973,15 @@ async function runPull(workspace, options, progress = spinner("Checking local wo
|
|
|
127903
127973
|
async function runNormalPull(workspace, options, progress) {
|
|
127904
127974
|
const destructive = options.force;
|
|
127905
127975
|
const hasBaseline = Object.keys(workspace.state.records).length > 0;
|
|
127976
|
+
if (!destructive && !hasBaseline && listProjectSourceFilesV4(workspace.root).length > 0) {
|
|
127977
|
+
throw new Error(
|
|
127978
|
+
"Cannot merge existing Neo sources without a pull baseline in .neo/state.json. Restore that file to preserve local edits, or back up your sources and run `neo pull --force` to replace them with the server version while preserving their paths."
|
|
127979
|
+
);
|
|
127980
|
+
}
|
|
127906
127981
|
const mainLocale = workspaceMainLocale(workspace.state.records);
|
|
127982
|
+
const hadConflicts = Object.values(workspace.state.records).some(
|
|
127983
|
+
(record5) => record5.conflictServerHash !== void 0 || record5.conflictFiles !== void 0 || record5.projectBinary?.conflict !== void 0
|
|
127984
|
+
);
|
|
127907
127985
|
if (acceptSourceEquivalentConflictBases(workspace, mainLocale) > 0) {
|
|
127908
127986
|
writeWorkspaceState(workspace.root, workspace.state);
|
|
127909
127987
|
}
|
|
@@ -127961,6 +128039,28 @@ async function runNormalPull(workspace, options, progress) {
|
|
|
127961
128039
|
document = await fetchProjectDocument(workspace);
|
|
127962
128040
|
nextCursor = document.revision === void 0 ? null : cursorFromRevision(document.revision);
|
|
127963
128041
|
}
|
|
128042
|
+
const compilerRefreshKeys = !destructive && hasBaseline && !hadConflicts && !options.regenerateSourceNames ? compilerMetadataChangedKeys(
|
|
128043
|
+
workspace.state.records,
|
|
128044
|
+
document,
|
|
128045
|
+
changedRecordKeys
|
|
128046
|
+
) : null;
|
|
128047
|
+
if (compilerRefreshKeys !== null) {
|
|
128048
|
+
if (changedRecordKeys === null) {
|
|
128049
|
+
await updateFullPullSyncMetadata(workspace, document);
|
|
128050
|
+
observedHeadTransactionHash = workspace.state.headTransactionHash;
|
|
128051
|
+
observedDerivedEdgeVersion = workspace.state.derivedEdgeVersion;
|
|
128052
|
+
}
|
|
128053
|
+
finishRecordOnlyDeltaPull({
|
|
128054
|
+
workspace,
|
|
128055
|
+
document,
|
|
128056
|
+
changedRecordKeys: compilerRefreshKeys,
|
|
128057
|
+
nextCursor,
|
|
128058
|
+
observedHeadTransactionHash,
|
|
128059
|
+
observedDerivedEdgeVersion,
|
|
128060
|
+
progress
|
|
128061
|
+
});
|
|
128062
|
+
return;
|
|
128063
|
+
}
|
|
127964
128064
|
let localByKey = /* @__PURE__ */ new Map();
|
|
127965
128065
|
let localStatus = null;
|
|
127966
128066
|
if (hasBaseline && !destructive) {
|
|
@@ -128151,18 +128251,7 @@ async function runResetPull(workspace, progress) {
|
|
|
128151
128251
|
if (record5) record5.projectBinary = state;
|
|
128152
128252
|
}
|
|
128153
128253
|
progress.update("Finalizing pull state\u2026");
|
|
128154
|
-
|
|
128155
|
-
const convex = await createConvexClient(workspace);
|
|
128156
|
-
const signal = await convex.query(api2.projectExportData.schemaSignal, {
|
|
128157
|
-
projectId: workspace.config.projectId,
|
|
128158
|
-
versionId: workspace.config.versionId
|
|
128159
|
-
});
|
|
128160
|
-
workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
|
|
128161
|
-
workspace.state.derivedEdgeVersion = signal?.derivedEdgeVersion ?? null;
|
|
128162
|
-
} catch {
|
|
128163
|
-
workspace.state.headTransactionHash = null;
|
|
128164
|
-
delete workspace.state.derivedEdgeVersion;
|
|
128165
|
-
}
|
|
128254
|
+
await updateFullPullSyncMetadata(workspace, document);
|
|
128166
128255
|
if (document.revision !== void 0) {
|
|
128167
128256
|
workspace.state.documentRevisionCursor = mutableCursor(
|
|
128168
128257
|
cursorFromRevision(document.revision)
|
|
@@ -128234,11 +128323,12 @@ async function finishFormat4Pull(args) {
|
|
|
128234
128323
|
([key, record5]) => localRecords.get(key) === record5 ? [] : [key]
|
|
128235
128324
|
)
|
|
128236
128325
|
);
|
|
128237
|
-
const
|
|
128326
|
+
const layoutWorkspace = workspaceForSourceLayoutV4(workspace, document);
|
|
128327
|
+
const recordFiles = readWorkspaceRecordFilesV4(layoutWorkspace);
|
|
128238
128328
|
for (const [key, record5] of localStatus?.reconstructed ?? []) {
|
|
128239
128329
|
if (record5.file != null) recordFiles.set(key, record5.file);
|
|
128240
128330
|
}
|
|
128241
|
-
const layoutStatus = localStatus ?? (destructive ? readWorkspaceLayoutStatusV4(
|
|
128331
|
+
const layoutStatus = localStatus ?? (destructive ? readWorkspaceLayoutStatusV4(layoutWorkspace) : null);
|
|
128242
128332
|
const localValues = layoutStatus?.localValues ?? workspace.state.localValues;
|
|
128243
128333
|
const binaryPaths = workspaceBinaryPathsV4(
|
|
128244
128334
|
workspace,
|
|
@@ -128256,6 +128346,16 @@ async function finishFormat4Pull(args) {
|
|
|
128256
128346
|
buildEmitRecordSet(document, plans, "server"),
|
|
128257
128347
|
{ recordFiles, localValues, binaryPaths }
|
|
128258
128348
|
);
|
|
128349
|
+
const resolveSourcePath = createWorkspaceSourcePathResolver(workspace.root);
|
|
128350
|
+
if (!destructive && Object.keys(workspace.state.records).length === 0) {
|
|
128351
|
+
for (const file of localResult.files) {
|
|
128352
|
+
if (existsSync8(resolveSourcePath(file.path))) {
|
|
128353
|
+
throw new Error(
|
|
128354
|
+
`Cannot replace existing source ${JSON.stringify(file.path)} without a pull baseline in .neo/state.json. Restore that file to preserve local edits, or back up your sources and run \`neo pull --force\` to replace them with the server version.`
|
|
128355
|
+
);
|
|
128356
|
+
}
|
|
128357
|
+
}
|
|
128358
|
+
}
|
|
128259
128359
|
const binaries = await pullProjectBinariesV4({
|
|
128260
128360
|
workspace,
|
|
128261
128361
|
document,
|
|
@@ -128309,7 +128409,6 @@ async function finishFormat4Pull(args) {
|
|
|
128309
128409
|
for (const key of regeneratedRecordKeys) {
|
|
128310
128410
|
for (const path of localRecordFiles.get(key) ?? []) rewritePaths.add(path);
|
|
128311
128411
|
}
|
|
128312
|
-
const resolveSourcePath = createWorkspaceSourcePathResolver(workspace.root);
|
|
128313
128412
|
const markedPaths = /* @__PURE__ */ new Set();
|
|
128314
128413
|
let written = 0;
|
|
128315
128414
|
for (const path of emittedPaths) {
|
|
@@ -128415,18 +128514,7 @@ async function finishFormat4Pull(args) {
|
|
|
128415
128514
|
if (observedHeadTransactionHash !== void 0) {
|
|
128416
128515
|
workspace.state.headTransactionHash = observedHeadTransactionHash;
|
|
128417
128516
|
} else {
|
|
128418
|
-
|
|
128419
|
-
const convex = await createConvexClient(workspace);
|
|
128420
|
-
const signal = await convex.query(api2.projectExportData.schemaSignal, {
|
|
128421
|
-
projectId: workspace.config.projectId,
|
|
128422
|
-
versionId: workspace.config.versionId
|
|
128423
|
-
});
|
|
128424
|
-
workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
|
|
128425
|
-
workspace.state.derivedEdgeVersion = signal?.derivedEdgeVersion ?? null;
|
|
128426
|
-
} catch {
|
|
128427
|
-
workspace.state.headTransactionHash = null;
|
|
128428
|
-
delete workspace.state.derivedEdgeVersion;
|
|
128429
|
-
}
|
|
128517
|
+
await updateFullPullSyncMetadata(workspace, document);
|
|
128430
128518
|
}
|
|
128431
128519
|
if (observedDerivedEdgeVersion !== void 0) {
|
|
128432
128520
|
workspace.state.derivedEdgeVersion = observedDerivedEdgeVersion;
|
|
@@ -128598,6 +128686,20 @@ function finishRecordOnlyDeltaPull(args) {
|
|
|
128598
128686
|
`Pulled ${args.changedRecordKeys.size} changed record(s) \u2014 0 file(s) updated \u2014 0 removed.`
|
|
128599
128687
|
);
|
|
128600
128688
|
}
|
|
128689
|
+
async function updateFullPullSyncMetadata(workspace, document) {
|
|
128690
|
+
try {
|
|
128691
|
+
const convex = await createConvexClient(workspace);
|
|
128692
|
+
const signal = await convex.query(api2.projectExportData.schemaSignal, {
|
|
128693
|
+
projectId: workspace.config.projectId,
|
|
128694
|
+
versionId: workspace.config.versionId
|
|
128695
|
+
});
|
|
128696
|
+
workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
|
|
128697
|
+
workspace.state.derivedEdgeVersion = signal?.derivedEdgeVersion ?? null;
|
|
128698
|
+
} catch {
|
|
128699
|
+
workspace.state.headTransactionHash = null;
|
|
128700
|
+
delete workspace.state.derivedEdgeVersion;
|
|
128701
|
+
}
|
|
128702
|
+
}
|
|
128601
128703
|
function cursorFromRevision(revision) {
|
|
128602
128704
|
return {
|
|
128603
128705
|
readBase: revision.readBase,
|
|
@@ -128755,6 +128857,7 @@ var init_pull = __esm({
|
|
|
128755
128857
|
init_static_value_seed_records();
|
|
128756
128858
|
init_static_member_ownership_recovery();
|
|
128757
128859
|
init_value_base_desync();
|
|
128860
|
+
init_compiler_metadata();
|
|
128758
128861
|
}
|
|
128759
128862
|
});
|
|
128760
128863
|
|
|
@@ -136399,7 +136502,7 @@ var init_registry2 = __esm({
|
|
|
136399
136502
|
"schema-contract/registry.mjs"() {
|
|
136400
136503
|
"use strict";
|
|
136401
136504
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
136402
|
-
cliVersion: "0.51.
|
|
136505
|
+
cliVersion: "0.51.1",
|
|
136403
136506
|
projectFileUploadBatchSize: 32,
|
|
136404
136507
|
documentRecords: {
|
|
136405
136508
|
member: {
|
|
@@ -143628,7 +143731,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
143628
143731
|
async function main() {
|
|
143629
143732
|
const args = parseArgs(process.argv.slice(2));
|
|
143630
143733
|
if (args.command === "--version") {
|
|
143631
|
-
console.log("0.51.
|
|
143734
|
+
console.log("0.51.1");
|
|
143632
143735
|
return;
|
|
143633
143736
|
}
|
|
143634
143737
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -90,7 +90,7 @@ wrappers.
|
|
|
90
90
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
91
91
|
|
|
92
92
|
```html
|
|
93
|
-
<!-- reviewed-through-cli: 0.51.
|
|
93
|
+
<!-- reviewed-through-cli: 0.51.1 -->
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -40,9 +40,17 @@ without compiling it; use `neo status` to inspect local edits and diagnostics.
|
|
|
40
40
|
An undo/reset metadata change invalidates the cursor and causes a safe
|
|
41
41
|
full-snapshot fallback.
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
After a compiler upgrade, run `neo pull` with `.neo/state.json` intact. When
|
|
44
|
+
remote changes affect only compiler-owned bodies or timestamps, pull refreshes
|
|
45
|
+
the cached records before local compilation and leaves authored files and
|
|
46
|
+
managed binaries untouched. It handles both changed-record pulls and full
|
|
47
|
+
snapshot refreshes. Added or deleted records, authored changes, and unresolved
|
|
48
|
+
conflicts still require the normal merge path.
|
|
49
|
+
|
|
50
|
+
Keep `.neo/state.json`: it holds the merge baseline and source placements.
|
|
51
|
+
Normal pull refuses existing production sources without that baseline. To
|
|
52
|
+
deliberately replace a checkout whose state is gone, back it up first and use
|
|
53
|
+
`neo pull --force`; the CLI recovers custom paths from the remaining declarations.
|
|
46
54
|
The force pull replaces local source with the server version.
|
|
47
55
|
|
|
48
56
|
Pull pins every page and snapshot batch to one published generation and logical
|