@neocompose/cli 0.70.0 → 0.70.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,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.70.1] - 2026-10-06
|
|
4
|
+
|
|
5
|
+
- `neo push` can upload a project file renamed with `@settings(name: ...)`. It used to stage the upload under the file's basename, so the commit failed with "Staged project file … did not match its source name".
|
|
6
|
+
- A project file's `@settings(name: ...)` must end with its file's extension, for example `@settings(name: "ClinkingCoin1.mp3")` for `clinkingcoin1.mp3`. A pull on another machine rebuilds the file's path from that name. The symbol error now says the name needs that extension.
|
|
7
|
+
- Push and pull keep `@settings(name: ...)` on a renamed file, and a new file keeps the path you gave it. Before, the rewrite after a push dropped the name and rebuilt the path from it.
|
|
8
|
+
|
|
3
9
|
## [0.70.0] - 2026-10-06
|
|
4
10
|
|
|
5
11
|
- `neo export` exports the working copy, local edits included, with no network. Unity sees an edit as soon as it's saved, before `neo push`. The export says whether it holds only the pulled head ("Clean") or how many local changes it includes ("Local"). A local export is marked in `metadata.localExport`; SDK 0.59.0 refuses player builds from it and keeps play-mode saves on disk instead of the server. A clean `neo export` or a push clears the mark. A local export still stops, writing nothing, on an error diagnostic or on a project file whose pulled bytes aren't on disk yet; run `neo pull` first.
|
package/dist/neo.mjs
CHANGED
|
@@ -31811,7 +31811,7 @@ var init_registry = __esm({
|
|
|
31811
31811
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
31812
31812
|
"use strict";
|
|
31813
31813
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
31814
|
-
cliVersion: "0.70.
|
|
31814
|
+
cliVersion: "0.70.1",
|
|
31815
31815
|
projectFileUploadBatchSize: 32,
|
|
31816
31816
|
documentRecords: {
|
|
31817
31817
|
member: {
|
|
@@ -60588,7 +60588,7 @@ function validateProjectFileDeclarationSymbolsV4(declarations) {
|
|
|
60588
60588
|
const expected = expectedSymbols.get(declaration.recordId);
|
|
60589
60589
|
if (expected === void 0 || declaration.symbol === expected) continue;
|
|
60590
60590
|
throw new Error(
|
|
60591
|
-
`Project file ${declaration.symbol} must use registry symbol ${expected}, derived from its persisted name ${JSON.stringify(declaration.persistedName)}. Rename the declaration or set @settings(name: ...)
|
|
60591
|
+
`Project file ${declaration.symbol} must use registry symbol ${expected}, derived from its persisted name ${JSON.stringify(declaration.persistedName)}. Rename the declaration, or set @settings(name: ...) to a file name ending in ${JSON.stringify(sourceExtension(declaration.persistedName))} that derives ${declaration.symbol}.`
|
|
60592
60592
|
);
|
|
60593
60593
|
}
|
|
60594
60594
|
}
|
|
@@ -60621,7 +60621,6 @@ function emitProjectFileRegistrySourcesV4(records2, binaryPaths = /* @__PURE__ *
|
|
|
60621
60621
|
const registryType = kind === "image" ? "ImageRegistry" : "AudioClipRegistry";
|
|
60622
60622
|
const registryName = kind === "image" ? "Images" : "AudioClips";
|
|
60623
60623
|
const valueType = kind === "image" ? "NeoImage" : "NeoAudioClip";
|
|
60624
|
-
const directory = kind === "image" ? "Files/Images" : "Files/AudioClips";
|
|
60625
60624
|
const entries = liveFiles.filter(({ data }) => data.fileType === kind).sort((left, right) => {
|
|
60626
60625
|
const leftSymbol = symbols.get(left.record.recordId) ?? "";
|
|
60627
60626
|
const rightSymbol = symbols.get(right.record.recordId) ?? "";
|
|
@@ -60638,12 +60637,16 @@ function emitProjectFileRegistrySourcesV4(records2, binaryPaths = /* @__PURE__ *
|
|
|
60638
60637
|
const templateName = templateId === null ? null : (kind === "image" ? textureTemplates : audioTemplates).get(
|
|
60639
60638
|
templateId
|
|
60640
60639
|
);
|
|
60641
|
-
const annotation2 = templateName ? ` @settings(template: ${templateName})
|
|
60642
|
-
` : "";
|
|
60643
60640
|
const path = normalizeTrustedProjectBinaryPath(
|
|
60644
|
-
binaryPaths.get(record6.recordId) ??
|
|
60641
|
+
binaryPaths.get(record6.recordId) ?? canonicalProjectBinaryPathV4(data),
|
|
60645
60642
|
kind
|
|
60646
60643
|
);
|
|
60644
|
+
const options = [
|
|
60645
|
+
...templateName ? [`template: ${templateName}`] : [],
|
|
60646
|
+
...data.name === sourceBasename(path) ? [] : [`name: ${JSON.stringify(data.name)}`]
|
|
60647
|
+
];
|
|
60648
|
+
const annotation2 = options.length === 0 ? "" : ` @settings(${options.join(", ")})
|
|
60649
|
+
`;
|
|
60647
60650
|
return ` @id(${JSON.stringify(record6.recordId)})
|
|
60648
60651
|
${annotation2} ${valueType} ${symbol} = new(${JSON.stringify(path)});`;
|
|
60649
60652
|
});
|
|
@@ -60665,10 +60668,7 @@ function projectFileDeclarationsV4(analysis) {
|
|
|
60665
60668
|
);
|
|
60666
60669
|
}
|
|
60667
60670
|
function lowerTrustedProjectFileRegistrySourcesV4(state, analysis, trustedPendingFiles = /* @__PURE__ */ new Map()) {
|
|
60668
|
-
const
|
|
60669
|
-
const declarations = analysis.files.registries.flatMap(
|
|
60670
|
-
(registry) => parseRegistry(registry, templateIds)
|
|
60671
|
-
);
|
|
60671
|
+
const declarations = projectFileDeclarationsV4(analysis);
|
|
60672
60672
|
validateProjectFileDeclarationSymbolsV4(declarations);
|
|
60673
60673
|
const seenPaths = /* @__PURE__ */ new Map();
|
|
60674
60674
|
const seenSymbols = /* @__PURE__ */ new Map();
|
|
@@ -60848,7 +60848,7 @@ function canonicalProjectBinaryPathV4(data) {
|
|
|
60848
60848
|
if (typeof data.name !== "string") {
|
|
60849
60849
|
throw new Error("Project file name is missing.");
|
|
60850
60850
|
}
|
|
60851
|
-
return `${kind === "image" ? "Files/Images" : "Files/AudioClips"}/${
|
|
60851
|
+
return `${kind === "image" ? "Files/Images" : "Files/AudioClips"}/${safeProjectFileName(data.name)}`;
|
|
60852
60852
|
}
|
|
60853
60853
|
function fileTemplateIdsByName(analysis) {
|
|
60854
60854
|
const templateIds = /* @__PURE__ */ new Map();
|
|
@@ -60900,13 +60900,22 @@ function parseRegistry(registry, templateIds) {
|
|
|
60900
60900
|
const settings = parseFileSettings(match[2], templateIds);
|
|
60901
60901
|
const path = JSON.parse(match[5]);
|
|
60902
60902
|
const recordId = match[1] ? JSON.parse(match[1]) : `__pending__:project-file:${encodeURIComponent(registry.source.uri)}:${registry.source.range.start.line}:${encodeURIComponent(match[4])}`;
|
|
60903
|
+
const fileName2 = sourceBasename(path);
|
|
60904
|
+
if (settings.name !== null) {
|
|
60905
|
+
const extension = sourceExtension(fileName2);
|
|
60906
|
+
if (!settings.name.toLowerCase().endsWith(extension.toLowerCase())) {
|
|
60907
|
+
throw new Error(
|
|
60908
|
+
`Project file ${match[4]} @settings(name: ${JSON.stringify(settings.name)}) must end with ${JSON.stringify(extension)}, the extension of ${JSON.stringify(path)}.`
|
|
60909
|
+
);
|
|
60910
|
+
}
|
|
60911
|
+
}
|
|
60903
60912
|
result.push({
|
|
60904
60913
|
recordId,
|
|
60905
60914
|
symbol: match[4],
|
|
60906
60915
|
path,
|
|
60907
60916
|
kind,
|
|
60908
60917
|
templateId: settings.templateId,
|
|
60909
|
-
persistedName: settings.name ??
|
|
60918
|
+
persistedName: settings.name ?? fileName2,
|
|
60910
60919
|
sourceFile: registry.source.uri,
|
|
60911
60920
|
sourceLine: registry.source.range.start.line + 1
|
|
60912
60921
|
});
|
|
@@ -60992,7 +61001,7 @@ function templateNames(records2, kind) {
|
|
|
60992
61001
|
})
|
|
60993
61002
|
);
|
|
60994
61003
|
}
|
|
60995
|
-
function
|
|
61004
|
+
function safeProjectFileName(value) {
|
|
60996
61005
|
const fileName2 = sourceBasename(value).replace(/[\\/]/g, "-");
|
|
60997
61006
|
if (fileName2 === "." || fileName2 === ".." || fileName2.length === 0) {
|
|
60998
61007
|
throw new Error(`Invalid project filename ${JSON.stringify(value)}.`);
|
|
@@ -61002,6 +61011,9 @@ function safeFileName(value) {
|
|
|
61002
61011
|
function sourceBasename(value) {
|
|
61003
61012
|
return value.replaceAll("\\", "/").split("/").at(-1) ?? "";
|
|
61004
61013
|
}
|
|
61014
|
+
function sourceExtension(value) {
|
|
61015
|
+
return /\.[^.]+$/.exec(value)?.[0] ?? "";
|
|
61016
|
+
}
|
|
61005
61017
|
function optionalString(value) {
|
|
61006
61018
|
return typeof value === "string" ? value : null;
|
|
61007
61019
|
}
|
|
@@ -136733,10 +136745,7 @@ import {
|
|
|
136733
136745
|
} from "node:fs";
|
|
136734
136746
|
import { basename, dirname as dirname7, extname, join as join6, relative as relative2, sep as sep2 } from "node:path";
|
|
136735
136747
|
function lowerProjectFileRegistrySourcesV4(root, state, analysis, options = {}) {
|
|
136736
|
-
const
|
|
136737
|
-
const declarations = analysis.files.registries.flatMap(
|
|
136738
|
-
(registry) => parseRegistry2(registry, templateIds)
|
|
136739
|
-
);
|
|
136748
|
+
const declarations = projectFileDeclarationsV4(analysis);
|
|
136740
136749
|
validateProjectFileDeclarationSymbolsV4(declarations);
|
|
136741
136750
|
const seenPaths = /* @__PURE__ */ new Map();
|
|
136742
136751
|
const seenSymbols = /* @__PURE__ */ new Map();
|
|
@@ -136821,14 +136830,8 @@ function lowerProjectFileRegistrySourcesV4(root, state, analysis, options = {})
|
|
|
136821
136830
|
};
|
|
136822
136831
|
});
|
|
136823
136832
|
}
|
|
136824
|
-
function projectFileDeclarationsV42(analysis) {
|
|
136825
|
-
const templateIds = fileTemplateIdsByName2(analysis);
|
|
136826
|
-
return analysis.files.registries.flatMap(
|
|
136827
|
-
(registry) => parseRegistry2(registry, templateIds)
|
|
136828
|
-
);
|
|
136829
|
-
}
|
|
136830
136833
|
function lowerDiscoveredProjectBinariesV4(root, state, analysis) {
|
|
136831
|
-
const explicit =
|
|
136834
|
+
const explicit = projectFileDeclarationsV4(analysis);
|
|
136832
136835
|
const project = Object.values(state).find(
|
|
136833
136836
|
(entry) => entry.recordKind === "project" && isObjectRecord2(entry.data)
|
|
136834
136837
|
);
|
|
@@ -136869,7 +136872,7 @@ function lowerDiscoveredProjectBinariesV4(root, state, analysis) {
|
|
|
136869
136872
|
});
|
|
136870
136873
|
}
|
|
136871
136874
|
function inspectProjectBinaryStatusV4(root, state, analysis) {
|
|
136872
|
-
const explicit =
|
|
136875
|
+
const explicit = projectFileDeclarationsV4(analysis);
|
|
136873
136876
|
const result = explicit.map((declaration) => {
|
|
136874
136877
|
const baseState = state[`project-file:${declaration.recordId}`];
|
|
136875
136878
|
const data = isObjectRecord2(baseState?.data) ? baseState.data : {};
|
|
@@ -136927,16 +136930,6 @@ function inspectProjectBinaryStatusV4(root, state, analysis) {
|
|
|
136927
136930
|
function pendingDiscoveredFileId(path) {
|
|
136928
136931
|
return `__pending__:project-file:drag:${encodeURIComponent(normalizeSlash2(path))}`;
|
|
136929
136932
|
}
|
|
136930
|
-
function canonicalProjectBinaryPathV42(data) {
|
|
136931
|
-
if (!isObjectRecord2(data))
|
|
136932
|
-
throw new Error("Project file metadata must be an object.");
|
|
136933
|
-
if (data.fileType !== "image" && data.fileType !== "audio")
|
|
136934
|
-
throw new Error("Project file metadata has an unsupported fileType.");
|
|
136935
|
-
if (typeof data.name !== "string")
|
|
136936
|
-
throw new Error("Project file metadata has no filename.");
|
|
136937
|
-
const directory = data.fileType === "image" ? "Files/Images" : "Files/AudioClips";
|
|
136938
|
-
return `${directory}/${safeFileName2(data.name)}`;
|
|
136939
|
-
}
|
|
136940
136933
|
function discoverProjectBinariesV4(root, explicit, ignoredPaths = []) {
|
|
136941
136934
|
const explicitPaths = new Set(
|
|
136942
136935
|
[...explicit.map((entry) => entry.path), ...ignoredPaths].map(
|
|
@@ -137012,124 +137005,11 @@ function writeBinaryConflictArtifactV4(root, fileId, fileName2, bytes, expectedS
|
|
|
137012
137005
|
"conflicts",
|
|
137013
137006
|
"files",
|
|
137014
137007
|
safePathSegment2(fileId),
|
|
137015
|
-
|
|
137008
|
+
safeProjectFileName(fileName2)
|
|
137016
137009
|
);
|
|
137017
137010
|
writeVerifiedBinaryDownloadV4(destination, bytes, expectedSha256);
|
|
137018
137011
|
return normalizeSlash2(relative2(root, destination));
|
|
137019
137012
|
}
|
|
137020
|
-
function fileTemplateIdsByName2(analysis) {
|
|
137021
|
-
const templateIds = /* @__PURE__ */ new Map();
|
|
137022
|
-
for (const global of analysis.configuration.globals) {
|
|
137023
|
-
const kind = global.type.name === "TextureTemplate" ? "texture-template" : global.type.name === "AudioTemplate" ? "audio-template" : null;
|
|
137024
|
-
if (kind === null) continue;
|
|
137025
|
-
templateIds.set(
|
|
137026
|
-
global.name,
|
|
137027
|
-
global.id ?? `__pending__:${kind}:${encodeURIComponent(global.source.uri)}:${global.source.range.start.line}:${global.source.range.start.character}:${encodeURIComponent(global.name)}`
|
|
137028
|
-
);
|
|
137029
|
-
}
|
|
137030
|
-
return templateIds;
|
|
137031
|
-
}
|
|
137032
|
-
function parseRegistry2(registry, templateIds) {
|
|
137033
|
-
const kind = registry.type.name === "ImageRegistry" ? "image" : registry.type.name === "AudioClipRegistry" ? "audio" : null;
|
|
137034
|
-
if (kind === null)
|
|
137035
|
-
throw new Error(
|
|
137036
|
-
`Unsupported project file registry type ${registry.type.name}.`
|
|
137037
|
-
);
|
|
137038
|
-
const expectedName = kind === "image" ? "Images" : "AudioClips";
|
|
137039
|
-
if (registry.name !== expectedName)
|
|
137040
|
-
throw new Error(
|
|
137041
|
-
`${registry.type.name} must use the canonical global name ${expectedName}.`
|
|
137042
|
-
);
|
|
137043
|
-
const body = objectInitializerBody2(registry.initializer, registry.type.name);
|
|
137044
|
-
const result = [];
|
|
137045
|
-
let cursor = 0;
|
|
137046
|
-
while (cursor < body.length) {
|
|
137047
|
-
const whitespace = /^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)+/.exec(
|
|
137048
|
-
body.slice(cursor)
|
|
137049
|
-
);
|
|
137050
|
-
if (whitespace) cursor += whitespace[0].length;
|
|
137051
|
-
if (cursor >= body.length) break;
|
|
137052
|
-
REGISTRY_ENTRY2.lastIndex = cursor;
|
|
137053
|
-
const match = REGISTRY_ENTRY2.exec(body);
|
|
137054
|
-
if (!match)
|
|
137055
|
-
throw new Error(
|
|
137056
|
-
`${registry.type.name} ${registry.name} contains an invalid file declaration near ${JSON.stringify(body.slice(cursor, cursor + 80))}.`
|
|
137057
|
-
);
|
|
137058
|
-
const entryType = match[3];
|
|
137059
|
-
if (kind === "image" && entryType !== "NeoImage" || kind === "audio" && entryType !== "NeoAudioClip") {
|
|
137060
|
-
throw new Error(
|
|
137061
|
-
`${registry.type.name} cannot contain ${entryType} declarations.`
|
|
137062
|
-
);
|
|
137063
|
-
}
|
|
137064
|
-
const settings = parseFileSettings2(match[2], templateIds);
|
|
137065
|
-
const path = JSON.parse(match[5]);
|
|
137066
|
-
const recordId = match[1] ? JSON.parse(match[1]) : `__pending__:project-file:${encodeURIComponent(registry.source.uri)}:${registry.source.range.start.line}:${encodeURIComponent(match[4])}`;
|
|
137067
|
-
result.push({
|
|
137068
|
-
recordId,
|
|
137069
|
-
symbol: match[4],
|
|
137070
|
-
path,
|
|
137071
|
-
kind,
|
|
137072
|
-
templateId: settings.templateId,
|
|
137073
|
-
persistedName: settings.name ?? basename(path),
|
|
137074
|
-
sourceFile: registry.source.uri,
|
|
137075
|
-
sourceLine: registry.source.range.start.line + 1
|
|
137076
|
-
});
|
|
137077
|
-
cursor = REGISTRY_ENTRY2.lastIndex;
|
|
137078
|
-
}
|
|
137079
|
-
return result;
|
|
137080
|
-
}
|
|
137081
|
-
function parseFileSettings2(source, templateIds) {
|
|
137082
|
-
if (!source) return { templateId: null, name: null };
|
|
137083
|
-
const expression = parseExpression(`new(${source})`);
|
|
137084
|
-
if (expression.kind !== "new")
|
|
137085
|
-
throw new Error("File @settings arguments are invalid.");
|
|
137086
|
-
let templateId = null;
|
|
137087
|
-
let name = null;
|
|
137088
|
-
expression.args.forEach((argument2, index) => {
|
|
137089
|
-
const argumentName = expression.argumentNames?.[index];
|
|
137090
|
-
if (!argumentName)
|
|
137091
|
-
throw new Error("File @settings arguments must be named.");
|
|
137092
|
-
if (argumentName === "template") {
|
|
137093
|
-
templateId = resolveTemplate2(argument2, templateIds);
|
|
137094
|
-
return;
|
|
137095
|
-
}
|
|
137096
|
-
if (argumentName === "name") {
|
|
137097
|
-
if (argument2.kind !== "litString")
|
|
137098
|
-
throw new Error("File @settings name must be a string literal.");
|
|
137099
|
-
name = argument2.value;
|
|
137100
|
-
return;
|
|
137101
|
-
}
|
|
137102
|
-
throw new Error(
|
|
137103
|
-
`Unknown project file @settings option ${argumentName}; expected template or name.`
|
|
137104
|
-
);
|
|
137105
|
-
});
|
|
137106
|
-
return { templateId, name };
|
|
137107
|
-
}
|
|
137108
|
-
function resolveTemplate2(expression, templates) {
|
|
137109
|
-
if (expression.kind === "litNull") return null;
|
|
137110
|
-
if (expression.kind === "ident") {
|
|
137111
|
-
const id2 = templates.get(expression.name);
|
|
137112
|
-
if (!id2)
|
|
137113
|
-
throw new Error(`Unknown file import template ${expression.name}.`);
|
|
137114
|
-
return id2;
|
|
137115
|
-
}
|
|
137116
|
-
if (expression.kind === "call" && expression.callee.kind === "ident" && expression.callee.name === "Reference") {
|
|
137117
|
-
const index = expression.argumentNames?.findIndex((name) => name === "id") ?? -1;
|
|
137118
|
-
const id2 = expression.args[index >= 0 ? index : 0];
|
|
137119
|
-
if (id2?.kind === "litString") return id2.value;
|
|
137120
|
-
}
|
|
137121
|
-
throw new Error(
|
|
137122
|
-
"File template must be a template symbol, Reference(id: ...), or null."
|
|
137123
|
-
);
|
|
137124
|
-
}
|
|
137125
|
-
function objectInitializerBody2(initializer, typeName) {
|
|
137126
|
-
const open = initializer.indexOf("{");
|
|
137127
|
-
const close = initializer.lastIndexOf("}");
|
|
137128
|
-
if (!/^new\s*\(\s*\)/.test(initializer.trim()) || open < 0 || close < open) {
|
|
137129
|
-
throw new Error(`${typeName} must use new() { ... }.`);
|
|
137130
|
-
}
|
|
137131
|
-
return initializer.slice(open + 1, close);
|
|
137132
|
-
}
|
|
137133
137013
|
function optionalString3(value) {
|
|
137134
137014
|
return typeof value === "string" ? value : null;
|
|
137135
137015
|
}
|
|
@@ -137178,25 +137058,18 @@ function visitBinaryFiles(directory, visit) {
|
|
|
137178
137058
|
visit(path);
|
|
137179
137059
|
}
|
|
137180
137060
|
}
|
|
137181
|
-
function safeFileName2(value) {
|
|
137182
|
-
const fileName2 = basename(value).replace(/[\\/]/g, "-");
|
|
137183
|
-
if (fileName2 === "." || fileName2 === ".." || fileName2.length === 0)
|
|
137184
|
-
throw new Error(`Invalid project filename ${JSON.stringify(value)}.`);
|
|
137185
|
-
return fileName2;
|
|
137186
|
-
}
|
|
137187
137061
|
function safePathSegment2(value) {
|
|
137188
137062
|
return value.replace(/[^A-Za-z0-9._-]/g, "_") || "file";
|
|
137189
137063
|
}
|
|
137190
137064
|
function normalizeSlash2(value) {
|
|
137191
137065
|
return value.split(sep2).join("/").replaceAll("\\", "/");
|
|
137192
137066
|
}
|
|
137193
|
-
var SUPPORTED_BINARY_TYPES
|
|
137067
|
+
var SUPPORTED_BINARY_TYPES;
|
|
137194
137068
|
var init_project_files = __esm({
|
|
137195
137069
|
"src/project-source/project-files.ts"() {
|
|
137196
137070
|
"use strict";
|
|
137197
137071
|
init_project_file_source();
|
|
137198
137072
|
init_workspace_source_path();
|
|
137199
|
-
init_executable_parser();
|
|
137200
137073
|
init_value_comparison();
|
|
137201
137074
|
init_source_format();
|
|
137202
137075
|
init_project_file_source();
|
|
@@ -137210,7 +137083,6 @@ var init_project_files = __esm({
|
|
|
137210
137083
|
[".mp3", { kind: "audio", mimeType: "audio/mpeg" }],
|
|
137211
137084
|
[".ogg", { kind: "audio", mimeType: "audio/ogg" }]
|
|
137212
137085
|
]);
|
|
137213
|
-
REGISTRY_ENTRY2 = /(?:@id\(\s*("(?:[^"\\]|\\.)*")\s*\)\s*)?(?:@settings\(([\s\S]*?)\)\s*)?(NeoImage|NeoAudioClip)\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*new\(\s*("(?:[^"\\]|\\.)*")\s*\)\s*;/gy;
|
|
137214
137086
|
}
|
|
137215
137087
|
});
|
|
137216
137088
|
|
|
@@ -140008,7 +139880,7 @@ async function pullProjectBinariesV4(args) {
|
|
|
140008
139880
|
const previous = args.previousRecords[key];
|
|
140009
139881
|
const localStatus = localById.get(record6.recordId);
|
|
140010
139882
|
const declarationPresent = args.destructive === true || args.localBinaries === void 0 || previous === void 0 || localStatus !== void 0;
|
|
140011
|
-
const path = localStatus?.path ?? previous?.projectBinary?.path ??
|
|
139883
|
+
const path = localStatus?.path ?? previous?.projectBinary?.path ?? canonicalProjectBinaryPathV4(record6.data);
|
|
140012
139884
|
const absolute = resolvePath(path);
|
|
140013
139885
|
const localDigest = existsSync9(absolute) ? sha256File(absolute) : null;
|
|
140014
139886
|
const baseDigest = previous?.projectBinary?.sha256 ?? readSha256(previous?.data) ?? null;
|
|
@@ -140130,7 +140002,7 @@ async function pullProjectBinariesV4(args) {
|
|
|
140130
140002
|
if (previous.recordKind !== "project-file") continue;
|
|
140131
140003
|
if (args.document.records.has(key)) continue;
|
|
140132
140004
|
const localStatus = localById.get(previous.recordId);
|
|
140133
|
-
const path = localStatus?.path ?? previous.projectBinary?.path ??
|
|
140005
|
+
const path = localStatus?.path ?? previous.projectBinary?.path ?? canonicalProjectBinaryPathV4(previous.data);
|
|
140134
140006
|
const absolute = resolvePath(path);
|
|
140135
140007
|
const localDigest = existsSync9(absolute) ? sha256File(absolute) : null;
|
|
140136
140008
|
const baseDigest = previous.projectBinary?.sha256 ?? readSha256(previous.data) ?? null;
|
|
@@ -140241,13 +140113,14 @@ var init_project_file_pull = __esm({
|
|
|
140241
140113
|
init_concurrency();
|
|
140242
140114
|
init_http();
|
|
140243
140115
|
init_value_comparison();
|
|
140116
|
+
init_project_file_source();
|
|
140244
140117
|
init_project_files();
|
|
140245
140118
|
DOWNLOAD_CONCURRENCY = 8;
|
|
140246
140119
|
}
|
|
140247
140120
|
});
|
|
140248
140121
|
|
|
140249
140122
|
// src/project-source/project-file-push.ts
|
|
140250
|
-
import {
|
|
140123
|
+
import { join as join11 } from "node:path";
|
|
140251
140124
|
import { readFileSync as readFileSync13 } from "node:fs";
|
|
140252
140125
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
140253
140126
|
async function cleanupRejectedProjectFilePushesV4(args) {
|
|
@@ -140323,11 +140196,17 @@ function prepareProjectFilePushesV4(args) {
|
|
|
140323
140196
|
if (mimeType === null) {
|
|
140324
140197
|
throw new Error(`Project file ${binary.path} has no MIME type.`);
|
|
140325
140198
|
}
|
|
140199
|
+
const name = change.nextData.name;
|
|
140200
|
+
if (typeof name !== "string") {
|
|
140201
|
+
throw new Error(
|
|
140202
|
+
`Project file ${recordId} has upload bytes but its source change has no name.`
|
|
140203
|
+
);
|
|
140204
|
+
}
|
|
140326
140205
|
prepared.push({
|
|
140327
140206
|
uploadToken: `${recordId}-${prepared.length}`,
|
|
140328
140207
|
recordId,
|
|
140329
140208
|
replaceFileId: binary.action === "upload" ? recordId : null,
|
|
140330
|
-
name
|
|
140209
|
+
name,
|
|
140331
140210
|
fileType: binary.kind,
|
|
140332
140211
|
mimeType,
|
|
140333
140212
|
byteLength: bytes.byteLength,
|
|
@@ -155834,12 +155713,12 @@ import {
|
|
|
155834
155713
|
unlinkSync as unlinkSync2,
|
|
155835
155714
|
writeFileSync as writeFileSync10
|
|
155836
155715
|
} from "node:fs";
|
|
155837
|
-
import { basename as
|
|
155716
|
+
import { basename as basename2, dirname as dirname8, join as join12 } from "node:path";
|
|
155838
155717
|
function writeUnityFile(path, content) {
|
|
155839
155718
|
mkdirSync9(dirname8(path), { recursive: true });
|
|
155840
155719
|
const temporary = join12(
|
|
155841
155720
|
dirname8(path),
|
|
155842
|
-
`.${
|
|
155721
|
+
`.${basename2(path)}.${randomUUID5()}.tmp`
|
|
155843
155722
|
);
|
|
155844
155723
|
try {
|
|
155845
155724
|
writeFileSync10(temporary, content);
|
|
@@ -158921,7 +158800,11 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
158921
158800
|
(id2) => rewritePlacementValueId(id2, replacements)
|
|
158922
158801
|
)
|
|
158923
158802
|
})),
|
|
158924
|
-
localStatus.sourceSnapshot
|
|
158803
|
+
localStatus.sourceSnapshot,
|
|
158804
|
+
localStatus.binaryFiles?.map((binary) => ({
|
|
158805
|
+
fileId: rewriteAssignedString(binary.fileId, replacements),
|
|
158806
|
+
path: binary.path
|
|
158807
|
+
}))
|
|
158925
158808
|
);
|
|
158926
158809
|
} catch (error) {
|
|
158927
158810
|
workspace.state = {
|
|
@@ -159199,7 +159082,7 @@ function rewriteFilesFromState(workspace, records2 = new Map(
|
|
|
159199
159082
|
data: recordState.data
|
|
159200
159083
|
}
|
|
159201
159084
|
])
|
|
159202
|
-
), preservedSourceFiles = /* @__PURE__ */ new Map(), recordFiles = /* @__PURE__ */ new Map(), localValues = workspace.state.localValues, sourceSnapshot) {
|
|
159085
|
+
), preservedSourceFiles = /* @__PURE__ */ new Map(), recordFiles = /* @__PURE__ */ new Map(), localValues = workspace.state.localValues, sourceSnapshot, binaryFiles) {
|
|
159203
159086
|
const result = emitProjectDocumentSourcesV4(
|
|
159204
159087
|
candidateValueRecordsForEmissionV4(
|
|
159205
159088
|
records2,
|
|
@@ -159209,7 +159092,7 @@ function rewriteFilesFromState(workspace, records2 = new Map(
|
|
|
159209
159092
|
{
|
|
159210
159093
|
recordFiles,
|
|
159211
159094
|
localValues,
|
|
159212
|
-
binaryPaths: workspaceBinaryPathsV4(workspace)
|
|
159095
|
+
binaryPaths: workspaceBinaryPathsV4(workspace, binaryFiles)
|
|
159213
159096
|
}
|
|
159214
159097
|
);
|
|
159215
159098
|
workspace.state.localValues = localValues;
|
|
@@ -172920,7 +172803,7 @@ import {
|
|
|
172920
172803
|
writeFileSync as writeFileSync15
|
|
172921
172804
|
} from "node:fs";
|
|
172922
172805
|
import {
|
|
172923
|
-
basename as
|
|
172806
|
+
basename as basename3,
|
|
172924
172807
|
dirname as dirname12,
|
|
172925
172808
|
isAbsolute as isAbsolute3,
|
|
172926
172809
|
join as join20,
|
|
@@ -173364,7 +173247,7 @@ function selectedSpecPaths(workspace, selectors) {
|
|
|
173364
173247
|
for (const selector of normalizedSelectors) {
|
|
173365
173248
|
if (selector.includes("/") || /[*?]/u.test(selector)) continue;
|
|
173366
173249
|
const basenameMatches = [...relativePaths.values()].filter(
|
|
173367
|
-
(path) =>
|
|
173250
|
+
(path) => basename3(path) === selector
|
|
173368
173251
|
);
|
|
173369
173252
|
if (basenameMatches.length > 1) {
|
|
173370
173253
|
throw new Error(
|
|
@@ -173373,7 +173256,7 @@ function selectedSpecPaths(workspace, selectors) {
|
|
|
173373
173256
|
}
|
|
173374
173257
|
}
|
|
173375
173258
|
const configuredIncludes = workspace.config.test?.include ?? [];
|
|
173376
|
-
const selectorMatches = (selector, path) => path === selector ||
|
|
173259
|
+
const selectorMatches = (selector, path) => path === selector || basename3(path) === selector || path.startsWith(`${selector.replace(/\/$/u, "")}/`) || globMatches(selector, path);
|
|
173377
173260
|
const selectedPaths = all.filter((absolutePath) => {
|
|
173378
173261
|
const path = relativePaths.get(absolutePath);
|
|
173379
173262
|
const configured = configuredIncludes.length === 0 || configuredIncludes.some((pattern) => globMatches(pattern, path));
|
|
@@ -174135,14 +174018,14 @@ function maintainNeoTestBuildCache(root, maxBytes = TEST_BUILD_CACHE_LIMIT_BYTES
|
|
|
174135
174018
|
return fromProtected === "" || !fromProtected.startsWith(`..${sep9}`) && fromProtected !== ".." && !isAbsolute3(fromProtected);
|
|
174136
174019
|
};
|
|
174137
174020
|
for (const file of testBuildFiles(root)) {
|
|
174138
|
-
if (!isProtected(file.path) &&
|
|
174021
|
+
if (!isProtected(file.path) && basename3(file.path).includes(".tmp-") && now - file.modifiedMs >= ABANDONED_TEMP_MAX_AGE_MS) {
|
|
174139
174022
|
rmSync10(file.path, { force: true });
|
|
174140
174023
|
}
|
|
174141
174024
|
}
|
|
174142
174025
|
const files = testBuildFiles(root);
|
|
174143
174026
|
let total = files.reduce((sum, file) => sum + file.size, 0);
|
|
174144
174027
|
const removable = files.filter(
|
|
174145
|
-
(file) =>
|
|
174028
|
+
(file) => basename3(file.path) !== "manifest.json" && !isProtected(file.path)
|
|
174146
174029
|
).sort((left, right) => left.modifiedMs - right.modifiedMs);
|
|
174147
174030
|
for (const file of removable) {
|
|
174148
174031
|
if (total <= maxBytes) break;
|
|
@@ -180887,7 +180770,7 @@ __export(dev_exports, {
|
|
|
180887
180770
|
runDev: () => runDev
|
|
180888
180771
|
});
|
|
180889
180772
|
import { watch } from "node:fs";
|
|
180890
|
-
import { basename as
|
|
180773
|
+
import { basename as basename4, dirname as dirname13 } from "node:path";
|
|
180891
180774
|
import { emitKeypressEvents } from "node:readline";
|
|
180892
180775
|
async function runDev(loadWorkspace2, options) {
|
|
180893
180776
|
const root = loadWorkspace2().root;
|
|
@@ -180924,7 +180807,7 @@ async function runDev(loadWorkspace2, options) {
|
|
|
180924
180807
|
const watchConfigAsset = (path) => {
|
|
180925
180808
|
if (configWatch?.path === path) return;
|
|
180926
180809
|
configWatch?.watcher.close();
|
|
180927
|
-
const name =
|
|
180810
|
+
const name = basename4(path);
|
|
180928
180811
|
const watcher = watch(dirname13(path), (_event, filename) => {
|
|
180929
180812
|
if (filename === name) schedule();
|
|
180930
180813
|
});
|
|
@@ -181391,7 +181274,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
181391
181274
|
async function main() {
|
|
181392
181275
|
const args = parseArgs(process.argv.slice(2));
|
|
181393
181276
|
if (args.command === "--version") {
|
|
181394
|
-
console.log("0.70.
|
|
181277
|
+
console.log("0.70.1");
|
|
181395
181278
|
return;
|
|
181396
181279
|
}
|
|
181397
181280
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -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.70.
|
|
12
|
+
<!-- reviewed-through-cli: 0.70.1 -->
|
|
13
13
|
|
|
14
14
|
# Neo Compose CLI
|
|
15
15
|
|
|
@@ -237,7 +237,9 @@ Registry declarations and their image/audio paths may be in any project folder
|
|
|
237
237
|
outside ignored/private directories. Update the registry path when moving a
|
|
238
238
|
binary file. Renaming the registry symbol or replacing bytes retains the file
|
|
239
239
|
ID when the declaration keeps its `@id`; keep the symbol aligned with the
|
|
240
|
-
persisted file name, or set `@settings(name: ...)` explicitly.
|
|
240
|
+
persisted file name, or set `@settings(name: ...)` explicitly. The name must
|
|
241
|
+
end with the binary's extension, as in `@settings(name: "ClinkingCoin1.mp3")`,
|
|
242
|
+
because pull rebuilds the file's path from it.
|
|
241
243
|
Omitting `@settings(template: ...)` uses the complete built-in Unity import
|
|
242
244
|
defaults for that file kind.
|
|
243
245
|
|
|
@@ -110,7 +110,7 @@ wrappers.
|
|
|
110
110
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
111
111
|
|
|
112
112
|
```html
|
|
113
|
-
<!-- reviewed-through-cli: 0.70.
|
|
113
|
+
<!-- reviewed-through-cli: 0.70.1 -->
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -263,7 +263,8 @@ Registry symbols derive deterministically from the persisted file name. For
|
|
|
263
263
|
example, `tree.cherryblossom.png` becomes `TreeCherryblossom`. Keep an authored
|
|
264
264
|
declaration aligned with that spelling, or set an explicit persisted name such
|
|
265
265
|
as `@settings(name: "TreeCherryBlossom.png")` when the binary path should stay
|
|
266
|
-
different.
|
|
266
|
+
different. The name must end with the binary's extension, because pull
|
|
267
|
+
rebuilds the file's path from it. With no template annotation, the CLI persists the complete built-in
|
|
267
268
|
Unity defaults for the file kind.
|
|
268
269
|
|
|
269
270
|
Pull/push compare server-verified SHA-256, not storage ETags. A divergent
|