@neocompose/cli 0.87.1 → 0.88.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 (40) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +14 -0
  3. package/dist/neo-runtime.mjs +3789 -1141
  4. package/dist/test-worker.mjs +2450 -116
  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/initializers.md +100 -0
  12. package/skills/neocompose-cli/references/declarations/member-kinds.md +107 -0
  13. package/skills/neocompose-cli/references/declarations/overloads.md +50 -0
  14. package/skills/neocompose-cli/references/dialogues.md +145 -0
  15. package/skills/neocompose-cli/references/neoscript/collections.md +98 -0
  16. package/skills/neocompose-cli/references/neoscript/control-flow.md +123 -0
  17. package/skills/neocompose-cli/references/neoscript/delegates-and-listeners.md +107 -0
  18. package/skills/neocompose-cli/references/neoscript/math-and-random.md +114 -0
  19. package/skills/neocompose-cli/references/neoscript/neoscript.md +112 -0
  20. package/skills/neocompose-cli/references/neoscript/strings.md +47 -0
  21. package/skills/neocompose-cli/references/neoscript/testing-and-migrations.md +73 -0
  22. package/skills/neocompose-cli/references/neoscript/types-and-narrowing.md +111 -0
  23. package/skills/neocompose-cli/references/sync/branches-and-history.md +69 -0
  24. package/skills/neocompose-cli/references/sync/conflicts-and-recovery.md +68 -0
  25. package/skills/neocompose-cli/references/sync/sync.md +96 -0
  26. package/skills/neocompose-cli/references/sync/unity-export.md +47 -0
  27. package/skills/neocompose-cli/references/values/defaults-and-localization.md +86 -0
  28. package/skills/neocompose-cli/references/values/files.md +71 -0
  29. package/skills/neocompose-cli/references/values/identities.md +97 -0
  30. package/skills/neocompose-cli/references/values/references.md +151 -0
  31. package/skills/neocompose-cli/references/values/values.md +110 -0
  32. package/skills/neocompose-cli/references/world/animation.md +133 -0
  33. package/skills/neocompose-cli/references/world/grids-and-cell-patterns.md +55 -0
  34. package/skills/neocompose-cli/references/world/variants.md +112 -0
  35. package/skills/neocompose-cli/references/world/world.md +105 -0
  36. package/skills/neocompose-cli/references/animation-and-world-authoring.md +0 -582
  37. package/skills/neocompose-cli/references/commands-and-sync.md +0 -408
  38. package/skills/neocompose-cli/references/declarations-and-construction.md +0 -773
  39. package/skills/neocompose-cli/references/neoscript.md +0 -990
  40. package/skills/neocompose-cli/references/values-identities-and-references.md +0 -421
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.87.1",
3
+ "version": "0.88.0",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,74 +9,56 @@ 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.87.1 -->
12
+ <!-- reviewed-through-cli: 0.88.0 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
16
- Treat a format-4 `neo/` directory as a Git-like checkout of one Neo Compose
17
- project version. Tracked native source is the CLI authoring source of truth:
18
- edit it and use `neo push` for schema, values, dialogues, and managed files.
19
- The web UI remains a peer authoring surface over the shared server records.
16
+ A format-4 `neo/` directory is a Git-like checkout of one Neo Compose project
17
+ version. Tracked native source is the CLI's source of truth: edit it and
18
+ `neo push` schema, values, dialogues, and managed files. The web UI edits the
19
+ same server records.
20
20
 
21
- Do not look for a C# schema project, Roslyn compiler, authoring DLL, generated
21
+ Format 4 has no C# schema project, Roslyn compiler, authoring DLL, generated
22
22
  SDK, `ValueRegistry`, per-member script sidecars, or checked-in dialogue JSON.
