@velarscript/cli 0.19.1 → 0.20.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.
Files changed (45) hide show
  1. package/dist/application-entry.d.ts +13 -0
  2. package/dist/application-entry.d.ts.map +1 -0
  3. package/dist/application-entry.js +14 -0
  4. package/dist/application-entry.js.map +1 -0
  5. package/dist/cli.js +15 -41
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config.d.ts +3 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +18 -2
  10. package/dist/config.js.map +1 -1
  11. package/dist/dev-server.d.ts.map +1 -1
  12. package/dist/dev-server.js +11 -0
  13. package/dist/dev-server.js.map +1 -1
  14. package/dist/mechanical-fixer.d.ts +4 -2
  15. package/dist/mechanical-fixer.d.ts.map +1 -1
  16. package/dist/mechanical-fixer.js +17 -4
  17. package/dist/mechanical-fixer.js.map +1 -1
  18. package/dist/node-application.d.ts +7 -9
  19. package/dist/node-application.d.ts.map +1 -1
  20. package/dist/node-application.js +20 -58
  21. package/dist/node-application.js.map +1 -1
  22. package/dist/node-production-build.d.ts +4 -4
  23. package/dist/node-production-build.d.ts.map +1 -1
  24. package/dist/node-production-build.js +5 -5
  25. package/dist/node-production-build.js.map +1 -1
  26. package/dist/node-production-verifier.d.ts.map +1 -1
  27. package/dist/node-production-verifier.js +8 -5
  28. package/dist/node-production-verifier.js.map +1 -1
  29. package/dist/project-check.d.ts +15 -3
  30. package/dist/project-check.d.ts.map +1 -1
  31. package/dist/project-check.js +86 -19
  32. package/dist/project-check.js.map +1 -1
  33. package/dist/project-format.d.ts +1 -1
  34. package/dist/project-format.d.ts.map +1 -1
  35. package/dist/project-format.js +1 -0
  36. package/dist/project-format.js.map +1 -1
  37. package/dist/reproduction.js +5 -5
  38. package/dist/reproduction.js.map +1 -1
  39. package/dist/version.d.ts +1 -1
  40. package/dist/version.js +1 -1
  41. package/package.json +8 -8
  42. package/skill/ai-skill-node.md +38 -23
  43. package/skill/ai-skill-server.md +39 -30
  44. package/skill/ai-skill-web.md +9 -0
  45. package/skill/ai-skill.md +3 -1
@@ -10,11 +10,12 @@ capabilities, or application configuration.
10
10
  path-pattern strings, Node modules, HTTP/WebSocket transport, and low-level
11
11
  server lifecycle; it does not own convention-based application configuration.
12
12
  An ordinary service activates `@velarscript/server` and then loads
13
- `velar skill server` for root `application.*`, application assembly, and
13
+ `velar skill server` for manifest-declared application configuration, assembly, and
14
14
  connection lifecycle.
15
15
 
16
- A deliberately low-level Node application may activate Node directly and name
17
- one exported zero-argument async startup function:
16
+ A deliberately low-level Node application may activate Node directly. Its
17
+ selected entry source owns startup inside `@main`, exactly like Core, Web, and
18
+ Desktop entries:
18
19
 
19
20
  ```json
20
21
  {
@@ -23,42 +24,41 @@ one exported zero-argument async startup function:
23
24
  "outDir": "dist",
24
25
  "publicDir": "public",
25
26
  "build": {"mode": "production", "sourceMaps": false},
26
- "extensions": ["@velarscript/node"],
27
- "node": {
28
- "app": "start"
29
- }
27
+ "extensions": ["@velarscript/node"]
30
28
  }
31
29
  ```
32
30
 
33
31
  The low-level entry owns its own startup arguments in code:
34
32
 
35
33
  ```velar fragment
36
- import {serve} from "velar/serve"
34
+ import {run, serve} from "velar/serve"
37
35
  import {app} from "./app.vel"
38
36
 
39
- export async def start():
40
- return await serve(app, port=3000, host="127.0.0.1")
37
+ @main:
38
+ const server = await serve(app, port=3000, host="127.0.0.1")
39
+ await run(server)
41
40
  ```
42
41
 
43
- For one shared HTTP/WebSocket application port, the same exact zero-argument
44
- shape returns `Promise<WebSocketServer>`:
42
+ For one shared HTTP/WebSocket application port, use the WebSocket transport's
43
+ matching lifecycle operation:
45
44
 
