@neocompose/cli 0.76.2 → 0.77.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.76.2",
3
+ "version": "0.77.0",
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.76.2 -->
12
+ <!-- reviewed-through-cli: 0.77.0 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -129,7 +129,7 @@ wrappers.
129
129
  The marker near the top of `SKILL.md` must exactly match the package version:
130
130
 
131
131
  ```html
132
- <!-- reviewed-through-cli: 0.76.2 -->
132
+ <!-- reviewed-through-cli: 0.77.0 -->
133
133
  ```
134
134
 
135
135
  The quoted version above is checked too, so this instruction cannot go stale
@@ -86,11 +86,11 @@ that does not authorize copying the annotation onto authored records.
86
86
 
87
87
  Use context-aware typed annotations:
88
88
 
89
- - `@settings(...)` for format/search/selection/editor constraints.
89
+ - `@settings(...)` for format/search/collection/editor constraints.
90
90
  - `@storage(allowed: ...)` on classes and storage keys on members.
91
91
  - `@visibility(.Hidden)` only on a class; absence means visible.
92
92
  - Stateful settings use contextual enum cases, such as
93
- `@settings(format: .Plain)` and `@settings(selection: .Multi)`.
93
+ `@settings(format: .Plain)` and `@settings(kind: .Unordered)`.
94
94
  - `@settings(...)` before a `List` element or `Dictionary` value type
95
95
  configures the collection's entries: `List<@settings(format: .Plain) string>`,
96
96
  `Dictionary<string, @settings(min: 0) int>`. Only the member that declares
@@ -202,12 +202,27 @@ List getter.
202
202
  Use `.EnumCase` only when context fixes one enum type; otherwise write
203
203
  `EnumType.Case`. Constructor parameters supply this context for positional
204
204
  and named arguments, including substituted generic parameter types. Defaults
205
- and settings must be statically analyzable.
205
+ and settings must be statically analyzable. An integer is not an enum option.
206
+ Instance fields, static fields, and local value definitions report incompatible
207
+ enum initializers at the authored expression before value lowering. Extracting
208
+ a list or dictionary into a local preserves element validation. Errors point
209
+ to the entry in the local definition, including missing `.Option` or
210
+ `EnumType.Option` dictionary keys.
206
211
 
207
212
  An explicit construction must be assignable to its receiving type. For example,
208
213
  `List<Base>` accepts `new Derived()` when `Derived` inherits `Base`, but rejects
209
214
  an unrelated class at `new`. Generic arguments must also be compatible.
210
215
 
216
+ Primary-constructor parameters can initialize generic collection fields directly:
217
+
218
+ ```neo
219
+ class Box<T>(List<T> value) {
220
+ public List<T> Value = value;
221
+ }
222
+ ```
223
+
224
+ The same rule applies to `Dictionary<string, T>` and nested collections.
225
+
211
226
  ## Member and relation rules
212
227
 
213
228
  Infer member kind and optionality from its type and nullability. Treat the
@@ -216,14 +231,31 @@ the instance's recorded constructor or variant. They track later source-default
216
231
  edits until that field is explicitly overridden; resetting an override makes it
217
232
  virtual again.
218
233
 
219
- A lookup member's arity is its declared type. `public Config Config` selects one
220
- entry and its declared type is the entry type; `public Set<Config> Configs`
221
- selects several. An initializer body for a single-select lookup returns one
222
- entry, never a set.
234
+ Declare a lookup member as `Reference<T>`. `public Reference<Config> Config`
235
+ selects one row and reads as `Config`. `public Set<Reference<Config>> Configs`
236
+ selects several and reads as `Set<Config>`. An initializer body for a single
237
+ reference returns one row, never a set. `T` with `@settings(collection:)` is an
238
+ error; the language server's quick fix respells it.
239
+
240
+ `@settings(collection: Owner.Member)` binds the reference to one collection.
241
+ Without it the reference is unbound: it selects any stored row of `T` or a
242
+ subclass, anywhere in the project. The selected row's store decides writes. A
243
+ write through it to a Save row lands, and to an asset row it errors. Its
244
+ generated C# property is the read-only interface; call `TryWritable` to write.
245
+
246
+ An unbound default can name its row by a unique index:
247
+
248
+ ```neo
249
+ public Reference<Item> StarterSeed = root.Assets.Items.Index.Slug["seed.carrot"]!;
250
+ ```
251
+
252
+ The receiver is a `root` path to a List, `.Index.<Name>` is a unique index on
253
+ it, and the key is a string literal. Any other shape stays initializer code.
254
+
255
+ A `Reference<T>` member satisfies an interface `T Foo { get; }` or
256
+ `{ get; set; }` and an abstract `T Foo { get; }`.
223
257
 