23
- Those are not part of format 4.
24
-
25
- ## Follow the safe workflow
26
-
27
- 1. Run `neo pull` before editing. Pull again before pushing if time has passed.
28
- 2. Edit tracked `.neo`, `.neoflow`, `.spec.neo`, and managed binary files only. Never edit
29
- `.neo/state.json`, analysis caches, or `.neo/conflicts` as source.
30
- 3. Run `neo status` and `neo diff`. Review every change, including changes that
31
- existed before the task began. Newly authored value seeds are grouped under
32
- the `.neo` source that owns them and are included in JSON output even when
33
- they are the only pending work.
34
- 4. Run `neo test` after NeoScript changes and `neo dialogue dryrun <ref>` after
35
- dialogue changes.
36
- `neo test` compiles the complete pending candidate, including idless nested
37
- construction rows, so tests must work before the first push; do not add IDs
38
- or push merely to obtain compiled initializer bodies.
39
- 5. Run `neo push --dry-run` before every real push. It performs the full local
40
- source emission, ID-assignment, transport-shape, hash, and repeat-verification path,
41
- then runs the preparation a real push ships — compilation, schema-commit
42
- materialization, and whole-graph validation — against the pulled document,
43
- without prompting, uploading, committing, or rewriting the checkout. Pull
44
- once with the installed CLI so the workspace carries compatible
45
- derived-edge extractor metadata. Pending getters and functions compile before
46
- local initializer evaluation, including on a project's first push. Initializers
47
- resolve pending value dependencies before their consumers; cyclic dependencies
48
- report the participating values.
49
- 6. Push one reviewed atomic change with `neo push`.
50
- Completion arrives through a live subscription. Progress counts refresh every
51
- five seconds while the durable job runs; a disconnect does not cancel it.
52
-
53
- Treat pull followed immediately by status or dry-run as a semantic no-op. If it
54
- reports project changes, stop and report a round-trip bug instead of pushing.
55
-
56
- The compiler reports file:line:column diagnostics and fails closed. Unknown
57
- authorable server fields require a CLI contract update; never preserve them as
58
- opaque JSON or guessed syntax.
59
-
60
- ## Honor hard authoring invariants
61
-
62
- - Never add `@system` to project-authored declarations, members, overrides,
63
- values, files, or other records. `@system` is reserved for platform-owned
64
- system records; authoring it can make the record uneditable.
65
- - Preserve existing `@id` annotations through rename, reorder, and file moves.
66
- A copy must get a new ID. A stored nested class value may keep its UUID-v4
67
- when moved between compatible empty fields on existing parents, provided
68
- its old parent no longer declares it. See the identity reference for limits.
69
- - Omit `@id` on new ordinary declarations and nested rows unless a same-push
70
- structural reference genuinely requires an explicit UUID. A successful push
71
- assigns the durable IDs and inserts them into the authored source. Files that
72
- get no new IDs keep their bytes.
73
- - Do not add a second `@id` to a root or static member initializer. The member
74
- ID owns that stored binding. Existing nested class/list rows retain their
75
- inline IDs; new rows normally omit them until push.
76
- - Treat `.neo/` as private state and tracked Neo source as the authorable input.
77
- - Never seek a force-CAS bypass. Pull, resolve, review, and retry.
78
-
79
- ## Set up a format-4 workspace
23
+ Don't look for them.
24
+
25
+ ## Workflow
26
+
27
+ 1. `neo pull` before editing, and again before pushing if time has passed.
28
+ 2. Edit only tracked `.neo`, `.neoflow`, `.spec.neo`, and managed binaries.
29
+ Never edit `.neo/state.json`, analysis caches, or `.neo/conflicts`.
30
+ 3. `neo status` and `neo diff`. Review every change, including ones that
31
+ predate your task.
32
+ 4. `neo test` after NeoScript changes; `neo dialogue dryrun <ref>` after
33
+ dialogue changes. Both work before the first push, so never add IDs or
34
+ push just to test.
35
+ 5. `neo push --dry-run`, the full local commit rehearsal.
36
+ 6. `neo push` one reviewed, atomic change. On `non-fast-forward`, pull and
37
+ push again.
38
+
39
+ Pull followed immediately by status or dry-run must be a no-op. If it reports
40
+ changes, stop and report a round-trip bug instead of pushing.
41
+
42
+ Diagnostics are file:line:column and the compiler fails closed. An unknown
43
+ authorable server field needs a CLI contract update; never keep it as opaque
44
+ JSON or guessed syntax.
45
+
46
+ ## Invariants
47
+
48
+ - Never author `@system`. It marks platform-owned records and can make a
49
+ record uneditable.
50
+ - Keep existing `@id`s through renames, reorders, and file moves. Copies get
51
+ new IDs.
52
+ - Omit `@id` on new declarations and rows unless a same-push structural
53
+ reference needs an explicit UUID-v4. Push assigns IDs and writes them into
54
+ source; files without new IDs keep their bytes.
55
+ - A root or static member's ID owns its stored binding. Never add a second
56
+ `@id` to its initializer.
57
+ - Class, List, Set, and Dictionary values have one owner. Use `Clone()` for a
58
+ copy or `Reference(...)` to share.
59
+ - Never seek a force-CAS bypass. Pull, resolve, review, retry.
60
+
61
+ ## Setup
80
62
 
