@neocompose/cli 0.23.2 → 0.24.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.23.2",
3
+ "version": "0.24.1",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,10 +35,17 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@inquirer/prompts": "^8.5.2",
38
- "convex": "^1.40.0"
38
+ "convex": "^1.40.0",
39
+ "ignore": "^7.0.6"
39
40
  },
40
41
  "devDependencies": {
41
42
  "esbuild": "^0.28.1",
42
- "prettier": "^3.9.5"
43
+ "prettier": "^3.9.5",
44
+ "uuid": "^14.0.1"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/ryanbliss/neo-compose.git",
49
+ "directory": "cli"
43
50
  }
44
51
  }
@@ -2,14 +2,14 @@
2
2
  name: neocompose-cli
3
3
  description: >-
4
4
  Edit, validate, and synchronize Neo Compose format-4 projects with the `neo`
5
- CLI. Use when working in a `neo/` checkout or with `.neo`/`.neoflow` source:
5
+ CLI. Use when working in a `neo/` checkout or with `.neo`/`.neoflow`/`.spec.neo` source:
6
6
  schema declarations, constructors, values and references, world objects and
7
7
  animation, dialogue, NeoScript, localization, migrations, managed image or
8
8
  audio files, branches and releases, or batch repair. Run `neo` from
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.23.2 -->
12
+ <!-- reviewed-through-cli: 0.24.1 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -24,11 +24,12 @@ Those are not part of format 4.
24
24
  ## Follow the safe workflow
25
25
 
26
26
  1. Run `neo pull` before editing. Pull again before pushing if time has passed.
27
- 2. Edit tracked `.neo`, `.neoflow`, and managed binary files only. Never edit
27
+ 2. Edit tracked `.neo`, `.neoflow`, `.spec.neo`, and managed binary files only. Never edit
28
28
  `.neo/state.json`, analysis caches, or `.neo/conflicts` as source.
29
29
  3. Run `neo status` and `neo diff`. Review every change, including changes that
30
30
  existed before the task began.
31
- 4. Run `neo dialogue dryrun <ref>` after dialogue changes.
31
+ 4. Run `neo test` after NeoScript changes and `neo dialogue dryrun <ref>` after
32
+ dialogue changes.
32
33
  5. Run `neo push --dry-run` before every real push. It performs the full local
33
34
  source emission, ID-assignment, transport-shape, hash, and repeat-verification path,
34
35
  then rehearses the server's preparation phase — schema-commit
@@ -49,8 +50,12 @@ opaque JSON or guessed syntax.
49
50
  values, files, or other records. `@system` is reserved for platform-owned
50
51
  system records; authoring it can make the record uneditable.
51
52
  - Preserve existing `@id` annotations through rename, reorder, and file moves.
53
+ - Omit `@id` on new ordinary declarations and nested rows unless a same-push
54
+ structural reference genuinely requires an explicit UUID. A successful push
55
+ assigns the durable IDs and rewrites source.
52
56
  - Do not add a second `@id` to a root or static member initializer. The member
53
- ID owns that stored binding. Nested class/list rows still carry their own IDs.
57
+ ID owns that stored binding. Existing nested class/list rows retain their
58
+ inline IDs; new rows normally omit them until push.
54
59
  - Treat `.neo/` as private state and tracked Neo source as the authorable input.
55
60
  - Never seek a force-CAS bypass. Pull, resolve, review, and retry.
56
61
 
@@ -100,10 +105,13 @@ neo/
100
105
  DialogueGroups/
101
106
  Dialogues/*.neoflow
102
107
  Migrations/*.neo
108
+ **/*.spec.neo
103
109
  .neo/{state.json,conflicts/}
104
110
  ```
105
111
 
106
- All non-hidden `.neo`, `.neoflow`, and supported managed binaries are tracked.
112
+ Production `.neo`/`.neoflow` files and supported managed binaries are tracked.
113
+ Colocated `.spec.neo` files are test-only and never enter status, source hashes,
114
+ pull/reset, or push.
107
115
  Normal pull preserves declaration placement and spelling by stable ID when it
108
116
  can. Force/reset may regroup source into the canonical layout.
109
117
 
@@ -109,9 +109,12 @@ 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 with stable row IDs. Missing optional child slots are
113
- skipped with diagnostics when the authored slot is absent, while stale
114
- pre-provenance placements may still fail closed.
112
+ Address direct children through selector delegates. A selector should implement
113
+ the project's own stable identity contract, such as an immutable `Name`, slug,
114
+ or semantic position; do not turn a mutable object-row ID back into identity by
115
+ returning `Reference<T>(id: "...")`. Missing optional child slots are skipped
116
+ with diagnostics when the authored slot is absent, while stale pre-provenance
117
+ placements may still fail closed.
115
118
 
116
119
  A placement row carries its `assetClassId` binding and optional `assetValueId`
117
120
  override beside its schema keys. They are row provenance, not declared schema:
@@ -127,8 +130,8 @@ sprite specialization is `NeoSpriteAnimationSegment`, whose
127
130
 
128
131
  Use one polymorphic `NeoAnimationClip.Tracks` list:
129
132
 
130
- - `NeoAnimationChildTrack` schedules a child clip selected by `Child` and
131
- `ClipKey`.
133
+ - `NeoAnimationChildTrack` schedules `ClipKey` on the child returned by its
134
+ `Selector` delegate.
132
135
  - A project subclass of
133
136
  `NeoAnimationSegmentTrack<TChild, TValue>` schedules a segment onto one
134
137
  target member. Implement its abstract `Segment` member as a stored value,
@@ -137,32 +140,54 @@ Use one polymorphic `NeoAnimationClip.Tracks` list:
137
140
  `NeoSpriteAnimationSegmentTrack<TChild extends NeoSpriteObject>` pairing
138
141
  targets `NeoSpriteObject.Sprite`.
139
142
 
140
- Declare a concrete project track by implementing `Segment`, then construct its
141
- row with the target child ID:
143
+ Declare a concrete project track by implementing `Segment`, expose a compatible
144
+ selector function on the owning object, then pass that function to each row:
142
145
 
143
146
  ```neo
