@neocompose/cli 0.19.3 → 0.19.5
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/CHANGELOG.md +136 -0
- package/README.md +17 -12
- package/dist/neo.mjs +10323 -190
- package/package.json +2 -1
- package/skills/neocompose-cli/SKILL.md +115 -524
- package/skills/neocompose-cli/agents/openai.yaml +4 -0
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +218 -0
- package/skills/neocompose-cli/references/cli-development.md +110 -0
- package/skills/neocompose-cli/references/commands-and-sync.md +130 -0
- package/skills/neocompose-cli/references/declarations-and-construction.md +217 -0
- package/skills/neocompose-cli/references/neoscript.md +150 -0
- package/skills/neocompose-cli/references/values-identities-and-references.md +158 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# NeoScript
|
|
2
|
+
|
|
3
|
+
Use this reference for inline code, snippets, nullability, control flow,
|
|
4
|
+
runtime ownership, evaluation, and migrations.
|
|
5
|
+
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
- Inline bodies and snippets
|
|
9
|
+
- Nullability and ownership
|
|
10
|
+
- Loops and transfer
|
|
11
|
+
- Switch
|
|
12
|
+
- Try/catch
|
|
13
|
+
- Evaluation and migrations
|
|
14
|
+
|
|
15
|
+
## Inline bodies and snippets
|
|
16
|
+
|
|
17
|
+
Keep computed getters, setters, functions, dialogue logic, group logic, and
|
|
18
|
+
constructors inline in their owning `.neo` or `.neoflow` declaration. Do not
|
|
19
|
+
create `Scripts/<Class>/<Member>.neo` sidecars.
|
|
20
|
+
|
|
21
|
+
Use the shared language service through focused commands:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
neo script check --all
|
|
25
|
+
neo script check --this Outpost --returns string 'return $"{this.Name}!";'
|
|
26
|
+
neo script check --mode setter --member ComputedName 'root.Session.Name = value;'
|
|
27
|
+
neo script check --mode nsfunction --member Outpost.RefreshUnlock 'return this.Level > 0;'
|
|
28
|
+
neo script compile --mode nsfunction --member Outpost.RefreshUnlock 'return this.Level > 0;'
|
|
29
|
+
neo script eval --returns string 'return root.Assets.Outposts[0].FullDisplayText;'
|
|
30
|
+
neo script eval --function Outpost.RefreshUnlock --this-value <id> --args '[3]'
|
|
31
|
+
neo script apply --mode action '...'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Prefer `--json` for automation.
|
|
35
|
+
|
|
36
|
+
## Nullability and ownership
|
|
37
|
+
|
|
38
|
+
Do not access a nullable receiver directly. First narrow it with a condition, or
|
|
39
|
+
use null propagation `?.`, coalescing `??`, or explicit force unwrap `!` when
|
|
40
|
+
failure is intended:
|
|
41
|
+
|
|
42
|
+
```neo
|
|
43
|
+
if (player.Target != null) {
|
|
44
|
+
return player.Target.Name;
|
|
45
|
+
}
|
|
46
|
+
return player.Target?.Name ?? "Unknown";
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Treat lookup-return values with the same nullable narrowing rules.
|
|
50
|
+
|
|
51
|
+
Let runtime ownership—not body kind—decide whether a write target is Immutable,
|
|
52
|
+
Save, Session, Setter, or otherwise writable. A constructor writes only its
|
|
53
|
+
`this` instance. A writable structured-leaf field still inherits the receiver's
|
|
54
|
+
effective storage restrictions.
|
|
55
|
+
|
|
56
|
+
## Loops and transfer
|
|
57
|
+
|
|
58
|
+
Use C#-shaped loops:
|
|
59
|
+
|
|
60
|
+
```neo
|
|
61
|
+
for (int i = 0; i < Items.Count; i++) {
|
|
62
|
+
if (Items[i].Disabled) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
Visit(Items[i]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
foreach (var item in root.Save.Items) {
|
|
69
|
+
item.Enabled = true;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A `foreach` receiver must be non-null. It snapshots membership/order once at
|
|
74
|
+
entry, so adding/removing collection rows does not alter the scheduled
|
|
75
|
+
iterations. Dictionary iteration binds values, not keys. The iterator binding
|
|
76
|
+
is read-only, although writes through a writable entry remain valid.
|
|
77
|
+
|
|
78
|
+
Use `break` for the nearest loop or switch and `continue` for the nearest
|
|
79
|
+
loop. A `continue` inside a switch nested in a loop continues the loop.
|
|
80
|
+
|
|
81
|
+
All nested loops and called NeoScript bodies share a 10,000-iteration budget.
|
|
82
|
+
Do not use or teach `while` or `do`; they are not supported.
|
|
83
|
+
|
|
84
|
+
## Switch
|
|
85
|
+
|
|
86
|
+
Use scalar, enum, or nullable selectors with compile-time constant labels:
|
|
87
|
+
|
|
88
|
+
```neo
|
|
89
|
+
switch (direction) {
|
|
90
|
+
case Direction.North:
|
|
91
|
+
Move(0, 1);
|
|
92
|
+
break;
|
|
93
|
+
case Direction.East:
|
|
94
|
+
case Direction.West:
|
|
95
|
+
Stop();
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
throw $"Unknown direction: {direction}";
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Permit `int`, `string`, `bool`, enum, and nullable forms. Stack labels when
|
|
103
|
+
they share one body. End every reachable non-empty section with `break`,
|
|
104
|
+
`return`, `throw`, or `continue` when a surrounding loop makes it valid.
|
|
105
|
+
Do not use implicit fallthrough, switch expressions, pattern cases, guards, or
|
|
106
|
+
`goto`.
|
|
107
|
+
|
|
108
|
+
## Try/catch
|
|
109
|
+
|
|
110
|
+
Catch the string-valued NeoScript runtime-error channel with ordered filters:
|
|
111
|
+
|
|
112
|
+
```neo
|
|
113
|
+
try {
|
|
114
|
+
return GetUnsafe();
|
|
115
|
+
}
|
|
116
|
+
catch (string message) when (message == "1") {
|
|
117
|
+
return "Site moved";
|
|
118
|
+
}
|
|
119
|
+
catch (string message) {
|
|
120
|
+
throw;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Require braces and at least one `catch (string name)`. The catch binding is
|
|
125
|
+
read-only and scoped to its filter/body. Put at most one unfiltered catch last.
|
|
126
|
+
A false or failing filter continues matching the original error. Bare
|
|
127
|
+
`throw;` is valid only inside a catch and rethrows the original message.
|
|
128
|
+
|
|
129
|
+
Do not use typed exception classes, parameterless catch, `finally`, `using`,
|
|
130
|
+
patterns, or host-exception recovery. Completed writes before an error are not
|
|
131
|
+
rolled back.
|
|
132
|
+
|
|
133
|
+
## Evaluation and migrations
|
|
134
|
+
|
|
135
|
+
`neo script eval` uses authored values and the same evaluator as the web app.
|
|
136
|
+
`neo script apply` previews ordered write intents unless its explicit command
|
|
137
|
+
contract offers a commit mode.
|
|
138
|
+
|
|
139
|
+
Keep migrations as tracked action files under `Migrations/`:
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
neo migrate new <name> --target <ClassName|project>
|
|
143
|
+
neo migrate list
|
|
144
|
+
neo migrate check
|
|
145
|
+
neo migrate run [--dry-run] [--skip-invalid]
|
|
146
|
+
neo migrate prune
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Run checks before migration execution. Review storage ownership and every write
|
|
150
|
+
intent; do not assume an action body is writable merely because it compiled.
|
|
@@ -0,0 +1,158 @@
|
|
|
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
|
+
@locked
|
|
23
|
+
@storage(allowed: .Immutable)
|
|
24
|
+
Assets Assets = new() {
|
|
25
|
+
Outposts = [Assets.Capitol],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Do not place another `@id` immediately before the root initializer. The member
|
|
31
|
+
ID owns the binding. Apply the same rule to static stored members:
|
|
32
|
+
|
|
33
|
+
```neo
|
|
34
|
+
@id("assets-class-id")
|
|
35
|
+
class Assets {
|
|
36
|
+
@id("capitol-member-id")
|
|
37
|
+
static Outpost Capitol = new {
|
|
38
|
+
Name = "Capitol",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
@id("home-getter-id")
|
|
42
|
+
static Outpost Home {
|
|
43
|
+
get { return Assets.Capitol; }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A computed static getter is an alias; it creates neither a binding nor a row.
|
|
49
|
+
|
|
50
|
+
## Identity rules
|
|
51
|
+
|
|
52
|
+
Preserve every existing ID through rename, reorder, and file moves. For a new
|
|
53
|
+
ordinary record, omit `@id` and let a successful real push assign and insert
|
|
54
|
+
it. Dry-run and failed pushes leave tracked source unchanged.
|
|
55
|
+
|
|
56
|
+
Nested class/list rows remain independently addressable and keep inline IDs:
|
|
57
|
+
|
|
58
|
+
```neo
|
|
59
|
+
Tags = [
|
|
60
|
+
@id("story-tag-item-id")
|
|
61
|
+
"story",
|
|
62
|
+
];
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Never match an existing ordered row by index or payload. A bare row is pending
|
|
66
|
+
create shorthand.
|
|
67
|
+
|
|
68
|
+
When a same-push structural reference has no symbolic, path, or unique-key
|
|
69
|
+
form, an author may assign a previously unseen UUID-v4 with `@id` to the new
|
|
70
|
+
row and reference it in the same edit. Reusing an existing ID means update, not
|
|
71
|
+
create. The server validates authored new IDs for UUID-v4 shape and uniqueness.
|
|
72
|
+
Prefer generated IDs unless the structural reference needs an ID immediately.
|
|
73
|
+
|
|
74
|
+
Do not invent IDs for structural rows whose identities derive from an owner
|
|
75
|
+
role. Do not add a separate root/static initializer ID.
|
|
76
|
+
|
|
77
|
+
## Same-push references
|
|
78
|
+
|
|
79
|
+
Use the `Reference` intrinsic. Prefer the most readable form the target
|
|
80
|
+
supports:
|
|
81
|
+
|
|
82
|
+
```neo
|
|
83
|
+
Reference(Assets.Capitol)
|
|
84
|
+
Reference(root.Assets.Cosmetics.Pants)
|
|
85
|
+
Reference<Outpost>(id: "capitol-value-id")
|
|
86
|
+
Reference<PantsAsset>(key: "pants.long")
|
|
87
|
+
Reference<PantsAsset>(key: "pants.long", index: Slug)
|
|
88
|
+
Reference<Dialogue>(id: "capitol-dialogue-id")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- Use a symbol or root path when source can name the value directly.
|
|
92
|
+
- Use `key:` only for a collection with a unique index. Omit `index:` when the
|
|
93
|
+
collection has exactly one usable unique index; supply the bare member name
|
|
94
|
+
when it has more than one.
|
|
95
|
+
- Use the generic `id:` form when the ID is the only target information. A
|
|
96
|
+
`Reference` call whose argument is neither `id:` nor `key:` is rejected by
|
|
97
|
+
name rather than read as an ID.
|
|
98
|
+
- Both forms are legal in a member's declaration default, not only inside a
|
|
99
|
+
value graph. A key written there resolves after every pass has run, so it may
|
|
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.
|
|
103
|
+
|
|
104
|
+
Declaration and file order do not affect resolution within one push. Cyclic
|
|
105
|
+
identity references are legal because they resolve IDs rather than evaluate a
|
|
106
|
+
dependency graph. Validate against the project after the push: a row deleted by
|
|
107
|
+
the edit is not a target, and lookup/dialogue references must still satisfy
|
|
108
|
+
assignability, collection membership, multiplicity, and group constraints.
|
|
109
|
+
|
|
110
|
+
`collectionValue` references follow the same post-push resolution and
|
|
111
|
+
membership rules as member defaults.
|
|
112
|
+
|
|
113
|
+
## Defaults and localization
|
|
114
|
+
|
|
115
|
+
Materialize omitted members from their current defaults only when an instance
|
|
116
|
+
is created. Do not expect later class-default changes to update existing rows.
|
|
117
|
+
Removing an explicitly materialized field from an existing initializer requests
|
|
118
|
+
a reset through the current default; require that change to appear in
|
|
119
|
+
`neo diff`.
|
|
120
|
+
|
|
121
|
+
Write main-locale text directly in localizable string initializers. Pull/lower
|
|
122
|
+
preserves other locales, comments, statuses, archive state, and unrelated
|
|
123
|
+
localized-text links. Do not author localized-text IDs in place of prose.
|
|
124
|
+
|
|
125
|
+
## Managed files
|
|
126
|
+
|
|
127
|
+
Declare files in typed registries:
|
|
128
|
+
|
|
129
|
+
```neo
|
|
130
|
+
ImageRegistry Images = new() {
|
|
131
|
+
@id("sword-image-file-id")
|
|
132
|
+
@settings(template: PixelArt)
|
|
133
|
+
NeoImage Sword = new("Files/Images/Sword.png");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
AudioClipRegistry AudioClips = new() {
|
|
137
|
+
@id("sword-hit-audio-file-id")
|
|
138
|
+
@settings(template: SoundEffect)
|
|
139
|
+
NeoAudioClip SwordHit = new("Files/AudioClips/SwordHit.wav");
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Reference a sprite with `Images.Sword.Slice(0)` and an audio clip with
|
|
144
|
+
`AudioClips.SwordHit`. A bare `Images.Sword` represents the file ID only in a
|
|
145
|
+
file-valued context such as `SpriteInfo.FileId`; it is not a complete sprite.
|
|
146
|
+
|
|
147
|
+
Dropping a supported binary under `Files/Images/` or `Files/AudioClips/`
|
|
148
|
+
creates a pending file with a provisional deterministic symbol. Status,
|
|
149
|
+
diff, and dry-run do not rewrite its registry. A successful push creates the
|
|
150
|
+
record, uploads verified bytes, and materializes its declaration and ID.
|
|
151
|
+
|
|
152
|
+
Use `neo files add <path> [--template <Name>]` to scaffold a declaration before
|
|
153
|
+
push when desired.
|
|
154
|
+
|
|
155
|
+
Pull/push compare server-verified SHA-256, not storage ETags. A divergent
|
|
156
|
+
binary keeps local bytes and writes the verified remote side under
|
|
157
|
+
`.neo/conflicts/files/<file-id>/`. A retained declaration with a missing binary
|
|
158
|
+
is an error; remove the declaration to request deletion.
|