81
63
  ```sh
82
64
  npm i -g @neocompose/cli
@@ -85,240 +67,74 @@ neo init --project <id> [--version <id>] [--dir neo]
85
67
  neo doctor
86
68
  ```
87
69
 
88
- Use `node cli/bin/neo.mjs` while developing the repository. Pass explicit flags
89
- and IDs in automation. Non-TTY/CI commands never wait for pickers or confirms.
90
-
91
- `neo init` requires a new or empty destination, apart from `.git` and
92
- `.gitignore`. It refuses other existing entries before writing anything; choose
93
- a separate directory when recovering a checkout whose config is missing.
94
-
95
- Require `formatVersion: 4` in `neo.json`. There is no format-3 reader or
96
- upgrader. Reconstruct an authoritative format-4 checkout with `neo init`.
97
-
98
- For an existing checkout:
99
-
100
- - `neo pull --reset` regenerates canonical source and managed binaries.
101
- - `neo pull --force` discards local edits in favor of the server.
102
- - `neo pull --regenerate-source-names` replaces generated default dialogue
103
- names with readable ones, keeps chosen names, and rewrites references.
104
-
105
- Use reset and force only when their destructive effect is intended.
106
-
107
- In Unity projects, `neo.json` may use `unityConfigPath` instead of
108
- `projectId`/`versionId`. The referenced `NeoComposeConfig.asset` then owns those
109
- IDs and is updated by branch/version switches; do not duplicate them.
110
-
111
- ## Recognize the workspace
70
+ Use `node cli/bin/neo.mjs` inside the neo-compose repository. Pass explicit
71
+ flags and IDs in automation; non-TTY runs never prompt. `neo init` needs an
72
+ empty destination apart from `.git` and `.gitignore`, so recover a checkout
73
+ with missing config in a separate directory. `neo.json` must have
74
+ `formatVersion: 4`. In Unity projects it may use `unityConfigPath` instead of
75
+ `projectId`/`versionId`; the referenced `NeoComposeConfig.asset` then owns the
76
+ IDs, so don't duplicate them.
112
77
 
113
78
  ```text
114
79
  neo/
115
- neo.json
116
- Project.neo
117
- Root.neo
118
- Classes/{System/, ...}
119
- Interfaces/{System/, ...}
120
- Enums/{System/, ...}
121
- Relations.neo
122
- Templates/
123
- Localization.neo
124
- LocalizationStatuses/
80
+ neo.json Project.neo Root.neo Relations.neo Localization.neo
81
+ Classes/ Interfaces/ Enums/ (system declarations under System/)
82
+ Templates/ LocalizationStatuses/ DialogueGroups/
125
83
  Files/{Images.neo,AudioClips.neo,Images/,AudioClips/}
126
- DialogueGroups/
127
84
  Variants/{<Class>.neo,<Class>/<Folder path>.neo}
128
85
  Dialogues/*.neoflow
129
86
  Migrations/*.neo
130
- **/*.spec.neo
131
- .neo/{state.json,conflicts/}
87
+ **/*.spec.neo (tests; never synced)
88
+ .neo/{state.json,conflicts/} (private state)
132
89
  ```
