@neocompose/cli 0.28.0 → 0.29.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 +18 -0
- package/dist/neo.mjs +74 -14
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +13 -11
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/values-identities-and-references.md +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.29.0] - 2026-08-12
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `Reference<T>(id: "...", withProvenance: true)` for executable NeoScript.
|
|
8
|
+
The opt-in flag resolves an authored row id to the nearest clone carrying it
|
|
9
|
+
as `sourceValueId` in the lexical receiver's ownership graph. It defaults to
|
|
10
|
+
`false`, preserving exact-ID behavior for every existing reference.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Animation child selectors created by the world UI and the legacy
|
|
15
|
+
`Child`-to-`Selector` reconciler now opt into provenance so clips authored
|
|
16
|
+
against a class default select each placement's cloned child.
|
|
17
|
+
- Unity export schema version is 19 and NeoScript compiler revision is 9.
|
|
18
|
+
Older SDKs reject the export rather than silently ignoring provenance and
|
|
19
|
+
applying an override to the shared authored row.
|
|
20
|
+
|
|
3
21
|
## [0.28.0] - 2026-08-12
|
|
4
22
|
|
|
5
23
|
### Added
|
package/dist/neo.mjs
CHANGED
|
@@ -7891,7 +7891,7 @@ var NEOSCRIPT_COMPILER_REVISION;
|
|
|
7891
7891
|
var init_strict_ir = __esm({
|
|
7892
7892
|
"../packages/neoscript-language/src/strict-ir.ts"() {
|
|
7893
7893
|
"use strict";
|
|
7894
|
-
NEOSCRIPT_COMPILER_REVISION =
|
|
7894
|
+
NEOSCRIPT_COMPILER_REVISION = 9;
|
|
7895
7895
|
}
|
|
7896
7896
|
});
|
|
7897
7897
|
|
|
@@ -10597,9 +10597,34 @@ var init_strict_resolver = __esm({
|
|
|
10597
10597
|
expression.pos
|
|
10598
10598
|
);
|
|
10599
10599
|
}
|
|
10600
|
-
|
|
10600
|
+
const hasProvenanceArgument = expression.args.length === 2;
|
|
10601
|
+
if (expression.args.length < 1 || expression.args.length > 2) {
|
|
10601
10602
|
throw new CompileError(
|
|
10602
|
-
"Reference<T> requires
|
|
10603
|
+
"Reference<T> requires id: string and optionally withProvenance: bool.",
|
|
10604
|
+
expression.pos
|
|
10605
|
+
);
|
|
10606
|
+
}
|
|
10607
|
+
if (expression.argumentNames?.[0] !== "id") {
|
|
10608
|
+
throw new CompileError(
|
|
10609
|
+
"Reference<T> requires id: as its first named argument.",
|
|
10610
|
+
expression.pos
|
|
10611
|
+
);
|
|
10612
|
+
}
|
|
10613
|
+
if (expression.args[0]?.kind !== "litString" || expression.args[0].value.length === 0) {
|
|
10614
|
+
throw new CompileError(
|
|
10615
|
+
"Reference<T> id must be a non-empty string literal.",
|
|
10616
|
+
expression.pos
|
|
10617
|
+
);
|
|
10618
|
+
}
|
|
10619
|
+
if (hasProvenanceArgument && expression.argumentNames?.[1] !== "withProvenance") {
|
|
10620
|
+
throw new CompileError(
|
|
10621
|
+
"Reference<T>'s second named argument must be withProvenance: bool.",
|
|
10622
|
+
expression.pos
|
|
10623
|
+
);
|
|
10624
|
+
}
|
|
10625
|
+
if (hasProvenanceArgument && expression.args[1]?.kind !== "litBool") {
|
|
10626
|
+
throw new CompileError(
|
|
10627
|
+
"Reference<T> withProvenance must be a boolean literal.",
|
|
10603
10628
|
expression.pos
|
|
10604
10629
|
);
|
|
10605
10630
|
}
|
|
@@ -10613,7 +10638,8 @@ var init_strict_resolver = __esm({
|
|
|
10613
10638
|
return {
|
|
10614
10639
|
pointer: {
|
|
10615
10640
|
type: "reference" /* Reference */,
|
|
10616
|
-
valueId: expression.args[0].value
|
|
10641
|
+
valueId: expression.args[0].value,
|
|
10642
|
+
...expression.args[1]?.kind === "litBool" && expression.args[1].value ? { withProvenance: true } : {}
|
|
10617
10643
|
},
|
|
10618
10644
|
type: referencedType
|
|
10619
10645
|
};
|
|
@@ -21834,7 +21860,9 @@ function validateReferenceExpression(expression, expected, environment, uri, ran
|
|
|
21834
21860
|
const typeArguments = expression.typeArguments ?? [];
|
|
21835
21861
|
const names = expression.argumentNames ?? [];
|
|
21836
21862
|
const idIndex = names.findIndex((name) => name === "id");
|
|
21863
|
+
const provenanceIndex = names.findIndex((name) => name === "withProvenance");
|
|
21837
21864
|
const hasId = idIndex >= 0;
|
|
21865
|
+
const hasProvenance = provenanceIndex >= 0;
|
|
21838
21866
|
const argument2 = expression.args[hasId ? idIndex : 0];
|
|
21839
21867
|
const malformed = (message) => pushDiagnostic(
|
|
21840
21868
|
diagnostics,
|
|
@@ -21878,9 +21906,11 @@ function validateReferenceExpression(expression, expected, environment, uri, ran
|
|
|
21878
21906
|
}
|
|
21879
21907
|
return;
|
|
21880
21908
|
}
|
|
21881
|
-
|
|
21909
|
+
const validIdShape = hasId && idIndex === 0 && expression.args.length === (hasProvenance ? 2 : 1) && (!hasProvenance || provenanceIndex === 1) && names.every((name) => name === "id" || name === "withProvenance");
|
|
21910
|
+
const validSymbolShape = !hasId && !hasProvenance && expression.args.length === 1 && names.every((name) => name === null);
|
|
21911
|
+
if (!validIdShape && !validSymbolShape) {
|
|
21882
21912
|
malformed(
|
|
21883
|
-
"Reference requires
|
|
21913
|
+
"Reference requires one symbol argument, or id: string followed by optional withProvenance: bool."
|
|
21884
21914
|
);
|
|
21885
21915
|
return;
|
|
21886
21916
|
}
|
|
@@ -21890,6 +21920,10 @@ function validateReferenceExpression(expression, expected, environment, uri, ran
|
|
|
21890
21920
|
malformed("Reference id must be one non-empty string literal.");
|
|
21891
21921
|
return;
|
|
21892
21922
|
}
|
|
21923
|
+
if (hasProvenance && expression.args[provenanceIndex]?.kind !== "litBool") {
|
|
21924
|
+
malformed("Reference withProvenance must be a boolean literal.");
|
|
21925
|
+
return;
|
|
21926
|
+
}
|
|
21893
21927
|
if (!explicit && expected?.name !== "string") {
|
|
21894
21928
|
malformed("Reference(id: ...) requires an explicit generic target type.");
|
|
21895
21929
|
return;
|
|
@@ -26596,7 +26630,11 @@ function projectSignatureHelp(analysis, document, position) {
|
|
|
26596
26630
|
return signatureResult(`@${callee.text}`, parameters, activeParameter);
|
|
26597
26631
|
}
|
|
26598
26632
|
if (callee.text === "Reference") {
|
|
26599
|
-
return signatureResult(
|
|
26633
|
+
return signatureResult(
|
|
26634
|
+
"Reference",
|
|
26635
|
+
["symbol or id", "withProvenance = false"],
|
|
26636
|
+
activeParameter
|
|
26637
|
+
);
|
|
26600
26638
|
}
|
|
26601
26639
|
if (callee.text === "Pause") {
|
|
26602
26640
|
return signatureResult(
|
|
@@ -38455,7 +38493,9 @@ function isNSKeyOf(value) {
|
|
|
38455
38493
|
}
|
|
38456
38494
|
function isNSPointerReference(value) {
|
|
38457
38495
|
const v = value;
|
|
38458
|
-
|
|
38496
|
+
if (v?.type !== "reference" /* reference */) return false;
|
|
38497
|
+
if (typeof v.valueId !== "string") return false;
|
|
38498
|
+
return v.withProvenance === void 0 || typeof v.withProvenance === "boolean";
|
|
38459
38499
|
}
|
|
38460
38500
|
function isNSPointerVariable(value) {
|
|
38461
38501
|
const v = value;
|
|
@@ -51301,9 +51341,14 @@ function collectFunctions(args) {
|
|
|
51301
51341
|
for (const action of node.actions) {
|
|
51302
51342
|
if (!isObjectRecord2(action) || action.type !== 0 || !isObjectRecord2(action.logic))
|
|
51303
51343
|
continue;
|
|
51304
|
-
if (action.logic.sourceInline === true || action.logic.type === 0 && isCompleteUIAction(action.logic.action))
|
|
51305
|
-
continue;
|
|
51306
51344
|
const useId = stringField(action, "id");
|
|
51345
|
+
if (action.logic.sourceInline === true) continue;
|
|
51346
|
+
if (action.logic.type === 0) {
|
|
51347
|
+
if (isCompleteUIAction(action.logic.action)) continue;
|
|
51348
|
+
throw new Error(
|
|
51349
|
+
`Dialogue action "${useId}" on actions node "${nodeId}" is incomplete. Complete or remove the action in Neo Compose before pulling.`
|
|
51350
|
+
);
|
|
51351
|
+
}
|
|
51307
51352
|
add(action.logic, `action:${useId}`, "void");
|
|
51308
51353
|
}
|
|
51309
51354
|
}
|
|
@@ -54332,6 +54377,16 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
|
|
|
54332
54377
|
if (expression.callee.kind === "ident" && expression.callee.name === "Reference") {
|
|
54333
54378
|
const index = expression.argumentNames?.findIndex((name) => name === "id") ?? -1;
|
|
54334
54379
|
if (index >= 0) {
|
|
54380
|
+
if (expression.argumentNames?.includes("withProvenance") === true) {
|
|
54381
|
+
throw new Error(
|
|
54382
|
+
`${path} writes Reference(id: ..., withProvenance: ...) as a persisted member value. Provenance-aware references are executable NeoScript values and must be used inside a function or delegate closure.`
|
|
54383
|
+
);
|
|
54384
|
+
}
|
|
54385
|
+
if (expression.args.length !== 1 || expression.argumentNames?.some((name) => name !== "id")) {
|
|
54386
|
+
throw new Error(
|
|
54387
|
+
`${path} writes Reference(id: ...) with unsupported arguments.`
|
|
54388
|
+
);
|
|
54389
|
+
}
|
|
54335
54390
|
const idArgument = expression.args[index];
|
|
54336
54391
|
if (idArgument?.kind === "litString") return idArgument.value;
|
|
54337
54392
|
throw new Error(
|
|
@@ -59911,13 +59966,14 @@ function evaluatorOwnershipDistances(rowId, indexes) {
|
|
|
59911
59966
|
indexes.ownershipDistancesByRowId.set(rowId, distances);
|
|
59912
59967
|
return distances;
|
|
59913
59968
|
}
|
|
59914
|
-
function resolveRuntimeReferenceRow(sourceValueId, ctx) {
|
|
59969
|
+
function resolveRuntimeReferenceRow(sourceValueId, ctx, withProvenance) {
|
|
59915
59970
|
const direct = evalValueById(
|
|
59916
59971
|
ctx,
|
|
59917
59972
|
sourceValueId,
|
|
59918
59973
|
ctx.__runtimeSessionValues,
|
|
59919
59974
|
ctx.__valueOverlay
|
|
59920
59975
|
);
|
|
59976
|
+
if (!withProvenance) return direct;
|
|
59921
59977
|
const receiver = trackedRowForValueReference(ctx.thisValue, ctx);
|
|
59922
59978
|
if (receiver === null) return direct;
|
|
59923
59979
|
const indexes = evaluatorIndexes(ctx);
|
|
@@ -62128,7 +62184,11 @@ function evalPointer(pointer, scope, ctx) {
|
|
|
62128
62184
|
return scope.get(pointer.variableId);
|
|
62129
62185
|
}
|
|
62130
62186
|
case "reference" /* reference */: {
|
|
62131
|
-
const row = resolveRuntimeReferenceRow(
|
|
62187
|
+
const row = resolveRuntimeReferenceRow(
|
|
62188
|
+
pointer.valueId,
|
|
62189
|
+
ctx,
|
|
62190
|
+
pointer.withProvenance === true
|
|
62191
|
+
);
|
|
62132
62192
|
if (!row) {
|
|
62133
62193
|
throw new NSGetterRuntimeError(
|
|
62134
62194
|
`Missing value reference: ${pointer.valueId}`
|
|
@@ -104470,7 +104530,7 @@ var init_registry2 = __esm({
|
|
|
104470
104530
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
104471
104531
|
formatVersion: 3,
|
|
104472
104532
|
contractVersion: "3.10",
|
|
104473
|
-
cliVersion: "0.
|
|
104533
|
+
cliVersion: "0.29.0",
|
|
104474
104534
|
projectFileUploadBatchSize: 32,
|
|
104475
104535
|
documentRecords: {
|
|
104476
104536
|
member: {
|
|
@@ -111036,7 +111096,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
111036
111096
|
async function main() {
|
|
111037
111097
|
const args = parseArgs(process.argv.slice(2));
|
|
111038
111098
|
if (args.command === "--version") {
|
|
111039
|
-
console.log("0.
|
|
111099
|
+
console.log("0.29.0");
|
|
111040
111100
|
return;
|
|
111041
111101
|
}
|
|
111042
111102
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -109,12 +109,14 @@ override replaces the whole leaf.
|
|
|
109
109
|
Frame overrides may change `Enabled`, `FlipX`, and `SortingOrder`; they may
|
|
110
110
|
not add, remove, or reorder `Children`.
|
|
111
111
|
|
|
112
|
-
Address direct children through selector delegates.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
Address direct children through selector delegates. Prefer the project's own
|
|
113
|
+
stable identity contract, such as an immutable `Name`, slug, or semantic
|
|
114
|
+
position. When a selector means one specific authored child slot whose
|
|
115
|
+
placement clones carry `sourceValueId`, return
|
|
116
|
+
`Reference<T>(id: "<authored-child-id>", withProvenance: true)`. The flag is
|
|
117
|
+
opt-in and defaults to `false`; without it the ID is matched exactly. Missing
|
|
118
|
+
optional child slots are skipped with diagnostics when the authored slot is
|
|
119
|
+
absent, while stale pre-provenance placements may still fail closed.
|
|
118
120
|
|
|
119
121
|
A placement row carries its `assetClassId` binding and optional `assetValueId`
|
|
120
122
|
override beside its schema keys. They are row provenance, not declared schema:
|
|
@@ -176,11 +178,11 @@ class LegPart : NeoObject {
|
|
|
176
178
|
```
|
|
177
179
|
|
|
178
180
|
Selectors may also be compatible inline closures. Prefer a named function when
|
|
179
|
-
the identity rule is reused or deserves an explicit failure message.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
pulled rows.
|
|
181
|
+
the identity rule is reused or deserves an explicit failure message. An exact
|
|
182
|
+
`Reference<T>(id: "...")` recreates the row-ID coupling selectors were
|
|
183
|
+
introduced to remove; use `withProvenance: true` only for a deliberately
|
|
184
|
+
authored slot identity. For new track rows, omit `@id` and let the successful
|
|
185
|
+
push assign it. Preserve IDs already present on pulled rows.
|
|
184
186
|
|
|
185
187
|
A selector argument such as `this.SelectPants` is evaluated in the lexical
|
|
186
188
|
scope of the class that declares the clip. Here `this` is the `LegPart`, not
|
|
@@ -83,7 +83,7 @@ wrappers.
|
|
|
83
83
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
84
84
|
|
|
85
85
|
```html
|
|
86
|
-
<!-- reviewed-through-cli: 0.
|
|
86
|
+
<!-- reviewed-through-cli: 0.29.0 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -83,6 +83,7 @@ supports:
|
|
|
83
83
|
Reference(Assets.Capitol)
|
|
84
84
|
Reference(root.Assets.Cosmetics.Pants)
|
|
85
85
|
Reference<Outpost>(id: "capitol-value-id")
|
|
86
|
+
Reference<NeoSpriteObject>(id: "authored-child-id", withProvenance: true)
|
|
86
87
|
Reference<PantsAsset>(key: "pants.long")
|
|
87
88
|
Reference<PantsAsset>(key: "pants.long", index: Slug)
|
|
88
89
|
Reference<Dialogue>(id: "capitol-dialogue-id")
|
|
@@ -95,14 +96,20 @@ Reference<Dialogue>(id: "capitol-dialogue-id")
|
|
|
95
96
|
- Use the generic `id:` form when the ID is the only target information. A
|
|
96
97
|
`Reference` call whose argument is neither `id:` nor `key:` is rejected by
|
|
97
98
|
name rather than read as an ID.
|
|
99
|
+
- Inside executable NeoScript, add `withProvenance: true` when the ID names an
|
|
100
|
+
authored row and the reference must select its nearest `sourceValueId` clone
|
|
101
|
+
in the lexical receiver's ownership graph. The parameter defaults to `false`;
|
|
102
|
+
absent or explicit `false` keeps exact-ID behavior. This option is not a
|
|
103
|
+
persisted member-default form.
|
|
98
104
|
- Both forms are legal in a member's declaration default, not only inside a
|
|
99
105
|
value graph. A key written there resolves after every pass has run, so it may
|
|
100
106
|
name a row the same push creates.
|
|
101
107
|
- Keep genuine structural references ID-based when their collection has no
|
|
102
108
|
stable symbol, path, or key surface. Animation track and frame-override
|
|
103
109
|
targets are selectors, not structural references: encode a stable
|
|
104
|
-
project-owned identity such as `Name` or slug
|
|
105
|
-
|
|
110
|
+
project-owned identity such as `Name` or slug. The exception is an authored
|
|
111
|
+
child slot whose placement clones retain `sourceValueId`: select that slot
|
|
112
|
+
with `Reference<T>(id: "...", withProvenance: true)`.
|
|
106
113
|
|
|
107
114
|
Declaration and file order do not affect resolution within one push. Cyclic
|
|
108
115
|
identity references are legal because they resolve IDs rather than evaluate a
|