@neocompose/cli 0.21.2 → 0.21.3
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 +11 -0
- package/dist/neo.mjs +152 -41
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +3 -0
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/commands-and-sync.md +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.21.3] - 2026-08-03
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- `neo push` paints its preparation spinner before workspace discovery,
|
|
8
|
+
lowering, and NeoScript compilation begin, so large projects no longer look
|
|
9
|
+
stalled before the push plan appears.
|
|
10
|
+
- Animation segment frame values are emitted through the required `value`
|
|
11
|
+
constructor argument. Required sprites use the canonical `SpriteInfo.Empty`
|
|
12
|
+
value; `null` is reserved for nullable `SpriteInfo?` values.
|
|
13
|
+
|
|
3
14
|
## [0.21.2] - 2026-08-03
|
|
4
15
|
|
|
5
16
|
### Fixed
|
package/dist/neo.mjs
CHANGED
|
@@ -842,7 +842,7 @@ function vectorTypes() {
|
|
|
842
842
|
members: structuredLeafFieldProperties(name)
|
|
843
843
|
}));
|
|
844
844
|
}
|
|
845
|
-
var NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_TYPES, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
|
|
845
|
+
var NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_TYPES, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, SPRITE_INFO_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID, NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
|
|
846
846
|
var init_language_spec = __esm({
|
|
847
847
|
"../packages/neoscript-language/src/language-spec.ts"() {
|
|
848
848
|
"use strict";
|
|
@@ -1006,6 +1006,10 @@ var init_language_spec = __esm({
|
|
|
1006
1006
|
kind: "primitive",
|
|
1007
1007
|
name: "ImageRef"
|
|
1008
1008
|
};
|
|
1009
|
+
SPRITE_INFO_TYPE = {
|
|
1010
|
+
kind: "primitive",
|
|
1011
|
+
name: "SpriteInfo"
|
|
1012
|
+
};
|
|
1009
1013
|
FLOAT_OPTIONAL_TYPE = {
|
|
1010
1014
|
kind: "primitive",
|
|
1011
1015
|
name: "float",
|
|
@@ -1148,12 +1152,26 @@ var init_language_spec = __esm({
|
|
|
1148
1152
|
"Returns whether a dialogue pointer has been visited."
|
|
1149
1153
|
)
|
|
1150
1154
|
];
|
|
1155
|
+
NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID = "builtin:SpriteInfo:property:Empty";
|
|
1156
|
+
NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE = Object.freeze({
|
|
1157
|
+
fileId: "",
|
|
1158
|
+
sliceIndex: 0
|
|
1159
|
+
});
|
|
1151
1160
|
NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
|
|
1152
1161
|
{
|
|
1153
1162
|
id: "builtin:SpriteInfo",
|
|
1154
1163
|
name: "SpriteInfo",
|
|
1155
1164
|
kind: "builtin",
|
|
1156
1165
|
members: [
|
|
1166
|
+
{
|
|
1167
|
+
...property(
|
|
1168
|
+
"SpriteInfo",
|
|
1169
|
+
"Empty",
|
|
1170
|
+
SPRITE_INFO_TYPE,
|
|
1171
|
+
"An authored empty sprite at slice zero."
|
|
1172
|
+
),
|
|
1173
|
+
static: true
|
|
1174
|
+
},
|
|
1157
1175
|
// `FileId` and `SliceIndex` come from the field table above — they are
|
|
1158
1176
|
// the writable, addressable fields, not derived properties (D11).
|
|
1159
1177
|
...structuredLeafFieldProperties("SpriteInfo"),
|
|
@@ -9739,6 +9757,12 @@ var init_strict_resolver = __esm({
|
|
|
9739
9757
|
}
|
|
9740
9758
|
resolveMemberNatural(receiverAst, name, scope, pos, optional) {
|
|
9741
9759
|
if (receiverAst.kind === "ident" && !scope.lookup(receiverAst.name)) {
|
|
9760
|
+
if (receiverAst.name === "SpriteInfo" && name === "Empty") {
|
|
9761
|
+
return literal(
|
|
9762
|
+
{ kind: "primitive", name: "SpriteInfo" },
|
|
9763
|
+
{ ...NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE }
|
|
9764
|
+
);
|
|
9765
|
+
}
|
|
9742
9766
|
const staticType = this.project.typeByName.get(receiverAst.name);
|
|
9743
9767
|
if (staticType && staticType.kind !== "enum") {
|
|
9744
9768
|
if (optional) {
|
|
@@ -9769,6 +9793,11 @@ var init_strict_resolver = __esm({
|
|
|
9769
9793
|
pos
|
|
9770
9794
|
);
|
|
9771
9795
|
}
|
|
9796
|
+
if (member.id === NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID) {
|
|
9797
|
+
return literal(member.type, {
|
|
9798
|
+
...NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE
|
|
9799
|
+
});
|
|
9800
|
+
}
|
|
9772
9801
|
if (member.computed === true) {
|
|
9773
9802
|
return {
|
|
9774
9803
|
pointer: {
|
|
@@ -38004,10 +38033,10 @@ function isSpriteValue(value) {
|
|
|
38004
38033
|
if (!Number.isInteger(sliceIndex)) return false;
|
|
38005
38034
|
return sliceIndex >= 0;
|
|
38006
38035
|
}
|
|
38007
|
-
function
|
|
38036
|
+
function emptySpriteValue() {
|
|
38008
38037
|
return { fileId: "", sliceIndex: 0 };
|
|
38009
38038
|
}
|
|
38010
|
-
function
|
|
38039
|
+
function isEmptySpriteValue(value) {
|
|
38011
38040
|
if (!value || typeof value !== "object") return false;
|
|
38012
38041
|
return getField(value, "fileId") === "" && getField(value, "sliceIndex") === 0;
|
|
38013
38042
|
}
|
|
@@ -38910,6 +38939,7 @@ var init_world_system_classes_generated = __esm({
|
|
|
38910
38939
|
{
|
|
38911
38940
|
memberId: "system_cbd6db9a-f473-44b5-b913-7cdc06452f35",
|
|
38912
38941
|
memberKind: "sprite",
|
|
38942
|
+
defaultValue: { fileId: "", sliceIndex: 0 },
|
|
38913
38943
|
required: true,
|
|
38914
38944
|
schemaKey: "Sprite"
|
|
38915
38945
|
},
|
|
@@ -39032,6 +39062,7 @@ var init_world_system_classes_generated = __esm({
|
|
|
39032
39062
|
{
|
|
39033
39063
|
memberId: "system_e9288ba9-f5a2-4485-8443-6afb155b31e0",
|
|
39034
39064
|
memberKind: "sprite",
|
|
39065
|
+
defaultValue: { fileId: "", sliceIndex: 0 },
|
|
39035
39066
|
required: true,
|
|
39036
39067
|
schemaKey: "Sprite"
|
|
39037
39068
|
},
|
|
@@ -39516,6 +39547,12 @@ var init_world_system_classes_generated = __esm({
|
|
|
39516
39547
|
docsText: "One value at a frame index inside a segment. It holds until the next row\nyou author, or until the segment's Duration runs out.",
|
|
39517
39548
|
extendsWorldKind: "animationFrameBase",
|
|
39518
39549
|
isAbstract: false,
|
|
39550
|
+
constructorProjections: [
|
|
39551
|
+
{
|
|
39552
|
+
memberId: "system_b71d1f73-da72-49de-ab9a-911cc9bffa43",
|
|
39553
|
+
parameterName: "value"
|
|
39554
|
+
}
|
|
39555
|
+
],
|
|
39519
39556
|
genericParams: [
|
|
39520
39557
|
{ id: "system_887b11d3-e56a-47ff-8d01-e2fcefb846a1", name: "T" }
|
|
39521
39558
|
],
|
|
@@ -42586,7 +42623,7 @@ function stampGenericBindings(value, member, args) {
|
|
|
42586
42623
|
}
|
|
42587
42624
|
function shouldSkipRequiredChildDefault(member) {
|
|
42588
42625
|
if (member.defaultValue !== void 0) return false;
|
|
42589
|
-
return
|
|
42626
|
+
return isMemberAudioBase(member);
|
|
42590
42627
|
}
|
|
42591
42628
|
function shouldMaterializeChildDefault(member) {
|
|
42592
42629
|
if (isMemberClassBase(member) && member.partial === true) return false;
|
|
@@ -42658,7 +42695,7 @@ function primitiveFallbackValue(document, member) {
|
|
|
42658
42695
|
if (isMemberLookupBase(member)) return { value: [] };
|
|
42659
42696
|
if (isMemberDialogueLookupBase(member)) return { value: [] };
|
|
42660
42697
|
if (isMemberSpriteBase(member)) {
|
|
42661
|
-
return { value:
|
|
42698
|
+
return { value: emptySpriteValue() };
|
|
42662
42699
|
}
|
|
42663
42700
|
if (isMemberAudioBase(member)) {
|
|
42664
42701
|
return { value: pendingAudioValue() };
|
|
@@ -42682,7 +42719,7 @@ function primitiveFallbackValue(document, member) {
|
|
|
42682
42719
|
function isPendingFileMemberValue(member, body) {
|
|
42683
42720
|
const value = body.value;
|
|
42684
42721
|
if (isMemberSpriteBase(member)) {
|
|
42685
|
-
return
|
|
42722
|
+
return isEmptySpriteValue(value);
|
|
42686
42723
|
}
|
|
42687
42724
|
if (isMemberAudioBase(member)) {
|
|
42688
42725
|
return isPendingAudioValue(value);
|
|
@@ -42768,11 +42805,18 @@ function validateDecimalMemberValue(member, body) {
|
|
|
42768
42805
|
}
|
|
42769
42806
|
function validateSpriteMemberValue(document, member, body) {
|
|
42770
42807
|
const spriteValue = body.value;
|
|
42808
|
+
if (spriteValue === null) {
|
|
42809
|
+
if (!member.required) return;
|
|
42810
|
+
throw new Error(
|
|
42811
|
+
`Sprite member "${member.name}" is required and cannot be null.`
|
|
42812
|
+
);
|
|
42813
|
+
}
|
|
42771
42814
|
if (!isSpriteValue(spriteValue)) {
|
|
42772
42815
|
throw new Error(
|
|
42773
42816
|
"Sprite value must be { fileId: string, sliceIndex: integer >= 0 }."
|
|
42774
42817
|
);
|
|
42775
42818
|
}
|
|
42819
|
+
if (isEmptySpriteValue(spriteValue)) return;
|
|
42776
42820
|
validateSpriteFileRegistration(document, member, spriteValue.fileId);
|
|
42777
42821
|
}
|
|
42778
42822
|
function validateSpriteFileRegistration(document, member, fileId) {
|
|
@@ -44993,6 +45037,9 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
|
|
|
44993
45037
|
}
|
|
44994
45038
|
switch (expression.kind) {
|
|
44995
45039
|
case "litNull":
|
|
45040
|
+
if (!expected.nullable) {
|
|
45041
|
+
throw new Error(`Required value ${path} cannot be null.`);
|
|
45042
|
+
}
|
|
44996
45043
|
return null;
|
|
44997
45044
|
case "litBool":
|
|
44998
45045
|
case "litString":
|
|
@@ -45212,6 +45259,9 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
|
|
|
45212
45259
|
);
|
|
45213
45260
|
}
|
|
45214
45261
|
case "member": {
|
|
45262
|
+
if (expected.name === "SpriteInfo" && expression.name === "Empty" && expression.receiver.kind === "ident" && expression.receiver.name === "SpriteInfo") {
|
|
45263
|
+
return { fileId: "", sliceIndex: 0 };
|
|
45264
|
+
}
|
|
45215
45265
|
const fileId = projectFileIdForPath(context, expression);
|
|
45216
45266
|
if (fileId !== null) return { fileId };
|
|
45217
45267
|
if (expression.name === "Slice" || expression.receiver.kind === "call") {
|
|
@@ -77143,7 +77193,12 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
|
|
|
77143
77193
|
}
|
|
77144
77194
|
function lowerValueBody(context, member, expression, base, source, environment, authoredSlice) {
|
|
77145
77195
|
const next = valueFileFields(base);
|
|
77146
|
-
if (expression.kind === "litNull")
|
|
77196
|
+
if (expression.kind === "litNull") {
|
|
77197
|
+
if (member.required) {
|
|
77198
|
+
throw new Error(`Required member ${member.name} cannot store null.`);
|
|
77199
|
+
}
|
|
77200
|
+
return { ...next, value: null };
|
|
77201
|
+
}
|
|
77147
77202
|
switch (member.kind) {
|
|
77148
77203
|
case "null":
|
|
77149
77204
|
return { ...next, value: null };
|
|
@@ -78127,6 +78182,9 @@ function expressionAnchorPos(expression) {
|
|
|
78127
78182
|
}
|
|
78128
78183
|
function lowerFileValue(context, member, expression) {
|
|
78129
78184
|
if (member.kind === "sprite") {
|
|
78185
|
+
if (isSpriteInfoEmptyExpression(expression)) {
|
|
78186
|
+
return { fileId: "", sliceIndex: 0 };
|
|
78187
|
+
}
|
|
78130
78188
|
if (expression.kind !== "call" || expression.callee.kind !== "member" || expression.callee.name !== "Slice") {
|
|
78131
78189
|
throw new Error(
|
|
78132
78190
|
`Sprite member ${member.name} requires Image.Slice(index).`
|
|
@@ -79114,7 +79172,8 @@ function emitValueBody(context, member, value, visited, targetTyped, environment
|
|
|
79114
79172
|
context,
|
|
79115
79173
|
kind,
|
|
79116
79174
|
`Audio member ${JSON.stringify(String(member.name ?? member.id))}`,
|
|
79117
|
-
body
|
|
79175
|
+
body,
|
|
79176
|
+
member.required === true
|
|
79118
79177
|
);
|
|
79119
79178
|
}
|
|
79120
79179
|
if (kind === 5)
|
|
@@ -79364,7 +79423,12 @@ function storedValueConstructor(context, schemaClass2, constructorArgs) {
|
|
|
79364
79423
|
return selected2;
|
|
79365
79424
|
}
|
|
79366
79425
|
function storedConstructorArgumentSource(context, type, value, environment, visited, cloneAggregateArguments = false) {
|
|
79367
|
-
if (value === null)
|
|
79426
|
+
if (value === null) {
|
|
79427
|
+
if (!type.nullable) {
|
|
79428
|
+
throw new Error("Required constructor argument stores null.");
|
|
79429
|
+
}
|
|
79430
|
+
return "null";
|
|
79431
|
+
}
|
|
79368
79432
|
switch (type.kind) {
|
|
79369
79433
|
case "null":
|
|
79370
79434
|
return "null";
|
|
@@ -79396,7 +79460,8 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
79396
79460
|
{
|
|
79397
79461
|
id: "__constructor_arg__",
|
|
79398
79462
|
name: "argument",
|
|
79399
|
-
kind: 11 /* Sprite
|
|
79463
|
+
kind: 11 /* Sprite */,
|
|
79464
|
+
required: !type.nullable
|
|
79400
79465
|
},
|
|
79401
79466
|
value
|
|
79402
79467
|
);
|
|
@@ -79405,7 +79470,8 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
79405
79470
|
context,
|
|
79406
79471
|
12 /* Audio */,
|
|
79407
79472
|
"constructor argument",
|
|
79408
|
-
value
|
|
79473
|
+
value,
|
|
79474
|
+
!type.nullable
|
|
79409
79475
|
);
|
|
79410
79476
|
case "enum":
|
|
79411
79477
|
return enumValue(
|
|
@@ -80180,8 +80246,13 @@ function delegateValue(context, body) {
|
|
|
80180
80246
|
}
|
|
80181
80247
|
return target.name;
|
|
80182
80248
|
}
|
|
80183
|
-
function fileValue(context, kind, label, body) {
|
|
80184
|
-
if (body === null || body === void 0)
|
|
80249
|
+
function fileValue(context, kind, label, body, required2) {
|
|
80250
|
+
if (body === null || body === void 0) {
|
|
80251
|
+
if (required2) {
|
|
80252
|
+
throw new Error(`${label} is required and cannot store null.`);
|
|
80253
|
+
}
|
|
80254
|
+
return "null";
|
|
80255
|
+
}
|
|
80185
80256
|
if (!isObjectRecord2(body)) {
|
|
80186
80257
|
throw new Error(
|
|
80187
80258
|
`${label} stores ${JSON.stringify(body)}, which is not a file value record.`
|
|
@@ -80193,12 +80264,18 @@ function fileValue(context, kind, label, body) {
|
|
|
80193
80264
|
);
|
|
80194
80265
|
}
|
|
80195
80266
|
if (body.fileId.length === 0) {
|
|
80196
|
-
|
|
80267
|
+
if (kind === 11 && numberOr2(body.sliceIndex, 0) === 0) {
|
|
80268
|
+
return "SpriteInfo.Empty";
|
|
80269
|
+
}
|
|
80270
|
+
throw new Error(`${label} stores an invalid empty file value.`);
|
|
80197
80271
|
}
|
|
80198
80272
|
const base = fileRegistrySource(context, kind, body.fileId);
|
|
80199
80273
|
if (kind !== 11) return base;
|
|
80200
80274
|
return `${base}.Slice(${numberOr2(body.sliceIndex, 0)})`;
|
|
80201
80275
|
}
|
|
80276
|
+
function isSpriteInfoEmptyExpression(expression) {
|
|
80277
|
+
return expression.kind === "member" && expression.name === "Empty" && expression.receiver.kind === "ident" && expression.receiver.name === "SpriteInfo";
|
|
80278
|
+
}
|
|
80202
80279
|
function fileRegistrySource(context, kind, fileId) {
|
|
80203
80280
|
const symbol = context.fileSymbols.get(fileId);
|
|
80204
80281
|
if (symbol !== void 0) {
|
|
@@ -80223,7 +80300,9 @@ function structuredLeafSource(context, kind, member, body) {
|
|
|
80223
80300
|
${assignments.map((entry) => indentNeoSourceNonEmptyLines(entry, 2)).join(",\n")}
|
|
80224
80301
|
}`;
|
|
80225
80302
|
}
|
|
80226
|
-
if (kind === 11 /* Sprite */)
|
|
80303
|
+
if (kind === 11 /* Sprite */) {
|
|
80304
|
+
return fileValue(context, 11, label, body, member.required === true);
|
|
80305
|
+
}
|
|
80227
80306
|
if (body === null) return "null";
|
|
80228
80307
|
if (!isObjectRecord2(body)) return "new()";
|
|
80229
80308
|
return `new(${structuredLeafFieldKeys(kind).map((key) => scalar(body[key])).join(", ")})`;
|
|
@@ -94858,7 +94937,7 @@ async function downloadProjectVersionTransactionResult(args) {
|
|
|
94858
94937
|
cursor = page.continueCursor;
|
|
94859
94938
|
}
|
|
94860
94939
|
}
|
|
94861
|
-
async function
|
|
94940
|
+
async function preparePushStatus(workspace, options) {
|
|
94862
94941
|
const status = computeWorkspaceStatus(workspace);
|
|
94863
94942
|
if (status.conflictedFiles.length > 0) {
|
|
94864
94943
|
throw new Error(
|
|
@@ -94887,22 +94966,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
94887
94966
|
changes: status.changes,
|
|
94888
94967
|
binaryChanges: status.binaryChanges ?? []
|
|
94889
94968
|
});
|
|
94890
|
-
if (status.changes.length === 0)
|
|
94891
|
-
if (options.json === true) {
|
|
94892
|
-
console.log(
|
|
94893
|
-
JSON.stringify({
|
|
94894
|
-
type: "push-plan",
|
|
94895
|
-
dryRun: options.dryRun,
|
|
94896
|
-
changeCount: 0,
|
|
94897
|
-
staticValueSeedCount: 0,
|
|
94898
|
-
changes: []
|
|
94899
|
-
})
|
|
94900
|
-
);
|
|
94901
|
-
} else {
|
|
94902
|
-
console.log("Nothing to push \u2014 working copy is clean.");
|
|
94903
|
-
}
|
|
94904
|
-
return;
|
|
94905
|
-
}
|
|
94969
|
+
if (status.changes.length === 0) return status;
|
|
94906
94970
|
const initConversions = status.initConversions ?? [];
|
|
94907
94971
|
if (initConversions.length > 0 && options.json !== true) {
|
|
94908
94972
|
for (const line of describeInitConversions(initConversions)) warn(line);
|
|
@@ -94974,9 +95038,41 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
94974
95038
|
} catch (error) {
|
|
94975
95039
|
reportDryRunFailure(error, options.json === true);
|
|
94976
95040
|
process.exitCode = 1;
|
|
94977
|
-
return;
|
|
95041
|
+
return null;
|
|
94978
95042
|
}
|
|
94979
95043
|
}
|
|
95044
|
+
return status;
|
|
95045
|
+
}
|
|
95046
|
+
async function runPush(workspace, options, preparationOverride) {
|
|
95047
|
+
const preparation = preparationOverride === void 0 ? process.stdout.isTTY === true && options.json !== true ? spinner("Preparing push\u2026") : null : preparationOverride;
|
|
95048
|
+
let status;
|
|
95049
|
+
try {
|
|
95050
|
+
status = await preparePushStatus(workspace, options);
|
|
95051
|
+
} catch (error) {
|
|
95052
|
+
preparation?.fail("Push preparation failed.");
|
|
95053
|
+
throw error;
|
|
95054
|
+
}
|
|
95055
|
+
if (status === null) {
|
|
95056
|
+
preparation?.fail("Push preparation failed.");
|
|
95057
|
+
return;
|
|
95058
|
+
}
|
|
95059
|
+
preparation?.stop();
|
|
95060
|
+
if (status.changes.length === 0) {
|
|
95061
|
+
if (options.json === true) {
|
|
95062
|
+
console.log(
|
|
95063
|
+
JSON.stringify({
|
|
95064
|
+
type: "push-plan",
|
|
95065
|
+
dryRun: options.dryRun,
|
|
95066
|
+
changeCount: 0,
|
|
95067
|
+
staticValueSeedCount: 0,
|
|
95068
|
+
changes: []
|
|
95069
|
+
})
|
|
95070
|
+
);
|
|
95071
|
+
} else {
|
|
95072
|
+
console.log("Nothing to push \u2014 working copy is clean.");
|
|
95073
|
+
}
|
|
95074
|
+
return;
|
|
95075
|
+
}
|
|
94980
95076
|
if (options.json === true) {
|
|
94981
95077
|
console.log(
|
|
94982
95078
|
JSON.stringify({
|
|
@@ -98100,14 +98196,29 @@ async function main() {
|
|
|
98100
98196
|
return;
|
|
98101
98197
|
}
|
|
98102
98198
|
case "push": {
|
|
98103
|
-
const
|
|
98104
|
-
const
|
|
98105
|
-
|
|
98106
|
-
|
|
98107
|
-
|
|
98108
|
-
|
|
98109
|
-
|
|
98110
|
-
|
|
98199
|
+
const json = boolFlag(args, "json");
|
|
98200
|
+
const preparation = process.stdout.isTTY === true && json !== true ? spinner("Preparing push\u2026") : null;
|
|
98201
|
+
let handedOffPreparation = false;
|
|
98202
|
+
try {
|
|
98203
|
+
const workspace = loadWorkspaceForCommand(args);
|
|
98204
|
+
const { runPush: runPush2 } = await Promise.resolve().then(() => (init_push(), push_exports));
|
|
98205
|
+
handedOffPreparation = true;
|
|
98206
|
+
await runPush2(
|
|
98207
|
+
workspace,
|
|
98208
|
+
{
|
|
98209
|
+
dryRun: boolFlag(args, "dry-run"),
|
|
98210
|
+
summary: stringFlag(args, "summary"),
|
|
98211
|
+
acceptBump: boolFlag(args, "accept-bump"),
|
|
98212
|
+
json
|
|
98213
|
+
},
|
|
98214
|
+
preparation
|
|
98215
|
+
);
|
|
98216
|
+
} catch (error) {
|
|
98217
|
+
if (!handedOffPreparation) {
|
|
98218
|
+
preparation?.fail("Push preparation failed.");
|
|
98219
|
+
}
|
|
98220
|
+
throw error;
|
|
98221
|
+
}
|
|
98111
98222
|
return;
|
|
98112
98223
|
}
|
|
98113
98224
|
case "status": {
|
package/package.json
CHANGED
|
@@ -66,12 +66,15 @@ Use complete values in normal member initialization:
|
|
|
66
66
|
|
|
67
67
|
```neo
|
|
68
68
|
Sprite = Images.Hero.Slice(0);
|
|
69
|
+
Placeholder = SpriteInfo.Empty;
|
|
69
70
|
Position = new(0, 0, 0);
|
|
70
71
|
Tint = Color(1, 1, 1, 1);
|
|
71
72
|
```
|
|
72
73
|
|
|
73
74
|
A bare `Images.Hero` yields a file ID only in a file-valued field context.
|
|
74
75
|
Use `.Slice(index)` for a complete `SpriteInfo`.
|
|
76
|
+
Use `SpriteInfo.Empty` for an authored non-null empty sprite. Use `null` only
|
|
77
|
+
when the declared type is nullable `SpriteInfo?`.
|
|
75
78
|
|
|
76
79
|
NeoScript may read or write structured fields when the receiver's effective
|
|
77
80
|
storage permits it:
|
|
@@ -73,7 +73,7 @@ wrappers.
|
|
|
73
73
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
74
74
|
|
|
75
75
|
```html
|
|
76
|
-
<!-- reviewed-through-cli: 0.21.
|
|
76
|
+
<!-- reviewed-through-cli: 0.21.3 -->
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -37,6 +37,10 @@ validation — so a rejection that used to cost a real push and return an opaque
|
|
|
37
37
|
`preparation-failed` now reports before anything is sent. It does not prompt,
|
|
38
38
|
upload, commit, or rewrite source.
|
|
39
39
|
|
|
40
|
+
Interactive pushes show `Preparing push…` before workspace discovery,
|
|
41
|
+
lowering, and compilation begin. JSON and non-TTY output remain structured and
|
|
42
|
+
do not emit that terminal-only spinner.
|
|
43
|
+
|
|
40
44
|
A clean dry-run does not promise a clean push. The workspace holds its
|
|
41
45
|
last-pulled state, so everything that grades the live head is still server-only:
|
|
42
46
|
re-verification of the uploaded bundle bytes, project-file staging, the
|