@vizualmodel/vmblu-cli 0.3.5 → 0.4.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/README.md +8 -6
- package/commands/init/init-project.js +41 -28
- package/commands/profile/profile.bundle.js +2611 -1307
- package/package.json +4 -3
- package/templates/0.9.1/blueprint.annex.md +268 -0
- package/templates/0.9.1/blueprint.schema.json +372 -0
- package/templates/0.9.1/profile.schema.json +74 -0
- package/templates/0.9.1/system-prompt.md +72 -0
- package/templates/0.9.1/vizual.schema.json +169 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizualmodel/vmblu-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"schemaVersion": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"schemaVersion": "0.9.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"vmblu": "bin/vmblu.js"
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"vmblu": "vmblu",
|
|
40
|
-
"local": "node ./bin/vmblu.js profile",
|
|
40
|
+
"local-profile": "node ./bin/vmblu.js profile",
|
|
41
|
+
"local-init": "node ./bin/vmblu.js init",
|
|
41
42
|
"build": "rollup -c ./commands/profile/rollup.config.js"
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Annex A: Semantic Clarifications for blueprint.schema.json
|
|
2
|
+
|
|
3
|
+
This annex captures subtle semantic points that are not fully enforceable in the JSON Schema but are critical for correct usage of the vmblu format by both humans and LLMs.
|
|
4
|
+
|
|
5
|
+
## A.1 Nodes
|
|
6
|
+
|
|
7
|
+
A source node represents an indivisible implementation unit, whereas a group node is a purely architectural composition of nodes.
|
|
8
|
+
A source node can represent a UI element, the access to a database, a login procedure, a 3D scene list etc.
|
|
9
|
+
The name of a node should be meaningful and unique inside a group node.
|
|
10
|
+
The prompt for a node should be a clear, concise and up-to-date description of its function.
|
|
11
|
+
|
|
12
|
+
## A.2 Interface names and Pin names
|
|
13
|
+
|
|
14
|
+
- Pins are grouped in **interfaces**
|
|
15
|
+
- There can only be one anonymous interface (name is ""), this is acceptable for nodes that only have a few pins.
|
|
16
|
+
- Group pins together into meaningful interfaces
|
|
17
|
+
- Use the following convention when giving a name to a pin: if the pin belongs to an interface start the name with the name of that interface followed by a period. If the rest of the name is more than one word, separate the words by a hyphen. Examples: _file.save_, _file.save-as_, _file.convert-to-uppercase_, where the interface name is _file_.
|
|
18
|
+
|
|
19
|
+
## A.3 Pin contracts and types
|
|
20
|
+
|
|
21
|
+
### (1) Types and `vmbluType`
|
|
22
|
+
|
|
23
|
+
* `vmbluType` always refers to either:
|
|
24
|
+
|
|
25
|
+
* a primitive (`string`, `number`, `boolean`, `any`, …), or
|
|
26
|
+
* a named type in the model’s `types` section.
|
|
27
|
+
* Structural payload details belong in the `types` section, not on pins.
|
|
28
|
+
|
|
29
|
+
### (2) Pin contract roles
|
|
30
|
+
|
|
31
|
+
* Every pin may declare a `contract` with a `role`:
|
|
32
|
+
|
|
33
|
+
* `role: "owner"` means: **this pin defines the payload type** and is authoritative.
|
|
34
|
+
* `role: "follower"` means: **this pin adapts** to the connected owner’s contract.
|
|
35
|
+
* If `role` is `"owner"`, the pin contract must include the payload type
|
|
36
|
+
* If `role` is `"follower"`, the pin must *not* include the payload type
|
|
37
|
+
|
|
38
|
+
A follower pin has no payload type by itself; it becomes meaningful only when connected. When a follower pin is disconnected, it stays a follower and has no stored payload type.
|
|
39
|
+
|
|
40
|
+
For input/output pins, the payload type is a single type that refers to a type in the `types`section. For request/reply pins the payload type consists of two types: the request payload and the reply payload. Both types also refer to a type in the `types` section.
|
|
41
|
+
|
|
42
|
+
A contract can thus have three different forms:
|
|
43
|
+
|
|
44
|
+
* for pins that follow it is simply
|
|
45
|
+
```json
|
|
46
|
+
"contract" : {
|
|
47
|
+
"role": "follower"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
* for input or output pins that own the contract it is
|
|
51
|
+
```json
|
|
52
|
+
"contract" : {
|
|
53
|
+
"role": "owner",
|
|
54
|
+
"payload" : "vmbluType"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
* for request or reply pins that own the contract it is
|
|
58
|
+
```json
|
|
59
|
+
"contract" : {
|
|
60
|
+
"role": "owner",
|
|
61
|
+
"payload" : {
|
|
62
|
+
"request" : "vmbluType",
|
|
63
|
+
"reply": "vmbluType"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Keep the blueprint lean and deterministic. Avoid duplicating payload shapes in multiple places; define once in `types` and reference in the contract payload.
|
|
69
|
+
|
|
70
|
+
## A.4 Connections
|
|
71
|
+
|
|
72
|
+
Connections are always made between pins. Interfaces are organizational only and are never connection endpoints.
|
|
73
|
+
Connections between pins are specified in the `connections` array. Message flow is from `src` to `dst`. `src` and `dst` are specified by the name of the pin and the name of the node. If the name of the node is omitted it is supposed to be a pin of the group node that contains the connection. This is the only way to receive messages from or send messages to the outside of the group node.
|
|
74
|
+
|
|
75
|
+
This means that the following connections are valid
|
|
76
|
+
|
|
77
|
+
* src: output pin @ node, dst : input pin @ node
|
|
78
|
+
simple connection
|
|
79
|
+
* src: request pin @ node, dst reply pin @ node
|
|
80
|
+
request/reply
|
|
81
|
+
* src: request pin @ node, dst: input pin @ node
|
|
82
|
+
input pin can listen to requests, but not reply
|
|
83
|
+
* src: output pin @ node, dst: output pin
|
|
84
|
+
An output pin of a node is connected to an output pin of the containing group node
|
|
85
|
+
* src: input pin, dst: input pin @ node
|
|
86
|
+
An input pin of the containing group node is connected to an input of a node inside the group node.
|
|
87
|
+
|
|
88
|
+
For a connection between two pins also the contracts of the pins have to be checked.
|
|
89
|
+
|
|
90
|
+
* **owner ↔ follower**: valid. The follower must conform to the owner’s `payload`.
|
|
91
|
+
* **owner ↔ owner**: valid only if both owners’ `payload` values match. If they do not match, the connection is invalid unless one side is changed to `follower`.
|
|
92
|
+
* **follower ↔ follower**: invalid. To make it valid, upgrade one side to `owner` and define its `vmbluType`.
|
|
93
|
+
|
|
94
|
+
Implementation obligations:
|
|
95
|
+
|
|
96
|
+
* When connecting a follower to an owner, adapt the follower implementation (or add an adapter node) so its payload handling conforms to the owner’s `vmbluType`.
|
|
97
|
+
* Changing an owner’s `vmbluType` is a breaking change for all connected followers; update them accordingly.
|
|
98
|
+
* Changing a pin’s role (`owner` ↔ `follower`) is an architectural decision. Do it deliberately and update connections/implementations accordingly.
|
|
99
|
+
* If a connection is invalid under the rules above, either:
|
|
100
|
+
|
|
101
|
+
* adjust roles, or
|
|
102
|
+
* introduce an explicit adapter node, or
|
|
103
|
+
* change payload types (as a conscious breaking change).
|
|
104
|
+
|
|
105
|
+
## A.5 Pin Message Handlers
|
|
106
|
+
|
|
107
|
+
Every **input** or **reply** pin corresponds to a message handler in the node implementation.
|
|
108
|
+
|
|
109
|
+
The naming convention for a handler is as follows:
|
|
110
|
+
|
|
111
|
+
- Handler name is `on<PinNameInCamelCase>`.
|
|
112
|
+
- Example:
|
|
113
|
+
- Pin: `"name": "saveMessage", "kind": "input"`
|
|
114
|
+
- Handler: `onSaveMessage(payload)`
|
|
115
|
+
|
|
116
|
+
This uniform convention ensures LLMs and the editor can always map pins to their corresponding handler.
|
|
117
|
+
|
|
118
|
+
Do not return a value from a handler, it is ignored.
|
|
119
|
+
|
|
120
|
+
## A.6 Pin prompts
|
|
121
|
+
|
|
122
|
+
A **pin prompt** is a short, natural-language description written primarily for an LLM during the **design phase** of a system.
|
|
123
|
+
|
|
124
|
+
It serves as:
|
|
125
|
+
|
|
126
|
+
* semantic guidance for generating handlers and emitters,
|
|
127
|
+
* a reminder of *why* a pin exists,
|
|
128
|
+
* a clarification of *when* a pin is used.
|
|
129
|
+
|
|
130
|
+
It is **not** a specification and **not authoritative**. Do not duplicate in a prompt what is in the pin contract.
|
|
131
|
+
|
|
132
|
+
## What a Pin Prompt Should Answer
|
|
133
|
+
|
|
134
|
+
Depending on pin kind, the prompt should answer **one core question**.
|
|
135
|
+
|
|
136
|
+
* Output pins: *When do I emit, and why?*
|
|
137
|
+
* Input pins: *What do I do when a message arrives?*
|
|
138
|
+
* Request pins: *What is being requested, and for what purpose?*
|
|
139
|
+
* Reply pins: *What does this reply confirm or return?*
|
|
140
|
+
|
|
141
|
+
A pin prompt must **not**:
|
|
142
|
+
|
|
143
|
+
* Describe payload fields or structure
|
|
144
|
+
(that belongs in `types`)
|
|
145
|
+
* Repeat `vmbluType`
|
|
146
|
+
* Define validation rules
|
|
147
|
+
* Impose constraints not expressible elsewhere
|
|
148
|
+
* Explain internal implementation details
|
|
149
|
+
|
|
150
|
+
Avoid phrases like:
|
|
151
|
+
|
|
152
|
+
* “This pin sends an object containing…”
|
|
153
|
+
* “The payload has fields…”
|
|
154
|
+
* “Must always / must never…”
|
|
155
|
+
|
|
156
|
+
## Length and Form
|
|
157
|
+
|
|
158
|
+
* **1–2 sentences**
|
|
159
|
+
* **Present tense**
|
|
160
|
+
* **Plain language**
|
|
161
|
+
* No lists, no markdown, no long explanations
|
|
162
|
+
|
|
163
|
+
Think: *intent note*, not documentation.
|
|
164
|
+
|
|
165
|
+
## Examples
|
|
166
|
+
|
|
167
|
+
* output: *“Emits updated orbital parameters whenever the simulation time advances. Trigger: after physics integration.”*
|
|
168
|
+
* input: *“Applies incoming orbit updates to update the rendered trajectory.”*
|
|
169
|
+
* request: *“Requests the active camera data.”*
|
|
170
|
+
* reply: *“Returns the spec of the active camera to the requestor.”*
|
|
171
|
+
|
|
172
|
+
## A.7 Request / Reply Semantics
|
|
173
|
+
|
|
174
|
+
A Request/Reply connection allows to group a message and the response to that message in one exchange.
|
|
175
|
+
Because the Request/Reply connection consists of two data exchanges, the request and the reply, the contract for the pin in the owner-role contains two vmbluTypes: one for the request and one for the reply.
|
|
176
|
+
|
|
177
|
+
- A **request pin** is an **output pin**.
|
|
178
|
+
- It is used by the requester node to initiate a request with `tx.request('pinName', payload)`.
|
|
179
|
+
- This function returns a **Promise** which resolves when the callee replies. The **Promise** is generated and managed by the runtime.
|
|
180
|
+
|
|
181
|
+
- A **reply pin** is an **input pin** on the callee.
|
|
182
|
+
- It receives the request payload and has a handler like any input pin.
|
|
183
|
+
- Inside this handler, the callee must call `tx.reply(payload)` to respond to the requester.
|
|
184
|
+
- The runtime delivers this reply on the backchannel and resolves the requester’s Promise.
|
|
185
|
+
- Note that the handler return value is ignored, optional async only to await internal work.
|
|
186
|
+
- If tx.reply is not called, the request promise will simply time out.
|
|
187
|
+
|
|
188
|
+
- **Connections**:
|
|
189
|
+
- Normally, `request` pins connect to `reply` pins.
|
|
190
|
+
- It is also valid to connect a `request` pin to an `input` pin (e.g. for logging or monitoring), but in that case no reply is sent.
|
|
191
|
+
|
|
192
|
+
Typical use of request/reply
|
|
193
|
+
|
|
194
|
+
The requesting node issues a request and then waits for the reply
|
|
195
|
+
|
|
196
|
+
```js
|
|
197
|
+
tx.request('pinName', requestPayload).then ( replyPayload => {
|
|
198
|
+
|
|
199
|
+
// handle the reply from the other node
|
|
200
|
+
...
|
|
201
|
+
})
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The receiving node has a handler for the request
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
onPinName(requestPayload) {
|
|
208
|
+
// does some processing
|
|
209
|
+
...
|
|
210
|
+
// and replies to the requesting node
|
|
211
|
+
tx.reply(replyPayload)
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## A.8 Factory Function Signature
|
|
216
|
+
|
|
217
|
+
A source node references its implementation via a **factory** object (`path` + `function`).
|
|
218
|
+
The factory function is called by the runtime to create the node instance.
|
|
219
|
+
|
|
220
|
+
The runtime will detect if the factory function is a generator function or a class name and will call the factory function in that case as follows: `new factoryFunction(...)`
|
|
221
|
+
|
|
222
|
+
In order to let documentation tools find the handlers of a node, add a _node_ JSdoc tag in the file where the handlers are defined.
|
|
223
|
+
The tage remains valid until the end of the file or until a new node tag is defined.
|
|
224
|
+
|
|
225
|
+
- Signature:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
/**
|
|
229
|
+
* @node node name
|
|
230
|
+
*/
|
|
231
|
+
export function createMyNode( tx, sx ) { ... }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- tx: object exposing runtime message functions (send, request, reply).
|
|
235
|
+
- sx: arbitrary initialization data supplied by the model. sx can be null.
|
|
236
|
+
- rx: not passed to the node. Runtime-only directives; used by the runtime to decide how/where to host the node (e.g. worker thread, debug flags).
|
|
237
|
+
|
|
238
|
+
## A.9 Dock Nodes and Drift
|
|
239
|
+
|
|
240
|
+
- A dock node references another node defined in a different file via a link.
|
|
241
|
+
- Pins and connections of the dock node are kept in the importing file.
|
|
242
|
+
- If the external node definition changes, the editor highlights differences (“drift”) between the dock node and its linked definition.
|
|
243
|
+
|
|
244
|
+
## A.10 MCP Support
|
|
245
|
+
|
|
246
|
+
Vmblu supports the Model Context Protocol (MCP). An LLM can directly communicate with nodes of a vmblu application by sending messages to nodes. The node has to indicate which inputs are available as an MCP tool simply by adding the tag 'mcp' before the handler's header:
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
/**
|
|
250
|
+
* @mcp
|
|
251
|
+
* @param ...
|
|
252
|
+
*/
|
|
253
|
+
onMessage() { // handler for the message
|
|
254
|
+
...
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The messages marked will be assembled by the vmblu editor into a tool file that can be used by an LLM interacting with the application.
|
|
259
|
+
|
|
260
|
+
## A.11 AI Generation Guidelines
|
|
261
|
+
|
|
262
|
+
For LLMs working with vmblu files:
|
|
263
|
+
|
|
264
|
+
- Respect node and pin names — do not rename unless explicitly asked.
|
|
265
|
+
- When generating source code for the nodes in the vmblu file, only generate code for the nodes, the _main_ function and node setup is generated directly from the vmblu file itself.
|
|
266
|
+
- When changing code for an application only change the code for the nodes, not the application file that was generated. That file will be re-generated by the editor.
|
|
267
|
+
|
|
268
|
+
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "@vizual_model/cli/templates/0.9.1/blueprint.schema.json",
|
|
4
|
+
"title": "vmblu Blueprint Model (v0.9.1)",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["header", "root"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"header": { "$ref": "#/$defs/Header" },
|
|
10
|
+
|
|
11
|
+
"imports": {
|
|
12
|
+
"description": "List of vmblu blueprint files that are referenced in the model. Allows for faster loading.",
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": { "type": "string", "minLength": 1 },
|
|
15
|
+
"uniqueItems": true
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
"factories": {
|
|
19
|
+
"description": "List of files where the source code of the source nodes can be found. Used by the docgen tool.",
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": { "type": "string", "minLength": 1 },
|
|
22
|
+
"uniqueItems": true
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
"libraries": {
|
|
26
|
+
"description": "List of vmblu blueprint files from which the editor allows the user to select nodes in an easy way.",
|
|
27
|
+
"type": "array",
|
|
28
|
+
"items": { "type": "string", "minLength": 1 },
|
|
29
|
+
"uniqueItems": true
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
"types": {
|
|
33
|
+
"description": "Repository of named data types used in pin contracts. Each vmbluType is either a primitive (string/number/boolean/any/...) or a key in this 'types' object.",
|
|
34
|
+
"$ref": "#/$defs/Types"
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
"root": {
|
|
38
|
+
"description": "The starting point of the vmblu blueprint model.",
|
|
39
|
+
"$ref": "#/$defs/Node"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
"$defs": {
|
|
44
|
+
"Header": {
|
|
45
|
+
"description": "Contains meta information about the model. Used by tools and editors.",
|
|
46
|
+
"type": "object",
|
|
47
|
+
"properties": {
|
|
48
|
+
"version": { "type": "string" },
|
|
49
|
+
"created": { "type": "string", "format": "date-time" },
|
|
50
|
+
"saved": { "type": "string", "format": "date-time" },
|
|
51
|
+
"utc": { "type": "string", "format": "date-time" },
|
|
52
|
+
"style": { "type": "string" },
|
|
53
|
+
"runtime": { "type": "string" }
|
|
54
|
+
},
|
|
55
|
+
"additionalProperties": false,
|
|
56
|
+
"required": ["version", "created", "saved", "utc"]
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
"Types": {
|
|
60
|
+
"description": "Repository of named architectural data types.",
|
|
61
|
+
"type": "object",
|
|
62
|
+
"additionalProperties": { "$ref": "#/$defs/Type" }
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
"Type": {
|
|
66
|
+
"description": "Definition of a single named type used in contracts.",
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {
|
|
69
|
+
"kind": {
|
|
70
|
+
"description": "Basic category of the type.",
|
|
71
|
+
"type": "string",
|
|
72
|
+
"enum": ["object", "array", "external", "primitive"],
|
|
73
|
+
"default": "object"
|
|
74
|
+
},
|
|
75
|
+
"summary": {
|
|
76
|
+
"description": "Short human-readable description of the type.",
|
|
77
|
+
"type": "string"
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
"fields": {
|
|
81
|
+
"description": "For object types: map of field name to field descriptor.",
|
|
82
|
+
"type": "object",
|
|
83
|
+
"additionalProperties": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"properties": {
|
|
86
|
+
"vmbluType": {
|
|
87
|
+
"description": "A vmblu type: either a primitive (string/number/boolean/any/...) or a named type key in the 'types' section.",
|
|
88
|
+
"type": "string",
|
|
89
|
+
"minLength": 1
|
|
90
|
+
},
|
|
91
|
+
"summary": {
|
|
92
|
+
"description": "Short description of the field.",
|
|
93
|
+
"type": "string"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"required": ["vmbluType"],
|
|
97
|
+
"additionalProperties": false
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
"required": {
|
|
102
|
+
"description": "For object types: list of required field names.",
|
|
103
|
+
"type": "array",
|
|
104
|
+
"items": { "type": "string", "minLength": 1 },
|
|
105
|
+
"uniqueItems": true
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
"items": {
|
|
109
|
+
"description": "For array types: element type descriptor.",
|
|
110
|
+
"type": "object",
|
|
111
|
+
"properties": {
|
|
112
|
+
"vmbluType": {
|
|
113
|
+
"description": "A vmblu type: either a primitive (string/number/boolean/any/...) or a named type key in the 'types' section.",
|
|
114
|
+
"type": "string",
|
|
115
|
+
"minLength": 1
|
|
116
|
+
},
|
|
117
|
+
"summary": {
|
|
118
|
+
"description": "Short description of the element.",
|
|
119
|
+
"type": "string"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"required": ["vmbluType"],
|
|
123
|
+
"additionalProperties": false
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
"external": {
|
|
127
|
+
"description": "For external/opaque types: identifies the external symbol (e.g. THREE.Vector3).",
|
|
128
|
+
"type": "object",
|
|
129
|
+
"properties": {
|
|
130
|
+
"library": {
|
|
131
|
+
"description": "Library or package providing this type (e.g. 'three').",
|
|
132
|
+
"type": "string",
|
|
133
|
+
"minLength": 1
|
|
134
|
+
},
|
|
135
|
+
"symbol": {
|
|
136
|
+
"description": "Symbol name of the type in the library (e.g. 'Vector3').",
|
|
137
|
+
"type": "string",
|
|
138
|
+
"minLength": 1
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"required": ["symbol"],
|
|
142
|
+
"additionalProperties": false
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"allOf": [
|
|
146
|
+
{
|
|
147
|
+
"oneOf": [
|
|
148
|
+
{
|
|
149
|
+
"description": "Object type must define fields.",
|
|
150
|
+
"properties": { "kind": { "const": "object" } },
|
|
151
|
+
"required": ["fields"]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"description": "Array type must define items.",
|
|
155
|
+
"properties": { "kind": { "const": "array" } },
|
|
156
|
+
"required": ["items"]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"description": "External type must define external symbol info.",
|
|
160
|
+
"properties": { "kind": { "const": "external" } },
|
|
161
|
+
"required": ["external"]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"description": "Primitive type is opaque here (typically used for documentation or aliasing).",
|
|
165
|
+
"properties": { "kind": { "const": "primitive" } }
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
"additionalProperties": false
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
"Node": {
|
|
174
|
+
"description": "A node describes a component of a software system. Nodes communicate via messages. There are three types of nodes.",
|
|
175
|
+
"oneOf": [
|
|
176
|
+
{
|
|
177
|
+
"allOf": [
|
|
178
|
+
{ "$ref": "#/$defs/NodeBase" },
|
|
179
|
+
{ "$ref": "#/$defs/SourceNodeSpec" }
|
|
180
|
+
],
|
|
181
|
+
"unevaluatedProperties": false
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"allOf": [
|
|
185
|
+
{ "$ref": "#/$defs/NodeBase" },
|
|
186
|
+
{ "$ref": "#/$defs/GroupNodeSpec" }
|
|
187
|
+
],
|
|
188
|
+
"unevaluatedProperties": false
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"allOf": [
|
|
192
|
+
{ "$ref": "#/$defs/NodeBase" },
|
|
193
|
+
{ "$ref": "#/$defs/DockNodeSpec" }
|
|
194
|
+
],
|
|
195
|
+
"unevaluatedProperties": false
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
"NodeBase": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"kind": { "enum": ["source", "group", "dock"] },
|
|
204
|
+
"name": { "type": "string", "minLength": 1, "pattern": "^[^@]+$" },
|
|
205
|
+
"label": { "type": "string" },
|
|
206
|
+
|
|
207
|
+
"interfaces": {
|
|
208
|
+
"type": "array",
|
|
209
|
+
"items": { "$ref": "#/$defs/Interface" }
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
"prompt": { "type": "string" },
|
|
213
|
+
|
|
214
|
+
"sx": { "$ref": "#/$defs/NodeInitialization" },
|
|
215
|
+
"rx": { "$ref": "#/$defs/RuntimeDirectives" }
|
|
216
|
+
},
|
|
217
|
+
"required": ["kind", "name"]
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
"SourceNodeSpec": {
|
|
221
|
+
"description": "A source node has an implementation in source code.",
|
|
222
|
+
"type": "object",
|
|
223
|
+
"properties": {
|
|
224
|
+
"kind": { "const": "source" },
|
|
225
|
+
"factory": {
|
|
226
|
+
"description": "Describes where the node's implementation can be found.",
|
|
227
|
+
"type": "object",
|
|
228
|
+
"properties": {
|
|
229
|
+
"path": { "type": "string", "minLength": 1 },
|
|
230
|
+
"function": { "type": "string", "minLength": 1 }
|
|
231
|
+
},
|
|
232
|
+
"required": ["path", "function"],
|
|
233
|
+
"additionalProperties": false
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
"required": ["factory"]
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
"GroupNodeSpec": {
|
|
240
|
+
"description": "A group node consists of other connected nodes. It allows to build modular models.",
|
|
241
|
+
"type": "object",
|
|
242
|
+
"properties": {
|
|
243
|
+
"kind": { "const": "group" },
|
|
244
|
+
|
|
245
|
+
"nodes": {
|
|
246
|
+
"type": "array",
|
|
247
|
+
"items": { "$ref": "#/$defs/Node" }
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
"connections": {
|
|
251
|
+
"type": "array",
|
|
252
|
+
"items": { "$ref": "#/$defs/Connection" }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
"DockNodeSpec": {
|
|
258
|
+
"description": "A dock node is a placeholder for a node that is defined in another file, specified in the link field.",
|
|
259
|
+
"type": "object",
|
|
260
|
+
"properties": {
|
|
261
|
+
"kind": { "const": "dock" },
|
|
262
|
+
"link": {
|
|
263
|
+
"type": "object",
|
|
264
|
+
"properties": {
|
|
265
|
+
"path": { "type": "string", "minLength": 1 },
|
|
266
|
+
"node": { "type": "string", "minLength": 1, "pattern": "^[^@]+$" }
|
|
267
|
+
},
|
|
268
|
+
"required": ["node"],
|
|
269
|
+
"additionalProperties": false
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"required": ["link"]
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
"Interface": {
|
|
276
|
+
"description": "An interface groups a number of pins of a node.",
|
|
277
|
+
"type": "object",
|
|
278
|
+
"required": ["name"],
|
|
279
|
+
"properties": {
|
|
280
|
+
"name": { "type": "string", "pattern": "^(|[^@]+)$" },
|
|
281
|
+
"pins": {
|
|
282
|
+
"type": "array",
|
|
283
|
+
"items": { "$ref": "#/$defs/Pin" }
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
"additionalProperties": false
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
"Pin": {
|
|
290
|
+
"description": "A node can receive or send a message via a pin.",
|
|
291
|
+
"type": "object",
|
|
292
|
+
"required": ["name", "kind"],
|
|
293
|
+
"properties": {
|
|
294
|
+
"name": { "type": "string", "minLength": 1, "pattern": "^[^@]+$" },
|
|
295
|
+
"kind": { "enum": ["input", "output", "request", "reply"] },
|
|
296
|
+
"contract": {
|
|
297
|
+
"type": "object",
|
|
298
|
+
"oneOf": [
|
|
299
|
+
{
|
|
300
|
+
"type": "object",
|
|
301
|
+
"properties": {
|
|
302
|
+
"role": { "const": "follower" }
|
|
303
|
+
},
|
|
304
|
+
"required": ["role"],
|
|
305
|
+
"additionalProperties": false
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"type": "object",
|
|
309
|
+
"properties": {
|
|
310
|
+
"role": { "const": "owner" },
|
|
311
|
+
"payload": { "type": "string", "minLength": 1 }
|
|
312
|
+
},
|
|
313
|
+
"required": ["role", "payload"],
|
|
314
|
+
"additionalProperties": false
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"type": "object",
|
|
318
|
+
"properties": {
|
|
319
|
+
"role": { "const": "owner" },
|
|
320
|
+
"payload": {
|
|
321
|
+
"type": "object",
|
|
322
|
+
"properties": {
|
|
323
|
+
"request": { "type": "string", "minLength": 1 },
|
|
324
|
+
"reply": { "type": "string", "minLength": 1 }
|
|
325
|
+
},
|
|
326
|
+
"required": ["request", "reply"],
|
|
327
|
+
"additionalProperties": false
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
"required": ["role", "payload"],
|
|
331
|
+
"additionalProperties": false
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
"prompt": { "type": "string" }
|
|
336
|
+
},
|
|
337
|
+
"additionalProperties": false
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
"Connection": {
|
|
341
|
+
"description": "A connection can be made between two pins. The message flow is from 'src' to 'dst'.",
|
|
342
|
+
"type": "object",
|
|
343
|
+
"additionalProperties": false,
|
|
344
|
+
"required": ["src", "dst"],
|
|
345
|
+
"properties": {
|
|
346
|
+
"src": { "$ref": "#/$defs/Address" },
|
|
347
|
+
"dst": { "$ref": "#/$defs/Address" }
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
"Address": {
|
|
352
|
+
"description": "The address of a pin. If node is omitted the node is the containing group node.",
|
|
353
|
+
"type": "object",
|
|
354
|
+
"additionalProperties": false,
|
|
355
|
+
"properties": {
|
|
356
|
+
"node": { "type": "string", "minLength": 1, "pattern": "^[^@]+$" },
|
|
357
|
+
"pin": { "type": "string", "minLength": 1, "pattern": "^[^@]+$" }
|
|
358
|
+
},
|
|
359
|
+
"required": ["pin"]
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
"NodeInitialization": {
|
|
363
|
+
"description": "Node-defined initialization data passed to the node at creation time. Shape is entirely up to the node designer.",
|
|
364
|
+
"type": "object"
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
"RuntimeDirectives": {
|
|
368
|
+
"description": "Runtime-defined creation/hosting directives. Shape is determined by the runtime (e.g., host=worker, debug=true).",
|
|
369
|
+
"type": "object"
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|