224
- The CLI also accepts `List<T>` with `selection: .Multi` on a member. Emitted
225
- source uses `Set<T>`; constructor and function parameters must use `Set<T>`
226
- to carry selection semantics.
258
+ Constructor and function parameters use `Set<T>` for several selections.
227
259
 
228
260
  Declare a multicast event as `NeoAction<…>`. Its value is an ordered listener
229
261
  set, so give it a bracketed list of method groups — never a lambda, and never
@@ -124,6 +124,25 @@ Inline `NeoDelegate` lambdas may be returned, stored, or assigned to a typed
124
124
  local such as `NeoDelegate<int, int> twice = (x) => x * 2;`, and may read
125
125
  surrounding locals and parameters. Those values are captured when the lambda is
126
126
  created, so later changes to the outer binding do not alter the closure.
127
+ Any non-null delegate expression can be called directly, including
128
+ `callbacks[0](value)`, `(condition ? first : second)()`, and `Factory.Make()()`.
129
+ Force-unwrap a nullable delegate before calling it, as in `callbacks["key"]!()`.
130
+ Void delegates can only be called as statements.
131
+ Instance delegate field defaults are compiled against their declared signature.
132
+ Each instance binds defaults that read `this` to itself; invalid lambda bodies
133
+ are reported at the declaration by status, editor validation, and preparation.
134
+ Static delegate fields use static class scope: they can read static members
135
+ without an instance owner, and cannot access `this` or instance members.
136
+ Other static fields can call them in their initializers, as in
137
+ `public static int First = Helper.Run();`. Outside a lambda body, a field
138
+ initializer qualifies the members it reads; a bare `Run()` or `Number` there is
139
+ an unknown name.
140
+ Collection type arguments in constructions, such as `new Box<List<int>>([1, 2])`,
141
+ work even when no field declares that collection type. Preparation includes the
142
+ needed type descriptors; spec-only types remain in the test candidate.
143
+ Generic primary constructors also accept stored collection arguments, such as
144
+ `public static Box<List<int>> Value = new([1, 2]);`. Stored replay uses the closed
145
+ parameter type to preserve collection references.
127
146
  Typed locals also accept generic class types such as `Box<int> box = new(1);`.
128
147
  Explicit lambda parameter annotations accept the same type grammar as
129
148
  declarations, including `decimal`, generic parameters, collections, arrays, and
@@ -550,7 +569,7 @@ locally, like push. If another commit lands while it runs, the run is refused:
550
569
  run it again. `neo loc` writes work the same way: a write refused because
551
570
  another commit landed is run again.
552
571
 
553
- VS Code rename follows override families and class constructors, resolves contextual enum options such as `.Success`, renames a constructor parameter's named arguments (`new Item(count: 1)`) in bodies, initializers, specs, and base clauses, and keeps local-variable renames scoped to their declaration. Assigned IDs are not required for these refactorings.
572
+ VS Code rename follows override families and class constructors, resolves contextual enum options such as `.Success`, renames a constructor parameter's named arguments (`new Item(count: 1)`) in bodies, initializers, specs, and base clauses, and keeps local-variable renames scoped to their declaration. Assigned IDs are not required for these refactorings. Inferred locals initialized with conditional expressions retain their common branch type for member completion, navigation, and rename. Direct parenthesized expressions and chained delegate factory calls retain their result type too. `List.Repeat` results infer their element type from the value, explicit call-site type arguments, and expected list type, including for inferred locals and direct indexed access. Lambda returns use the delegate signature for target-typed constructors and enum argument suggestions. Member completion also follows optional access and null-forgiving receivers, including dictionary lookups.
554
573
 
555
574
  ## Member change listeners
556
575