144
147
  class StoredPantsTrack : NeoSpriteAnimationSegmentTrack<PantsSprite> {
145
148
  public override NeoSpriteAnimationSegment Segment = new();
146
149
  }
147
150
 
148
- Tracks = [
149
- @id("pants-track-row-id")
150
- new StoredPantsTrack(id: "pants-child-row-id") {
151
- StartFrame = 0,
152
- Direction = .Reverse,
153
- OffsetEndIndex = 3,
154
- },
155
- ];
151
+ class LegPart : NeoObject {
152
+ public PantsSprite SelectPants() {
153
+ var child = this.Children.FirstOrDefault((candidate) => {
154
+ return candidate.Name == "Pants";
155
+ });
156
+ if (child is PantsSprite pants) {
157
+ return pants;
158
+ }
159
+ throw "Pants child is missing or has the wrong type";
160
+ }
161
+
162
+ public NeoAnimationClip<LegPart> Walk = new NeoAnimationClip<LegPart> {
163
+ Tracks = [
164
+ new StoredPantsTrack(selector: this.SelectPants) {
165
+ StartFrame = 0,
166
+ Direction = .Reverse,
167
+ OffsetEndIndex = 3,
168
+ },
169
+ ]
170
+ };
171
+ }
156
172
  ```
157
173
 
174
+ Selectors may also be compatible inline closures. Prefer a named function when
175
+ the identity rule is reused or deserves an explicit failure message. Never use
176
+ a selector merely to wrap `Reference<T>(id: "...")`; that recreates the
177
+ row-ID coupling selectors were introduced to remove. For new track rows, omit
178
+ `@id` and let the successful push assign it. Preserve IDs already present on
179
+ pulled rows.
180
+
158
181
  Each track has `StartFrame`, `Direction` (`.Forward` or `.Reverse`), and a
159
182
  crop window `OffsetStartIndex`/`OffsetEndIndex`. Crop before reversing, then
160
183
  schedule on the owning clip. Content beyond the owning clip truncates. Reject
161
184
  empty/inverted crop windows and tracks that can never enter the clip.
162
185
 
163
- Treat track target selection as class metadata, not row data. A target must be
164
- compatible with `TChild` and `TValue`. Track reads and segment getters are
165
- re-resolved for the next applied frame after a watched dependency changes.
186
+ Treat track target selection as project-authored identity logic, not row data.
187
+ The selector return type must be compatible with `TChild`; the segment value
188
+ must be compatible with `TValue`. `Refresh` controls selector reevaluation,
189
+ while track reads and segment getters are re-resolved for the next applied
190
+ frame after a watched dependency changes.
166
191
 
167
192
  When multiple tracks write the same member in one frame, apply list order and
168
193
  let the last write win.
@@ -41,8 +41,12 @@ Read the relevant specs in full:
41
41
  - [P50 loops](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p50-neoscript-for-and-foreach-loops.md)
42
42
  - [P51 switch](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p51-neoscript-switch-statements.md)
43
43
  - [P52 try/catch](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p52-neoscript-try-catch-blocks.md)
44
+ - [P60 delegate parameters and selector targeting](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p60-closure-parameters-and-selector-targeting.md)
45
+ - [P61 initializer materialization](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p61-initializer-materialization.md)
46
+ - [P64 NeoScript unit testing and push hooks](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p64-neoscript-unit-testing-and-push-hooks.md)
44
47
 
45
- P38–P44 and P47–P51 are implemented. P45 remains deliberately deferred; do not
48
+ P38–P44, P47–P52, P60–P61, and the initial P64 test/push-hook vertical slice
49
+ are implemented. P45 remains deliberately deferred; do not
46
50
  build or teach runtime-child provenance. P46 is a hardening proposal, not an
47
51
  authoring capability. P52's document header still says proposed, but try/catch
48
52
  shipped in CLI 0.18; implementation and parity tests take precedence over that
@@ -78,7 +82,7 @@ wrappers.
78
82
  The marker near the top of `SKILL.md` must exactly match the package version:
79
83
 
80
84
  ```html
81
- <!-- reviewed-through-cli: 0.23.2 -->
85
+ <!-- reviewed-through-cli: 0.24.1 -->
82
86
  ```
83
87
 
84
88
  The quoted version above is checked too, so this instruction cannot go stale
@@ -98,8 +98,11 @@ Reference<Dialogue>(id: "capitol-dialogue-id")
98
98
  - Both forms are legal in a member's declaration default, not only inside a
99
99
  value graph. A key written there resolves after every pass has run, so it may
100
100
  name a row the same push creates.
101
- - Keep structural references, such as child-track targets, ID-based when their
102
- collection has no stable key/path surface.
101
+ - Keep genuine structural references ID-based when their collection has no
102
+ stable symbol, path, or key surface. Animation track and frame-override
103
+ targets are selectors, not structural references: encode a stable
104
+ project-owned identity such as `Name` or slug in the selector instead of
105
+ wrapping a row ID in `Reference<T>(id: "...")`.
103
106
 
104
107
  Declaration and file order do not affect resolution within one push. Cyclic
105
108
  identity references are legal because they resolve IDs rather than evaluate a