46
45
  ```velar fragment
47
46
  import {app as routes} from "./app.vel"
48
- import {listen} from "velar/websocket"
47
+ import {listen, run} from "velar/websocket"
49
48
 
50
- export async def start():
51
- return await listen({
49
+ @main:
50
+ const server = await listen({
52
51
  host: "127.0.0.1",
53
52
  port: 3000,
54
53
  http: routes,
55
54
  origins: ["https://app.example.com"],
56
55
  maxBodyBytes: 16777216,
57
56
  })
57
+ await run(server)
58
58
  ```
59
59
 
60
- The exact result is `Promise<WebSocketServer>`. The launcher supplies no
61
- host, port, or body-limit parameters.
60
+ `run(server)` owns SIGINT/SIGTERM shutdown for either transport. The external
61
+ CLI executes the compiled entry module directly.
62
62
 
63
63
  Use direct Node activation for tools, embedded adapters, and tests. For an
64
64
  application service, activate `@velarscript/server`; it provides the same
@@ -83,14 +83,14 @@ type CreateArticle:
83
83
 
84
84
  export server articles:
85
85
  /// Reports whether this service is ready.
86
- @get(p"/health") => {ok: true}
86
+ @get health(p"/health") => {ok: true}
87
87
 
88
- @get(p"/articles/{id:number}?{details:bool?}"):
88
+ @get readArticle(p"/articles/{id:number}?{details:bool?}"):
89
89
  if id < 1:
90
90
  throw HttpProblem({status: 404, code: "article.not_found", title: "Article not found"})
91
91
  return {id, details: details ?? false}
92
92
 
93
- @post(p"/articles", input: CreateArticle):
93
+ @post createArticle(p"/articles", input: CreateArticle):
94
94
  return created({id: 1, title: input.title})
95
95
 
96
96
  ```
@@ -114,6 +114,12 @@ patterns require `as name` so the compiler never injects identifiers that are
114
114
  hidden inside another declaration. The old `path=` spelling is an error with a
115
115
  mechanical fix to the positional form and `as path`.
116
116
 
117
+ For a public contract, put one stable source identifier between the role and
118
+ the pattern: `@get readArticle(...)` or `@websocket worldRealtime(...)`.
119
+ Operation identities must be unique after composition, survive `prefix`, and
120
+ are emitted verbatim to OpenAPI. Leave the name out only for a local route whose
121
+ method/path-derived OpenAPI identity is sufficient.
122
+
117
123
  On `POST`, `PUT`, or `PATCH`, one concrete Data parameter is the
118
124
  checked JSON body. A `Request` parameter explicitly requests the complete
119
125
  request, including `queryAll` and cooperative `cancellation`. Ambiguous bodies,
@@ -218,6 +224,12 @@ An app-scoped provider may depend only on other app-scoped providers, may be
218
224
  eager, and releases during shutdown. Cycles and provider-budget exhaustion fail
219
225
  closed. Do not build a controller or container layer around it.
220
226
 
227
+ When the process has already constructed an application resource, bind it with
228
+ `supply(app, provider, value)`. The provider must be app-scoped, the value is
229
+ checked against that provider's inferred result type, and its `release` callback
230
+ still owns shutdown. The binding follows `prefix`, middleware, docs, lifecycle,
231
+ and server composition; supplying the same provider twice is rejected.
232
+
221
233
  ## Composition, lifecycle, and middleware
222
234
 
223
235
  Compose route tables as values:
@@ -282,7 +294,9 @@ task finishes. `setCookie` and
282
294
  fields. Never start long-lived work by
283
295
  dropping a Promise; use an owned lifecycle, background task, Worker, or process.
284
296
 
285
- `docs` adds a bundled offline UI and OpenAPI 3.1 JSON. Compiler route types
297
+ `docs` adds a bundled offline UI and OpenAPI 3.1 JSON. HTTP and WebSocket
298
+ operations share its `paths` catalog; WebSocket entries use GET, response 101,
299
+ and `x-velar-transport: websocket`. Compiler route types
286
300
  and response helpers supply parameter, body, response, content-type, and static
287
301
  success-status schemas. Applicable framework-generated 400, 401, 413, 415, and
288
302
  422 responses are included automatically; a preceding `///` comment supplies
@@ -317,7 +331,7 @@ session belongs in the route table:
317
331
  import {WebSocketConnection} from "velar/websocket"
318
332
 
319
333
  server realtime:
320
- @websocket(p"/worlds/{worldId:string}/realtime", connection: WebSocketConnection):
334
+ @websocket worldRealtime(p"/worlds/{worldId:string}/realtime", connection: WebSocketConnection):
321
335
  async for message in connection:
322
336
  await connection.send(message)