133
90
 
134
- Production `.neo`/`.neoflow` files and supported managed binaries are tracked.
135
- Colocated `.spec.neo` files are test-only and never enter status, source hashes,
136
- pull/reset, or push.
137
- Normal pull preserves declaration placement and spelling by stable ID when it
138
- can. Force/reset regenerates canonical text while retaining the current declaration
139
- paths and extracted initializer bindings, including moves made since the last
140
- sync. New server declarations use the default layout. System declarations
141
- default to a `System` subfolder under their category, including classes, enums,
142
- interfaces, templates, localization statuses, and priority/dialogue groups.
143
- Ownership comes from the reserved system identity, not the declaration name.
144
-
145
- ## Load the focused contract you need
146
-
147
- Read only the references relevant to the task, but read each selected reference
148
- completely before editing:
91
+ Declarations may live in any `.neo` file; pull keeps their placement by ID.
149
92
 
150
- - [Declarations and construction](references/declarations-and-construction.md):
151
- classes, interfaces, enums, annotations, storage, required/header
152
- constructors, declared constructors, settlement, and inheritance.
153
- - [Values, identities, and references](references/values-identities-and-references.md):
154
- root/static bindings, nested/list identities, same-push references, unique
155
- keys, files, localization, and virtual default projection.
156
- - [Animation and world authoring](references/animation-and-world-authoring.md):
157
- objects, sorting, optional children, structured leaves, object variants and
158
- variant folders, partial animation overrides, segments, tracks, and NeoFlow
159
- dialogues.
160
- - [NeoScript](references/neoscript.md): inline bodies, snippets, nullability,
161
- numeric and list builtins, loops, switch, try/catch, ownership, evaluation,
162
- and migrations.
163
- - [Commands and synchronization](references/commands-and-sync.md): pull/push,
164
- conflicts, low-level repair, branches, releases, and history.
165
- - [CLI development](references/cli-development.md): implementation source of
166
- truth, shipped/proposed spec status, package boundaries, release maintenance,
167
- and repository verification.
93
+ ## Source shape
168
94
 
169
- ## Use native typed source
170
-
171
- Declare top-level project objects with typed declarations:
95
+ Top-level project objects are typed declarations:
172
96
 
173
97
  ```neo
174
98
  Type Name = expression;
175
99
  Type Name = new(arguments) {
176
- // Typed owned declarations supported by Type.
177
- }
178
- ```
179
-
180
- Do not invent lowercase persistence-kind declarations such as `project`,
181
- `values`, `files`, or `relations`. Named arguments and contextual enum literals
182
- come from generated contracts; do not invent raw fields or property bags.
183
-
184
- Persisted reusable values are static members on ordinary project classes:
185
-
186
- ```neo
187
- @id("assets-class-id")
188
- @storage(allowed: .Immutable)
189
- class Assets {
190
- @id("capitol-member-id")
191
- static Outpost Capitol = new {
192
- Name = "Capitol",
193
- Image = Images.Capitol.Slice(0),
194
- };
195
- }
196
- ```
197
-
198
- The member ID anchors the stored binding. A computed static getter is an alias
199
- and creates no stored binding or value row.
200
-
201
- Local project initializers may live in any `.neo` file and need no imports:
202
-
203
- ```neo
204
- List<NeoSortingLayer> SORTING_LAYERS = [
205
- @id("existing-layer-id")
206
- new NeoSortingLayer() { Name = "Default" }
207
- ];
208
- ```
209
-
210
- Use `SortingLayers = SORTING_LAYERS` in Root or another stored initializer.
211
- The consuming member owns the value identity; do not add an ID at the use.
212
- Preserve existing nested IDs when extracting, and omit IDs on new rows.
213
- An aggregate has one owning assignment. Use `Reference(SORTING_LAYERS)` only
214
- where the receiving member permits that reference type. For independent
215
- copies, use the editor's duplicate action or copy the initializer without IDs.
216
- Scalars may have several owners. If those values diverge in web, pull keeps
217
- the different server values by inlining the differing uses. Initializer
218
- aliases are local source organization, not runtime globals or server records.
219
- Complete member and collection entries compose owned values, including inside
220
- constructor-backed initializers. A class local used as a constructor argument or
221
- executable operand refers to its single stored instance. Nested targets need an
222
- existing `@id` or an authored UUID-v4; a direct static owner supports pending IDs.
223
- Scalar executable expressions such as `BASE + 1` still require inlining the
224
- scalar expression. Locals are unavailable inside executable closures.
225
- The shared editor offers extract-to-file on a selected complete initializer,
226
- inline on its sole use, and duplicate at a use. Move the created file freely.
227
-
228
- Declare managed files in typed registries:
229
-
230
- ```neo
231
- ImageRegistry Images = new() {
232
- @id("sword-image-file-id")
233
- @settings(template: PixelArt)
234
- NeoImage Sword = new("Files/Images/Sword.png");
235
- }
236
-
237
- AudioClipRegistry AudioClips = new() {
238
- @id("sword-hit-audio-file-id")
239
- @settings(template: SoundEffect)
240
- NeoAudioClip SwordHit = new("Files/AudioClips/SwordHit.wav");
100
+ // typed owned declarations supported by Type
241
101
  }
242
102
  ```
