@neocompose/cli 0.24.0 → 0.24.2

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.24.0",
3
+ "version": "0.24.2",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,6 +40,12 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "esbuild": "^0.28.1",
43
- "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"
44
50
  }
45
51
  }
@@ -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.24.0 -->
12
+ <!-- reviewed-through-cli: 0.24.2 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -50,8 +50,12 @@ opaque JSON or guessed syntax.
50
50
  values, files, or other records. `@system` is reserved for platform-owned
51
51
  system records; authoring it can make the record uneditable.
52
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.
53
56
  - Do not add a second `@id` to a root or static member initializer. The member
54
- 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.
55
59
  - Treat `.neo/` as private state and tracked Neo source as the authorable input.
56
60
  - Never seek a force-CAS bypass. Pull, resolve, review, and retry.
57
61
 
@@ -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,59 @@ 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
+
181
+ A selector argument such as `this.SelectPants` is evaluated in the lexical
182
+ scope of the class that declares the clip. Here `this` is the `LegPart`, not
183
+ the nested track row or an outer object instance that later receives a copy of
184
+ the declaration default.
185
+
158
186
  Each track has `StartFrame`, `Direction` (`.Forward` or `.Reverse`), and a
159
187
  crop window `OffsetStartIndex`/`OffsetEndIndex`. Crop before reversing, then
160
188
  schedule on the owning clip. Content beyond the owning clip truncates. Reject
161
189
  empty/inverted crop windows and tracks that can never enter the clip.
162
190
 
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.
191
+ Treat track target selection as project-authored identity logic, not row data.
192
+ The selector return type must be compatible with `TChild`; the segment value
193
+ must be compatible with `TValue`. `Refresh` controls selector reevaluation,
194
+ while track reads and segment getters are re-resolved for the next applied
195
+ frame after a watched dependency changes.
166
196
 
167
197
  When multiple tracks write the same member in one frame, apply list order and
168
198
  let the last write win.
@@ -41,10 +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)
44
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)
45
47
 
46
- P38–P44, P47–P52, and the initial P64 test/push-hook vertical slice are
47
- 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
48
50
  build or teach runtime-child provenance. P46 is a hardening proposal, not an
49
51
  authoring capability. P52's document header still says proposed, but try/catch
50
52
  shipped in CLI 0.18; implementation and parity tests take precedence over that
@@ -80,7 +82,7 @@ wrappers.
80
82
  The marker near the top of `SKILL.md` must exactly match the package version:
81
83
 
82
84
  ```html
83
- <!-- reviewed-through-cli: 0.24.0 -->
85
+ <!-- reviewed-through-cli: 0.24.2 -->
84
86
  ```
85
87
 
86
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