323
337
  ```
@@ -331,7 +345,8 @@ contains these routes rejects its legacy single `path` option and does not offer
331
345
  accepted sessions through `WebSocketServer.next()`.
332
346
 
333
347
  Set
334
- `maxBodyBytes` to the supplied application value. `origins` contains exact
348
+ `maxBodyBytes` to the supplied application value. `host` is non-empty text of
349
+ at most 255 code units without NUL. `origins` contains exact
335
350
  canonical HTTP/HTTPS origins. The default rejects any upgrade carrying
336
351
  `Origin`; no-Origin non-browser clients remain allowed. Use `["*"]` only for an
337
352
  intentional unrestricted policy. A rejected browser origin receives 403 before
@@ -13,7 +13,7 @@ browser application activates `@velarscript/web`:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@velarscript/server": "0.19.1"
16
+ "@velarscript/server": "0.20.1"
17
17
  }
18
18
  }
19
19
  ```
@@ -24,27 +24,33 @@ browser application activates `@velarscript/web`:
24
24
  "entry": "src/main.vel",
25
25
  "outDir": "dist",
26
26
  "publicDir": "public",
27
- "extensions": ["@velarscript/server"]
27
+ "extensions": ["@velarscript/server"],
28
+ "server": {
29
+ "configuration": "application.yml"
30
+ }
28
31
  }
29
32
  ```
30
33
 
31
34
  The Server application extension composes the Node capability. Do not list both
32
35
  extensions. Without `@velarscript/server`, `velar/server` is unavailable and
33
- root application configuration is not loaded.
36
+ application configuration is not loaded.
34
37
 
35
- The conventional entry export is `start`. A different exported binding may be
36
- selected with the optional `server.app` manifest field. Source maps belong to
37
- the target-neutral top-level `build.sourceMaps` switch. Host, port, request limits, database locations, and
38
- other runtime settings never belong in `velar.json`.
38
+ The selected entry source must start the application inside `@main`; there is
39
+ no special exported startup binding. Source maps belong to the target-neutral
40
+ top-level `build.sourceMaps` switch. `velar.json` stores only the project-relative
41
+ configuration path. Host, port, request limits, database locations, and other
42
+ runtime values remain in that YAML or JSON file.
39
43
 
40
44
  ## Convention-based application configuration
41
45
 
42
- The only conventional configuration file is root `application.yml`.
46
+ `server.configuration` is required and is the single configuration source.
47
+ The CLI's minimal template chooses root `application.yml`, but users may rename
48
+ or move it by editing `velar.json`; the framework never scans conventional
49
+ filenames.
43
50
 
44
51
  YAML and JSON enter the same checked runtime-Type boundary. Files are bounded;
45
- YAML is strict, rejects duplicate keys, and limits aliases. An explicit
46
- `.yml`, `.yaml`, or `.json` path is the escape hatch for deployment-specific
47
- configuration; other root filenames are never discovered by convention.
52
+ YAML is strict, rejects duplicate keys, and limits aliases. The declared path
53
+ must stay within the project and end in `.yml`, `.yaml`, or `.json`.
48
54
 
49
55
  The framework-owned server section is:
50
56
 
@@ -56,22 +62,24 @@ server:
56
62
  ```
57
63
 
58
64
  All three fields are optional. Their defaults are `127.0.0.1`, `3000`, and
59
- 16 MiB. `application(app)` reads this section when the server starts:
65
+ 16 MiB. `application(app)` reads this section and creates the server; the
66
+ entry owns its lifetime explicitly:
60
67
 
61
68
  ```velar
62
69
  import {application} from "velar/server"
70
+ import {run} from "velar/serve"
63
71
 
64
72
  export server routes:
65
73
  @get(p"/health") => {status: "ready"}
66
74
 
67
- export const start = application(routes)
75
+ @main:
76
+ const server = await application(routes)
77
+ await run(server)
68
78
  ```
69
79
 
70
80
  `velar dev`, `velar serve`, and the standalone `velar build` output use the
71
- same root configuration. CLI `--host` and Node `--port` overrides are not a
72
- second configuration channel. A missing conventional file uses the server
73
- defaults; when application-specific settings are required, load the full file
74
- with `configuration(Type)`, which requires the file to exist.
81
+ same declared configuration. CLI `--host` and Node `--port` overrides are not
82
+ a second configuration channel. A missing declared file fails closed.
75
83
 
76
84
  ## Typed application settings
77
85
 
@@ -93,11 +101,12 @@ type ApplicationSettings:
93
101
  server: ServerSettings
94
102
  database: DatabaseSettings
95
103
 