243
103
 
244
- Use `Images.Sword.Slice(0)` for a sprite and `AudioClips.SwordHit` for audio.
245
- Registry declarations and their image/audio paths may be in any project folder
246
- outside ignored/private directories. Update the registry path when moving a
247
- binary file. Renaming the registry symbol or replacing bytes retains the file
248
- ID when the declaration keeps its `@id`; keep the symbol aligned with the
249
- persisted file name, or set `@settings(name: ...)` explicitly. The name must
250
- end with the binary's extension, as in `@settings(name: "ClinkingCoin1.mp3")`,
251
- because pull rebuilds the file's path from it.
252
-
253
- A declaration can also live in its own file, with the registry listing it by
254
- name the way a member lists a local value. Its `@id` and `@settings` stay on
255
- the declaration:
256
-
257
- ```neo
258
- // Values/Audio/SWORD_HIT.neo
259
- @id("sword-hit-audio-file-id")
260
- @settings(template: SoundEffect)
261
- NeoAudioClip SWORD_HIT = new("Files/AudioClips/SwordHit.wav");
262
-
263
- // Files/AudioClips.neo
264
- AudioClipRegistry AudioClips = new() {
265
- NeoAudioClip SwordHit = SWORD_HIT;
266
- }
267
- ```
268
-
269
- Pull preserves unchanged registry entries, comments, and authored order. New remote
270
- entries append to the registry; deleted entries are removed in place. Generated
271
- entries include `@settings(name: ...)` when the persisted name differs from the
272
- binary basename.
273
- Omitting `@settings(template: ...)` uses the complete built-in Unity import
274
- defaults for that file kind.
275
-
276
- ## Resolve conflicts by identity
277
-
278
- Pull performs a record-aware three-way merge. Disjoint fields and children
279
- merge; collection and graph children merge by ID, never by index. Conflicting
280
- scalars, edges, order, delete/edit pairs, and binaries become explicit.
281
-
282
- Conflict source deliberately fails compilation. Edit the desired final source,
283
- or use `neo resolve --mine|--theirs` as a whole-side convenience. Then pull,
284
- review, dry-run, and push again.
285
-
286
- Either `neo resolve` side adopts the server side as the new base for every
287
- conflict it settles, so the next push plans against what the server holds:
288
- `--theirs` reads clean afterwards, `--mine` reads as an ordinary local update.
289
- Server-derived compilation metadata is not authored source and does not create
290
- a pull conflict by itself; if an older CLI retained such a metadata-only
291
- conflict without writing source markers, either side settles it the same way
292
- while preserving any real local source edit.
293
-
294
- `neo push` prepares the commit locally, recompiling changed NeoScript bodies
295
- and schema-affected callers, and the server commits the prepared changes under
296
- CAS. If another commit lands after your pull, the push fails as
297
- `non-fast-forward`: pull, then push again. Use
298
- `neo push --dry-run` for the complete source-to-record round-trip check; a
299
- normal push deliberately does not upload or re-lower the whole source tree. On
300
- `base-hash-conflict`, pull and resolve. On `version-bump-required`, inspect the
301
- classification and pass `neo push --accept-bump` only when intended.
302
- If a push committed but its local rewrite failed, run `neo pull` to resume the
303
- saved result. Keep `.neo/state.json`; status and push require that recovery first.
104
+ Never invent lowercase persistence kinds such as `project`, `values`,
105
+ `files`, or `relations`, raw fields, or property bags. Named arguments and
106
+ contextual enum literals come from generated contracts.
107
+
108
+ Formatting comes from `.editorconfig` (`indent_style`, `indent_size`,
109
+ `end_of_line`, `insert_final_newline`; defaults two spaces, LF, final
110
+ newline), shared by the CLI and VS Code. Formatting-only edits never create a
111
+ push.
112
+
113
+ ## References
114
+
115
+ Open the domain page for the task, then only the leaf it points to:
116
+
117
+ - [NeoScript](references/neoscript/neoscript.md): bodies, names, nullability,
118
+ writes. Leaves: math and random, strings, collections, control flow, types
119
+ and narrowing, delegates and listeners, testing and migrations.
120
+ - [Declarations](references/declarations/declarations.md): classes,
121
+ interfaces, enums, modifiers, members. Leaves: annotations and storage,
122
+ constructors, initializers, member kinds, overloads.
123
+ - [Values](references/values/values.md): Root and static bindings, locals,
124
+ ownership. Leaves: identities, `Reference<T>`, defaults and localization,
125
+ managed files.
126
+ - [World objects](references/world/world.md): tiles, objects, sorting,
127
+ structured leaves. Leaves: grids and cell patterns, variants, animation.
128
+ - [Dialogues](references/dialogues.md): NeoFlow files, groups, labels,
129
+ triggering from NeoScript.
130
+ - [Sync commands](references/sync/sync.md): pull, status, dry-run, push.
131
+ Leaves: conflicts and recovery, branches and access, Unity export.
132
+ - [CLI development](references/cli-development.md): only when changing the
133
+ CLI, language service, package, or this skill.
304
134
 
