@neocompose/cli 0.34.2 → 0.35.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.34.2",
3
+ "version": "0.35.1",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -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.34.2 -->
12
+ <!-- reviewed-through-cli: 0.35.1 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -47,9 +47,8 @@ Treat pull followed immediately by status or dry-run as a semantic no-op. If it
47
47
  reports project changes, stop and report a round-trip bug instead of pushing.
48
48
 
49
49
  The compiler reports file:line:column diagnostics and fails closed. Unknown
50
- non-null authorable server fields require a CLI contract update; never preserve
51
- them as opaque JSON or guessed syntax. An unknown top-level document field whose
52
- value is exactly JSON `null` is treated as absent.
50
+ authorable server fields require a CLI contract update; never preserve them as
51
+ opaque JSON or guessed syntax.
53
52
 
54
53
  ## Honor hard authoring invariants
55
54
 
@@ -198,6 +197,8 @@ AudioClipRegistry AudioClips = new() {
198
197
  Use `Images.Sword.Slice(0)` for a sprite and `AudioClips.SwordHit` for audio.
199
198
  Renaming the registry symbol, moving the local presentation, or replacing bytes
200
199
  retains the file ID.
200
+ Omitting `@settings(template: ...)` uses the complete built-in Unity import
201
+ defaults for that file kind.
201
202
 
202
203
  ## Resolve conflicts by identity
203
204
 
@@ -45,9 +45,17 @@ NeoVariant<ExampleObject> Down = new(
45
45
  required: it is the only way to construct through the variant.
46
46
  - `apply` takes exactly one parameter of the target class and is void. Omit it
47
47
  for a variant that is only ever constructed.
48
- - Both are ordinary delegate closures: parenthesized parameter list, block
49
- body, no expression-bodied form. The server compiles them, so authored source
50
- carries only the code.
48
+ - Both are ordinary delegate closures: parenthesized parameter list, then
49
+ either a block body or an expression body. `initialize` returns, so
50
+ `() => new ExampleObject(.Down)` works; `apply` is void, so its expression
51
+ body must be a call or an assignment, as in
52
+ `(source) => source.FacingDir = .Down`. The server compiles them, so authored
53
+ source carries only the code. Each closure has its own lexical scope, so
54
+ local names may be reused between `initialize` and `apply`.
55
+ - `overrides` and each child override's `overrides` value are `Partial<T>`
56
+ deltas over existing instances. They may use inferred `new { ... }` or
57
+ explicit `new Partial<T> { ... }`, and never pass arguments to or invoke
58
+ `T`'s constructor—even when `T` has a required constructor.
51
59
 
52
60
  Folders are records too, declared as their own globals and assigned per
53
61
  variant. Nesting is spelled in the path with `/`; intermediate segments are
@@ -346,8 +354,11 @@ node bindings scoped to their node/children. Give each persisted condition use,
346
354
  action invocation, mutation, pause, option, and node its own owner-scoped ID.
347
355
 
348
356
  Use `=> Next` or a trailing block with `return Next;`; do not author a `to:`
349
- argument. Require destinations for triggers, options, and outcomes. Permit
350
- terminal text/actions to fall through. Keep all statements for
357
+ argument. A destination arrow always follows an `=` initializer, as in
358
+ `= new(...) => Welcome;`; an arrow that instead follows a member name or a
359
+ parameter list's `)` is a NeoScript expression body, so the two never collide.
360
+ Require destinations for triggers, options, and outcomes. Permit terminal
361
+ text/actions to fall through. Keep all statements for
351
362
  `Actions Empty = new();` inside its body.
352
363
 
353
364
  After editing, run `neo dialogue dryrun <dialogue-ref>`. Exit 1 means the graph
@@ -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.34.2 -->
86
+ <!-- reviewed-through-cli: 0.35.1 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -25,6 +25,41 @@ Declare a setter's value type explicitly with the canonical form
25
25
  `set(int value) { ... }`. Project analysis, candidate materialization, and
26
26
  focused script commands all use the same accessor extraction.
27
27
 
28
+ A body whose whole point is one expression may be written as an expression
29
+ body, `=> expr;`. It is pure sugar for the block form — same compiled
30
+ instructions, same diagnostics, same stored source — and is available on
31
+ getter-only properties, individual accessors, and functions:
32
+
33
+ ```neo
34
+ public bool HasVisited => this.VisitCount > 0;
35
+
36
+ public int Clamped {
37
+ get => Math.Clamp(this.Raw, 0, 10);
38
+ set(int value) { this.Raw = value; }
39
+ }
40
+
41
+ public bool Unlocked(int level) => this.Level >= level;
42
+ ```
43
+
44
+ The `=>` is only an expression body where it directly follows the member name
45
+ or the parameter list's `)`. An arrow after an `=` initializer is always a
46
+ NeoFlow destination, so `override Trigger Trigger = new(...) => Welcome;`
47
+ keeps its meaning.
48
+
49
+ In a void context — a `void` function, a setter, or a void delegate — `=> expr`
50
+ is an expression statement rather than a return, so the expression must do
51
+ something: a call such as `void Ping() => this.OnChanged();`, or an assignment
52
+ such as `set(int value) => this.Raw = value;`. An expression whose value would
53
+ simply be discarded is rejected with a diagnostic that names the block body as
54
+ the fix.
55
+
56
+ `neo push` and `neo pull` canonicalize a stored body to the shorthand when its
57
+ authored spelling is exactly one `return` statement that fits on one line;
58
+ anything else re-emits as a block. Setters always re-emit as blocks. A push
59
+ preserves the form you authored for members it did not otherwise rewrite, so
60
+ choosing longhand for a one-line getter is stable; a fresh `neo pull` writes
61
+ the canonical shorthand.
62
+
28
63
  Declare a bodyless NeoScript contract with `abstract`, for example
29
64
  `public abstract bool Equals(Item other);`. Reserve `native` for host-provided
30
65
  functions; concrete NeoScript overrides inherit the abstract signature.
@@ -55,6 +90,15 @@ so later changes to the outer binding do not alter the closure. Explicit lambda
55
90
  parameter annotations accept the same type grammar as declarations, including
56
91
  `decimal`, generic parameters, collections, arrays, and nullable types.
57
92
 
93
+ A lambda may use an expression body too: `(x) => x * 2` is the block body
94
+ `(x) => { return x * 2; }`. In a void delegate the expression is a statement,
95
+ so it must call or assign. A dictionary-literal body needs parentheses,
96
+ `() => ({ "a": 1 })`, because a bare `{` after the arrow always opens a block.
97
+
98
+ ```neo
99
+ List<Item> ready = this.Items.Where((item) => item.Count > 0);
100
+ ```
101
+
58
102
  Calling `Equals(other)` on a non-null generic value dynamically uses the
59
103
  runtime Class's one-argument `Equals` Function or NSFunction when it returns
60
104
  `bool`, including the effective override. Values without that member fall back
@@ -39,9 +39,7 @@ class Assets {
39
39
  };
40
40
 
41
41
  @id("home-getter-id")
42
- static Outpost Home {
43
- get { return Assets.Capitol; }
44
- }
42
+ static Outpost Home => Assets.Capitol;
45
43
  }
46
44
  ```
47
45
 
@@ -172,7 +170,8 @@ diff, and dry-run do not rewrite its registry. A successful push creates the
172
170
  record, uploads verified bytes, and materializes its declaration and ID.
173
171
 
174
172
  Edit the typed registry declaration directly when an explicit symbol or
175
- non-default template is needed before push.
173
+ non-default template is needed before push. With no template annotation, the
174
+ CLI persists the complete built-in Unity defaults for the file kind.
176
175
 
177
176
  Pull/push compare server-verified SHA-256, not storage ETags. A divergent
178
177
  binary keeps local bytes and writes the verified remote side under