@neocompose/cli 0.87.2 → 0.89.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +14 -0
  3. package/dist/neo-runtime.mjs +11153 -3060
  4. package/dist/test-worker.mjs +15214 -9707
  5. package/package.json +1 -1
  6. package/skills/neocompose-cli/SKILL.md +95 -279
  7. package/skills/neocompose-cli/references/cli-development.md +101 -117
  8. package/skills/neocompose-cli/references/declarations/annotations-and-storage.md +112 -0
  9. package/skills/neocompose-cli/references/declarations/constructors.md +164 -0
  10. package/skills/neocompose-cli/references/declarations/declarations.md +103 -0
  11. package/skills/neocompose-cli/references/declarations/extensions.md +46 -0
  12. package/skills/neocompose-cli/references/declarations/initializers.md +100 -0
  13. package/skills/neocompose-cli/references/declarations/member-kinds.md +107 -0
  14. package/skills/neocompose-cli/references/declarations/overloads.md +50 -0
  15. package/skills/neocompose-cli/references/dialogues.md +145 -0
  16. package/skills/neocompose-cli/references/neoscript/collections.md +138 -0
  17. package/skills/neocompose-cli/references/neoscript/control-flow.md +123 -0
  18. package/skills/neocompose-cli/references/neoscript/delegates-and-listeners.md +107 -0
  19. package/skills/neocompose-cli/references/neoscript/math-and-random.md +114 -0
  20. package/skills/neocompose-cli/references/neoscript/neoscript.md +113 -0
  21. package/skills/neocompose-cli/references/neoscript/strings.md +47 -0
  22. package/skills/neocompose-cli/references/neoscript/testing-and-migrations.md +73 -0
  23. package/skills/neocompose-cli/references/neoscript/types-and-narrowing.md +111 -0
  24. package/skills/neocompose-cli/references/sync/branches-and-history.md +69 -0
  25. package/skills/neocompose-cli/references/sync/conflicts-and-recovery.md +68 -0
  26. package/skills/neocompose-cli/references/sync/sync.md +96 -0
  27. package/skills/neocompose-cli/references/sync/unity-export.md +63 -0
  28. package/skills/neocompose-cli/references/values/defaults-and-localization.md +86 -0
  29. package/skills/neocompose-cli/references/values/files.md +71 -0
  30. package/skills/neocompose-cli/references/values/identities.md +97 -0
  31. package/skills/neocompose-cli/references/values/references.md +151 -0
  32. package/skills/neocompose-cli/references/values/values.md +110 -0
  33. package/skills/neocompose-cli/references/world/animation.md +133 -0
  34. package/skills/neocompose-cli/references/world/grids-and-cell-patterns.md +55 -0
  35. package/skills/neocompose-cli/references/world/variants.md +112 -0
  36. package/skills/neocompose-cli/references/world/world.md +105 -0
  37. package/skills/neocompose-cli/references/animation-and-world-authoring.md +0 -582
  38. package/skills/neocompose-cli/references/commands-and-sync.md +0 -408
  39. package/skills/neocompose-cli/references/declarations-and-construction.md +0 -773
  40. package/skills/neocompose-cli/references/neoscript.md +0 -990
  41. package/skills/neocompose-cli/references/values-identities-and-references.md +0 -421