305
135
  ## Finish with evidence
306
136
 
307
- Before a real push, report the files changed, the relevant `neo diff`, dialogue
308
- dry-run results when applicable, and `neo push --dry-run`. Do not claim success
309
- from parsing alone when construction, reference membership, runtime ownership,
310
- or server verification is involved.
311
-
312
- ## Formatting
313
-
314
- The CLI and VS Code extension share NeoScript formatting and read `.editorconfig`
315
- for `.neo` and `.neoflow` files. Set `indent_style`, `indent_size`, `end_of_line`,
316
- and `insert_final_newline` there to keep regenerated source consistent with your
317
- editor. Defaults are two spaces, LF, and a final newline. A NeoFlow prose
318
- block's content and closing `"""` lines follow its opening `"""`, so re-indenting
319
- never changes the text. Push preserves authored
320
- text when regeneration has the same tokens; pull preserves semantically unchanged
321
- files. Formatting-only body or source-location changes do not create a subsequent
322
- push, including stored initializer recipes, computed member defaults, and inline
323
- constructor delegates; real code and string-content edits still do. Formatting preferences belong
324
- to the checkout, not stored script bodies.
137
+ Before a real push, report the changed files, the relevant `neo diff`,
138
+ dialogue dry-run results when applicable, and `neo push --dry-run`. Parsing
139
+ alone doesn't prove construction, reference membership, runtime ownership, or
140
+ server verification.