96
- export const settings = await configuration(ApplicationSettings)
104
+ export async def loadSettings() -> ApplicationSettings:
105
+ return await configuration(ApplicationSettings)
97
106
  ```
98
107
 
99
- `configuration(Type, path=null, maxBytes=65536)` returns
100
- `Promise<Type>`. A non-null path must end in `.yml`, `.yaml`, or `.json`.
108
+ `configuration(Type, maxBytes=65536)` returns `Promise<Type>` and always reads
109
+ the manifest-declared path.
101
110
  The framework parses syntax; the application Runtime Type owns field names and
102
111
  types, and application validation still owns domain ranges and invariants.
103
112
  Environment variables may form an explicit deployment override layer, but
@@ -238,12 +247,12 @@ idempotent handling.
238
247
  ## Custom shared HTTP/WebSocket startup
239
248
 
240
249
  A service whose route table contains `@websocket` declarations may load the
241
- same typed configuration and export an exact zero-argument async startup
242
- function for the shared HTTP/WebSocket listener:
250
+ same typed configuration and create the shared HTTP/WebSocket listener inside
251
+ `@main`:
243
252
 
244
253
  ```velar fragment
245
254
  import {configuration} from "velar/server"
246
- import {listen} from "velar/websocket"
255
+ import {listen, run} from "velar/websocket"
247
256
 
248
257
  type ServerSettings:
249
258
  host: string
@@ -253,21 +262,21 @@ type ServerSettings:
253
262
  type Settings:
254
263
  server: ServerSettings
255
264
 
256
- const settings = await configuration(Settings)
257
-
258
- export async def start():
259
- return await listen({
265
+ @main:
266
+ const settings = await configuration(Settings)
267
+ const server = await listen({
260
268
  host: settings.server.host,
261
269
  port: settings.server.port,
262
270
  http: routes,
263
271
  origins: ["https://app.example.com"],
264
272
  maxBodyBytes: settings.server.maxBodyBytes,
265
273
  })
274
+ await run(server)
266
275
  ```
267
276
 
268
- The result must be exactly `Promise<WebSocketServer>`. The launcher supplies no
269
- host, port, or body-limit arguments; the root application configuration remains
270
- the single runtime authority. Each `@websocket` RoutePattern owns its own path,
277
+ The entry module itself is the executable artifact; the declared application
278
+ configuration remains the single runtime authority. Each `@websocket`
279
+ RoutePattern owns its own path,
271
280
  typed captures, admission inputs, and session handler, so this declarative mode
272
281
  does not accept the listener's legacy single `path` option.
273
282
 
@@ -23,6 +23,15 @@ modules, and the `web` manifest key. Without that extension these are not Core
23
23
  syntax. Web visual builders are named imports from `velar/look`; there is no
24
24
  `Look.` namespace.
25
25
 
26
+ Every word in that list is a contextual keyword that stays available as an
27
+ ordinary name — except five. `mount`, `tick`, `viewport`, `scheme`, and `motion`
28
+ are **reserved bindings**: `mount` and `tick` are real runtime entry points, and
29
+ `viewport`, `scheme`, and `motion` name the Look media subjects, so a local
30
+ binding can never shadow a media condition. A Web module refuses all five as
31
+ binding names with `VEL3007`. Three of them are ordinary words for a Web author,
32
+ so name a scroll container `scroller`, a colour setting `theme`, and an
33
+ animation preference `reducedMotion`.
34
+
26
35
  `@` remains the language-wide annotation introducer, and `@name` is a context
27
36
  annotation with a compiler-owned compile-time role. Components own `@mounted:`
28
37
  and `@cleanup:`; Look owns conditions such as `@hover` and `@before`. They are
package/skill/ai-skill.md CHANGED
@@ -75,7 +75,8 @@ considering source fallback. Other templates select their own framework brief. E
75
75
  `velar.json`, a `package.json` whose scripts are the gates, a `src/` tree, a
76
76
  passing test, and an `AGENTS.md`.
77
77
 
78
- Writing the manifest yourself: `formatVersion` is required, `extensions` may be
78
+ Writing the manifest yourself: `formatVersion` is required, `kind` may be
79
+ `application` or `library` (and defaults to `application`), `extensions` may be
79
80
  omitted by a project that loads none, `entry` defaults to `src/main.vel`,
80
81
  `outDir` to `dist`, and `publicDir` to `public`.
81
82
 
@@ -84,6 +85,7 @@ A Core project (CLI or library) loads no extensions:
84
85
  ```json
85
86
  {
86
87
  "formatVersion": 2,
88
+ "kind": "library",
87
89
  "entry": "src/main.vel",
88
90
  "extensions": []
89
91
  }