@@ -1,421 +0,0 @@
1
- # Values, identities, and references
2
-
3
- Use this reference for root/static values, nested identities, references,
4
- localization, and managed project files.
5
-
6
- ## Contents
7
-
8
- - Root and static bindings
9
- - Identity rules
10
- - Same-push references
11
- - Defaults and localization
12
- - Managed files
13
-
14
- ## Root and static bindings
15
-
16
- Edit only the initializer after `=` in the compiler-owned `Root.neo` envelope.
17
- The root member name, type, member ID, lock, and storage metadata are read-only.
18
-
19
- ```neo
20
- Root root = new() {
21
- @id("root-assets-member-id")
22
- @storage(allowed: .Immutable)
23
- Assets Assets = new() {
24
- Outposts = [Assets.Capitol.Clone()],
25
- };
26
- }
27
- ```
28
-
29
- Do not place another `@id` immediately before the root initializer. The member
30
- ID owns the binding. Apply the same rule to static stored members:
31
-
32
- ```neo
33
- @id("assets-class-id")
34
- class Assets {
35
- @id("capitol-member-id")
36
- static Outpost Capitol = new {
37
- Name = "Capitol",
38
- };
39
-
40
- @id("home-getter-id")
41
- static Outpost Home => Assets.Capitol;
42
- }
43
- ```
44
-
45
- A computed static getter is an alias; it creates neither a binding nor a row.
46
-
47
- A static used in another initializer copies value kinds, including scalars and
48
- delegates. Class, list, set, and dictionary values have exactly one owner.
49
- Placing a value that something else already owns is refused: a static, a
50
- static's field, a collection entry, a local placed elsewhere, or a constructor
51
- parameter stored in an ordinary field. Status, push, and `neo test` report the
52
- placement at its authored position. Call `Clone()` to own a copy, or use
53
- `Reference`:
54
-
55
- ```neo
56
- static Outpost Annex = Assets.Capitol.Clone();
57
- static Reference<Outpost> Seat = Reference(Assets.Capitol);
58
- ```
59
-
60
- Statics created together may refer to each other regardless of declaration
61
- order; no preliminary push is needed.
62
-
63
- Enum-keyed dictionaries accept contextual or qualified option keys in defaults
64
- and stored values:
65
-
66
- ```neo
67
- Dictionary<ToolType, float> Damage = { .Pickaxe: 10, ToolType.Axe: 2 };
68
- ```
69
-
70
- Pull writes `.Option` for known keys. A quoted raw option ID is also accepted;
71
- a quoted option name such as `"Pickaxe"` is not an ID. Pull preserves orphaned
72
- keys as quoted IDs when their option has been deleted.
73
-
74
- ## Identity rules
75
-
76
- Preserve every existing ID through rename, reorder, and file moves. Renaming a
77
- schema member while keeping its ID preserves its owned value graph. Update
78
- initializer keys to the new name and retain existing child IDs, including when
79
- editing those children in the same change. A copy
80
- must get a new ID. A stored nested class value may keep its UUID-v4 when moved
81
- to an empty, compatible class field on another existing parent. Remove its
82
- old owning declaration in the same push. Both fields must declare the same
83
- non-generic class and storage rules. The move must leave exactly one owning
84
- path to the same root or static binding through ordinary class fields.
85
- Both ownership paths must use inherited storage and automatic distribution;
86
- member overrides are not supported for moves. Moving
87
- projected values, constructor-owned slots, partitioned values, generic
88
- instances, or unordered-list entries is refused. Moves into newly constructed
89
- parents are also refused; omit the ID to create a new value there.
90
-
91
- For a new ordinary record, omit
92
- `@id` and let a successful real push assign and insert it. Dry-run and failed pushes
93
- leave tracked source unchanged.
94
-
95
- A local initializer's existing row ID may precede its variable declaration:
96
-
97
- ```neo
98
- @id("existing-quest-row-id")
99
- Quest HardAsStone = new Quest() { Name = "Hard as stone" };
100
- ```
101
-
102
- This names the initializer row. It does not create a stored global. The inline
103
- `Quest HardAsStone = @id("...") new Quest();` spelling is also accepted, and
104
- formatting moves its ID above the declaration. Do not put an ID in both places.
105
-
106
- A local initializer such as `Delivery DeliveryRow = new()` retains `Delivery`
107
- when consumed by a base-class member. Aliases retain that same concrete type.
108
-
109
- Complete local member and collection initializers also work inside constructions
110
- that execute a constructor. Each local composes its owned subtree and preserves
111
- its concrete class:
112
-
113
- ```neo
114
- AudioFolder SFX_FOLDER = new("Sound effects") {
115
- Children = [UI_VOLUME, GAMEPLAY_VOLUME]
116
- };
117
- AudioSettings AUDIO_SETTINGS = new() { Main = SFX_FOLDER };
118
- ```
119
-
120
- In constructor arguments and executable operands, a class local names its one
121
- stored instance instead of constructing a copy. Its owning placement keeps it,
122
- so a constructor that stores it needs a `Reference` field:
123
-
124
- ```neo
125
- @id("86ac7c7d-8d3b-4642-9def-cdf32643bdc5")
126
- DeliveryQuest HARD_AS_STONE = new();
127
- // The core quest list owns HARD_AS_STONE.
128
- WorkflowStep UNLOCK = new QuestUnlockStep(HARD_AS_STONE);
129
-
130
- class QuestUnlockStep(DeliveryQuest quest) : WorkflowStep {
131
- public Reference<DeliveryQuest> Quest = quest;
132
- }
133
- ```
134
-
135
- The referenced local must have exactly one owning placement. A nested target
136
- needs its existing `@id`. A structurally owned list entry can also use an unused
137
- UUID-v4 in the same push. For a local nested inside an evaluated constructor,
138
- leave it idless on the first push; push assigns its actual identity before it can
139
- be referenced. Do not assign a fresh UUID to that nested construction. A direct static owning member can supply an idless local's pending identity.
140
- Aliases of that static local work too. A member default is a construction template,
141
- so its local does not identify a single stored instance. Unowned locals, ambiguous
142
- placements, and cycles are errors at source. Constructor argument type checking
143
- still applies. Canonical construction arguments may use `Reference<Type>(id: "…")`.
144
-
145
- Owned locals inside evaluated initializers need directly addressable fields, list
146
- entries, or literal dictionary keys; inline the construction when a computed key
147
- or other executable expression prevents tracking its owning path.
148
-
149
- Scalar locals remain complete-initializer bindings; inline their expressions when
150
- using them in arithmetic or constructor arguments. Closure bodies cannot capture
151
- project authoring locals.
152
-
153
- Nested class/list rows remain independently addressable and keep inline IDs:
154
-
155
- ```neo
156
- Tags = [
157
- @id("story-tag-item-id")
158
- "story",
159
- ];
160
- ```
161
-
162
- Never match an existing ordered row by index or payload. A bare row is pending
163
- create shorthand.
164
-
165
- When a same-push structural reference has no symbolic, path, or unique-key
166
- form, an author may assign a previously unseen UUID-v4 with `@id` to the new
167
- row and reference it in the same edit. Reusing an existing ID means update, not
168
- create. The server validates authored new IDs for UUID-v4 shape and uniqueness.
169
- Prefer generated IDs unless the structural reference needs an ID immediately.
170
- Dry-run preserves a valid authored UUID-v4 ID on a new nested member or dictionary
171
- value, including one declared as a local initializer. An unknown malformed member
172
- value ID is an error at its annotation; remove `@id` to let push assign the ID,
173
- or supply an unused UUID v4. This does not change the derived identity of a
174
- root/static binding or an existing projected value.
175
-
176
- Do not invent IDs for structural rows whose identities derive from an owner
177
- role. Do not add a separate root/static initializer ID. A constructor argument
178
- is one such row — its identity comes from the schema key its parameter settles
179
- — so it never carries `@id`, in either the named or the positional form.
180
-
181
- ## Same-push references
182
-
183
- `Reference<T>` and `Set<Reference<T>>` declare lookup storage. For a class
184
- `T`, their runtime values are `T` and `Set<T>`, so a projection can assign
185
- existing class values directly:
186
-
187
- ```neo
188
- EligibleIngredients = root.Assets.Crafting.FurnaceRecipes
189
- .Select((MachineRecipe recipe) => recipe.Ingredient)
190
- .ToSet()
191
- ```
192
-
193
- `Box<Reference<Item>>` keeps its reference storage type through push and pull,
194
- including explicit `new Box<Reference<Item>>()` calls. Its `Item` targets stay
195
- shared; reading a class reference still produces the class value. A derived
196
- construction in a base-typed slot retains reference bindings forwarded through
197
- the inheritance chain, such as `Base<Reference<Item>>` holding
198
- `new Derived<Reference<Item>>()`.
199
-
200
- Writing `Reference(recipe.Ingredient)` inside the callback is also valid.
201
- `Reference(value)` preserves an evaluated class value and its identity; it does
202
- not clone it or turn it into a separate wrapper object. An optional generic
203
- argument checks the target type. Lookup assignment still requires an existing
204
- backing row and enforces its declared target and collection constraints.
205
-
206
- A class-constrained generic lookup may select from a collection of its bound
207
- class. For example, `Reference<TAsset>` with `TAsset extends HeldItemAsset`
208
- may use `@settings(collection: CosmeticAssets.HeldItems)` when that collection
209
- holds `HeldItemAsset`. Derived classes may specialize the target and override
210
- the member; retain the collection setting on each override.
211
-
212
- Use the `Reference` intrinsic. Prefer the most readable form the target
213
- supports:
214
-
215
- ```neo
216
- Reference(Assets.Capitol)
217
- Reference(root.Assets.Cosmetics.Pants)
218
- Reference(root.Player.Gold)
219
- Reference<Outpost>(id: "capitol-value-id")
220
- Reference<NeoSpriteObject>(id: "authored-child-id", withProvenance: true)
221
- Reference<PantsAsset>(key: "pants.long")
222
- Reference<PantsAsset>(key: "pants.long", index: Slug)
223
- Reference<NeoDialogue>(id: "capitol-dialogue-id")
224
- ```
225
-
226
- - Use a symbol or root path when source can name the value directly. A
227
- value-type reference such as `Reference<int>` always names a member path or
228
- an `id:`; a plain value is an error.
229
- - Use `key:` only for a collection with a unique index. Omit `index:` when the
230
- collection has exactly one usable unique index; supply the bare member name
231
- when it has more than one.
232
- - Use the generic `id:` form when the ID is the only target information.
233
- Unrecognized named arguments are rejected rather than read as IDs.
234
- - Inside executable NeoScript, add `withProvenance: true` when the ID names an
235
- authored row and the reference must select its nearest `sourceValueId` clone
236
- in the lexical receiver's ownership graph. The parameter defaults to `false`;
237
- absent or explicit `false` keeps exact-ID behavior. This option is not a
238
- persisted member-default form.
239
- - Both forms are legal in a member's declaration default, not only inside a
240
- value graph. A key written there resolves after every pass has run, so it may
241
- name a row the same push creates.
242
- - List and dictionary declaration defaults can contain slot references, including
243
- nested collections: `List<Reference<int>> Counts = [Reference(root.Save.Bits)]`.
244
- Each instance owns its collection; entries continue to target the original
245
- root or static slot, including slots supplied by declaration defaults.
246
- - Keep genuine structural references ID-based when their collection has no
247
- stable symbol, path, or key surface. Animation track and frame-override
248
- targets are selectors, not structural references: encode a stable
249
- project-owned identity such as `Name` or slug. The exception is an authored
250
- child slot whose placement clones retain `sourceValueId`: select that slot
251
- with `Reference<T>(id: "...", withProvenance: true)`.
252
-
253
- Declaration and file order do not affect resolution within one push. Cyclic
254
- identity references are legal because they resolve IDs rather than evaluate a
255
- dependency graph. Validate against the project after the push: a row deleted by
256
- the edit is not a target, and lookup/dialogue references must still satisfy
257
- assignability, collection membership, multiplicity, and group constraints.
258
-
259
- `collectionValue` references follow the same post-push resolution and
260
- membership rules as member defaults. Name the collection itself, for example
261
- `root.Assets.Quests.Daily` or `Reference(root.Assets.Quests.Daily)`. Invalid
262
- reference-valued settings are errors; they never silently remove the binding.
263
- A path may traverse construction defaults
264
- and declarations created in the same push. Preparation materializes the target
265
- collection and its required ancestor rows together, preserving the virtual
266
- identities. No preliminary push or manual value ID is needed.
267
-
268
- An object Root.neo writes is init-built when its class has an `init` block. A
269
- declaration binding may name a member inside it, and the push stores that
270
- member's row so the binding has a target. A reference an `init` block or
271
- constructor captures, such as `new Rule(Reference(this.Weather))`, stores its
272
- target's ID and keeps the target's row. Status refuses two forms, because their
273
- target has no row to check until the push stores it: a value row's reference to
274
- a member of an init-built object (bind it from a declaration instead), and a
275
- binding to a class or list an `init` block builds. A project an older CLI pushed
276
- with such a captured reference stored it without its target; push once to
277
- repair it.
278
-
279
- ## Defaults and localization
280
-
281
- A class member whose default constructs its declared type emits a contextual
282
- `= new()`, including populated defaults and defaults whose value row is
283
- virtual. A default that constructs a subclass keeps the concrete type, such as
284
- `Base Value = new Derived();`. Edit the declaration to change the shared
285
- default, or assign the member inside an instance initializer to override only
286
- that instance. Leaving the emitted construction unchanged creates no redundant
287
- value rows. A nullable member with no default remains bare; an explicit null
288
- default emits `= null`.
289
-
290
- Changing a construction to another overload or shared argument rebuilds the
291
- instance even when the argument values compare equal. Owned inline arguments
292
- still compare by contents; unchanged shared arguments keep their identities.
293
-
294
- Spelling an unchanged child default, such as `FPS = 8`, stays a no-op after
295
- push even when sibling fields own stored rows. Adding a different child default
296
- preserves those siblings' row identities; it does not transfer their ownership.
297
-
298
- Omitted members are virtual projections of the instance's recorded constructor
299
- or variant. Later edits to that source update every omitted member. Writing a
300
- member creates a sparse override with its deterministic projected ID; removing
301
- that member from an existing initializer resets the override and resumes source
302
- tracking. Require either transition to appear in `neo diff`.
303
-
304
- A stored class with no construction record still inherits literal declaration
305
- defaults for omitted fields. For example, `FoodInfo.Quality = .OneStar` supplies
306
- the quality of an existing food row that stores only its price. Do not add an
307
- instance override to repair that omission. Reads do not invent a historical
308
- constructor, and required fields with no applicable default remain errors.
309
- Explicit stored overrides and partial payloads keep their existing meaning.
310
-
311
- Generic arguments specify types, not default values. A required generic member
312
- must be supplied at construction unless its member declaration or an inherited
313
- member declaration supplies a default. Missing required members are compile
314
- errors. Pull preserves incomplete stored objects for repair; add the missing
315
- initializer or declare the intended member default before testing or pushing.
316
- An override without a local initializer inherits an available base member
317
- default, including when its stored `defaultValue` carrier is null. An explicit
318
- `= null` initializer is a literal nullable default, not an inheritance marker.
319
-
320
- Editing an initializer updates sparse override rows in place: projected member
321
- IDs remain stable, and omitted virtual rows are never emitted as authored seed
322
- records. Spelling a declared default verbatim in a new initializer lowers to
323
- the same absence as omitting the member — a leaf equal to its declaration, or
324
- a bare class construction whose members the declaration wholly settles, mints
325
- no override row and resumes source tracking. A stored row already spelling its
326
- default converges to the sparse form on its next authored touch. A stored
327
- construction predating the P75 collapse converges the same way: its next push
328
- drops the constructor-settled keys the body duplicated from the creation data
329
- and stamps the construction's provenance. That is a one-time storage
330
- convergence, not an edit — resolved values do not change, and the argument
331
- rows stay reachable through the creation data that already named them.
332
-
333
- Defaulted members may be added without recreating existing instances, including
334
- instances whose sparse arguments are retained only as constructor data.
335
- Source is authoritative for a construction: editing its constructor arguments,
336
- including a static's, rebuilds the instance in place on push. The value keeps
337
- its ID, rows at unchanged positions keep theirs, added entries create rows,
338
- removed entries delete them, and the stored creation data records the new
339
- arguments. Overrides the rebuilt construction no longer produces are deleted,
340
- so keep them in the construction's `{ ... }` block. A construction whose class
341
- changed fails with `construction-arguments-conflict`; delete and recreate the
342
- value to change its class.
343
-
344
- Write main-locale text directly in localizable string initializers. Pull/lower
345
- retargets only the edited assignment. Equal primary-locale text on the same
346
- declared member shares a localization record across member overrides and
347
- instances. Different members keep separate translation contexts. Editing a
348
- class default updates its inheriting instances; editing one instance does not
349
- change that default. Reverting the instance text to its default restores the
350
- shared assignment and archives an unreferenced unique text record.
351
-
352
- An empty string stores no localization ID. Entering nonempty primary-locale
353
- text selects or creates the member's shared localization record. Do not author
354
- localized-text IDs in place of prose. Nullability, not text length, controls
355
- whether the member is required. Other locales remain translations of their
356
- linked source record.
357
-
358
- ## Managed files
359
-
360
- Managed images support PNG, JPEG, GIF, and SVG. SVG files use `image/svg+xml`
361
- and retain their original bytes through pull, push, and Unity export; the CLI
362
- does not rasterize them. The same byte-length, MIME-type, and SHA-256 checks
363
- apply to SVG transfers as to other managed files.
364
-
365
- Declare files in typed registries:
366
-
367
- ```neo
368
- ImageRegistry Images = new() {
369
- @id("sword-image-file-id")
370
- @settings(template: PixelArt)
371
- NeoImage Sword = new("Files/Images/Sword.png");
372
- }
373
-
374
- AudioClipRegistry AudioClips = new() {
375
- @id("sword-hit-audio-file-id")
376
- @settings(template: SoundEffect)
377
- NeoAudioClip SwordHit = new("Files/AudioClips/SwordHit.wav");
378
- }
379
- ```
380
-
381
- Reference a sprite with `Images.Sword.Slice(0)` and an audio clip with
382
- `AudioClips.SwordHit`. A bare `Images.Sword` represents the file ID only in a
383
- file-valued context such as `SpriteInfo.FileId`; it is not a complete sprite.
384
-
385
- Dropping a supported binary under `Files/Images/` or `Files/AudioClips/`
386
- creates a pending file with a provisional deterministic symbol. Status,
387
- diff, and dry-run do not rewrite its registry. A successful push creates the
388
- record, uploads verified bytes, and materializes its declaration and ID.
389
-
390
- Registry symbols derive deterministically from the persisted file name. For
391
- example, `tree.cherryblossom.png` becomes `TreeCherryblossom`. Keep an authored
392
- declaration aligned with that spelling, or set an explicit persisted name such
393
- as `@settings(name: "TreeCherryBlossom.png")` when the binary path should stay
394
- different. The name must end with the binary's extension, because pull
395
- rebuilds the file's path from it. With no template annotation, the CLI persists the complete built-in
396
- Unity defaults for the file kind.
397
-
398
- Template-backed Unity settings may contain sparse nested override values and leaf
399
- paths such as `platformSettings.standalone.maxTextureSize` or
400
- `spriteSettings.pivot.x`. Preserve these paths during synchronization so untouched
401
- settings continue inheriting from the template.
402
-
403
- A top-level `NeoImage` or `NeoAudioClip` declaration in any definition file
404
- can stand in for an inline entry. The registry lists it by name
405
- (`NeoAudioClip SwordHit = SWORD_HIT;`), and the declaration carries the `@id`,
406
- `@settings`, and path. Push, pull and reset keep it in its own file. Every such
407
- declaration must be listed exactly once.
408
-
409
- Pull/push compare server-verified SHA-256, not storage ETags. A divergent
410
- binary keeps local bytes and writes the verified remote side under
411
- `.neo/conflicts/files/<file-id>/`. A retained declaration with a missing binary
412
- is an error; remove the declaration to request deletion.
413
-
414
- New schema getters referenced by NeoFlow interpolation need no `@id`. Export and
415
- `neo dev` assign the same identity to the declaration and its references, including
416
- inherited getters. Repeated exports and the next push reuse the export identity ledger.
417
-
418
- Dictionary string keys are data. An entry named `"Id"` reads its value through
419
- `dictionary["Id"]`; class `.Id` continues to return the class instance identity.
420
-
421
- You can remove a constructor and replace every call to it in the same edit. Push prepares the new calls together with the schema change and removes argument rows owned by the old constructions.