@velarscript/cli 0.11.1 → 0.12.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 (74) hide show
  1. package/README.md +15 -10
  2. package/dist/cli.js +138 -40
  3. package/dist/cli.js.map +1 -1
  4. package/dist/deployment-verifier.d.ts.map +1 -1
  5. package/dist/deployment-verifier.js +1 -3
  6. package/dist/deployment-verifier.js.map +1 -1
  7. package/dist/extension-metadata.d.ts.map +1 -1
  8. package/dist/extension-metadata.js +1 -0
  9. package/dist/extension-metadata.js.map +1 -1
  10. package/dist/language-server-tool.d.ts +0 -1
  11. package/dist/language-server-tool.d.ts.map +1 -1
  12. package/dist/language-server-tool.js +0 -4
  13. package/dist/language-server-tool.js.map +1 -1
  14. package/dist/node-application.d.ts +13 -0
  15. package/dist/node-application.d.ts.map +1 -0
  16. package/dist/node-application.js +276 -0
  17. package/dist/node-application.js.map +1 -0
  18. package/dist/official-language-server-extensions.d.ts.map +1 -1
  19. package/dist/official-language-server-extensions.js +13 -1
  20. package/dist/official-language-server-extensions.js.map +1 -1
  21. package/dist/production-build.d.ts +1 -1
  22. package/dist/production-build.d.ts.map +1 -1
  23. package/dist/production-build.js +0 -2
  24. package/dist/production-build.js.map +1 -1
  25. package/dist/production-verifier.js +1 -17
  26. package/dist/production-verifier.js.map +1 -1
  27. package/dist/project-format.d.ts +1 -1
  28. package/dist/project-format.d.ts.map +1 -1
  29. package/dist/project-format.js +1 -1
  30. package/dist/project-format.js.map +1 -1
  31. package/dist/project.d.ts +3 -0
  32. package/dist/project.d.ts.map +1 -1
  33. package/dist/project.js +64 -0
  34. package/dist/project.js.map +1 -1
  35. package/dist/standard-modules.d.ts +3 -12
  36. package/dist/standard-modules.d.ts.map +1 -1
  37. package/dist/standard-modules.js +13 -3045
  38. package/dist/standard-modules.js.map +1 -1
  39. package/dist/static-deployment.d.ts +1 -8
  40. package/dist/static-deployment.d.ts.map +1 -1
  41. package/dist/static-deployment.js +3 -28
  42. package/dist/static-deployment.js.map +1 -1
  43. package/dist/test-output.d.ts +1 -1
  44. package/dist/test-output.d.ts.map +1 -1
  45. package/dist/test-output.js.map +1 -1
  46. package/dist/version.d.ts +2 -2
  47. package/dist/version.d.ts.map +1 -1
  48. package/dist/version.js +2 -2
  49. package/dist/version.js.map +1 -1
  50. package/package.json +9 -11
  51. package/skill/ai-skill-desktop.md +84 -0
  52. package/skill/ai-skill-node.md +301 -0
  53. package/skill/ai-skill-web.md +150 -0
  54. package/skill/ai-skill.md +36 -263
  55. package/dist/build-engine-tool.d.ts +0 -3
  56. package/dist/build-engine-tool.d.ts.map +0 -1
  57. package/dist/build-engine-tool.js +0 -34
  58. package/dist/build-engine-tool.js.map +0 -1
  59. package/dist/packaged-official-tool.d.ts +0 -8
  60. package/dist/packaged-official-tool.d.ts.map +0 -1
  61. package/dist/packaged-official-tool.js +0 -32
  62. package/dist/packaged-official-tool.js.map +0 -1
  63. package/dist/project-task-bundle-entry.d.ts +0 -2
  64. package/dist/project-task-bundle-entry.d.ts.map +0 -1
  65. package/dist/project-task-bundle-entry.js +0 -18
  66. package/dist/project-task-bundle-entry.js.map +0 -1
  67. package/dist/project-task-invocation.d.ts +0 -16
  68. package/dist/project-task-invocation.d.ts.map +0 -1
  69. package/dist/project-task-invocation.js +0 -72
  70. package/dist/project-task-invocation.js.map +0 -1
  71. package/dist/project-task-tool.d.ts +0 -3
  72. package/dist/project-task-tool.d.ts.map +0 -1
  73. package/dist/project-task-tool.js +0 -61
  74. package/dist/project-task-tool.js.map +0 -1
@@ -0,0 +1,301 @@
1
+ # The VelarScript Node AI skill brief
2
+
3
+ Load this after `velar skill core`. This brief contains only the Node owner’s
4
+ contract. Core does not learn server declarations, path-pattern strings, Node
5
+ capabilities, or application configuration.
6
+
7
+ ## Ownership and application entry
8
+
9
+ A Node service activates the extension and names one exported `ServeApp`:
10
+
11
+ ```json
12
+ {
13
+ "formatVersion": 2,
14
+ "entry": "src/main.vel",
15
+ "outDir": "dist",
16
+ "publicDir": "public",
17
+ "extensions": ["@velarscript/node"],
18
+ "node": {
19
+ "app": "app",
20
+ "host": "127.0.0.1",
21
+ "port": 3000,
22
+ "maxBodyBytes": 16777216,
23
+ "build": {"sourceMaps": false}
24
+ }
25
+ }
26
+ ```
27
+
28
+ The entry exports application data; it does not need a manually named function
29
+ or top-level `serve(...)` call:
30
+
31
+ ```velar fragment
32
+ import {app as routes} from "./app.vel"
33
+
34
+ export const app = routes
35
+ ```
36
+
37
+ Use `velar dev` while editing, `velar serve` for checked production runtime
38
+ behavior, and `velar build` for a standalone Node output directory. A direct
39
+ `serve(app, port=0)` call is still correct in integration tests or an embedded
40
+ server.
41
+
42
+ `@name` keeps its one language-wide role: it qualifies a compiler-owned name
43
+ in the current context. In a `server` block, the available names are `@get`,
44
+ `@post`, `@put`, `@patch`, `@delete`, and `@notFound`. They are not decorators,
45
+ functions, imports, annotations, first-class values, or user extension points.
46
+
47
+ ## Routes and checked inputs
48
+
49
+ A server is an immutable anonymous route table:
50
+
51
+ ```velar
52
+ import {HttpError, created} from "velar/serve"
53
+
54
+ type CreateArticle:
55
+ title: string
56
+
57
+ export server articles:
58
+ /// Reports whether this service is ready.
59
+ @get(p"/health") => {ok: true}
60
+
61
+ @get(p"/articles/{id:number}", details: bool = false):
62
+ if id < 1:
63
+ throw HttpError(404, {error: "article_not_found"})
64
+ return {id, details}
65
+
66
+ @post(p"/articles", input: CreateArticle):
67
+ return created({id: 1, title: input.title})
68
+
69
+ ```
70
+
71
+ The path is written once. A capture such as `{id:number}` declares `id`
72
+ directly in the route body, so never repeat it in the argument list. Captures
73
+ require an ASCII half-width `:` and accept `string`, `number`, `bool`, or
74
+ a named enum. The Node-only `p"..."` prefix marks a compile-time reverse
75
+ matcher; an ordinary string is not accepted, and Core does not recognize this
76
+ prefix.
77
+
78
+ Unadorned scalar and `List<scalar>` parameters are query inputs. A default makes
79
+ the input optional. Repeated query values populate a List; a repeated scalar is
80
+ a 422 error. On `POST`, `PUT`, or `PATCH`, one concrete Data parameter is the
81
+ checked JSON body. A `Request` parameter explicitly requests the complete
82
+ request, including `queryAll` and cooperative `cancellation`. Ambiguous bodies,
83
+ duplicate declarations, conflicting path shapes, and unsupported path types are
84
+ compile errors.
85
+
86
+ `@notFound()` is the one application fallback for a path that matches no
87
+ route. It may omit its parameter or accept one explicitly typed `Request`.
88
+ Returning Data keeps status 404; return an explicit response such as
89
+ `json(value, status=410)` to choose another final status. A matched route's
90
+ `HttpError` and framework 405 responses do not enter this fallback. Declare at
91
+ most one on the final application; an app that owns `@notFound` cannot be moved
92
+ under a non-root `prefix`, because a global fallback has no unambiguous prefix
93
+ scope. Compose prefixed route tables first, then declare the fallback on the
94
+ outer `server`. A catch-all route such as `staticFiles("/", ...)` is a matched
95
+ route and therefore owns its own file fallback instead of entering
96
+ `@notFound`.
97
+
98
+ Use ordinary values for the cases that need more than inference:
99
+
100
+ ```velar
101
+ import {input, provide, security} from "velar/serve"
102
+
103
+ type User:
104
+ id: string
105
+
106
+ type UploadMetadata:
107
+ title: string
108
+
109
+ const currentUser = provide(
110
+ inputs={token: security.bearer()},
111
+ resolve=async values => {id: values.token},
112
+ )
113
+
114
+ server account:
115
+ @get(p"/me",
116
+ user=input.dependency(currentUser),
117
+ tenant=input.header("x-tenant"),
118
+ session=input.cookie("session", default=null),
119
+ ) => {id: user.id, tenant, session}
120
+
121
+ @post(p"/images",
122
+ metadata=input.form(UploadMetadata),
123
+ image=input.upload("image", maxBytes=8_388_608),
124
+ ) => {title: metadata.title, filename: image.filename}
125
+ ```
126
+
127
+ `input.query`, `input.header`, and `input.cookie` select named scalar
128
+ values. `input.form(Type)` checks URL-encoded or multipart fields, including
129
+ repeated fields for `List<scalar>` properties; duplicate scalar fields fail.
130
+ `input.upload` returns an `Upload` whose bytes are valid only for the request
131
+ lifetime; copy or persist them before retaining data. `security.apiKey`,
132
+ `basic`, `bearer`, `oauth2`, and `openId` parse credentials and also
133
+ feed OpenAPI security schemes.
134
+
135
+ `provide(inputs, resolve, scope="request", release=null, eager=false)` declares
136
+ a dependency as data. A request-scoped provider resolves once per request even
137
+ when injected repeatedly and releases after response/background completion.
138
+ An app-scoped provider may depend only on other app-scoped providers, may be
139
+ eager, and releases during shutdown. Cycles and provider-budget exhaustion fail
140
+ closed. Do not build a controller or container layer around it.
141
+
142
+ ## Composition, lifecycle, and middleware
143
+
144
+ Compose route tables as values:
145
+
146
+ ```velar fragment
147
+ import {Request, RouteDocumentation, docs, lifecycle, middleware, prefix, staticFiles, use} from "velar/serve"
148
+
149
+ const service = lifecycle(
150
+ prefix("/api", articles),
151
+ startup=async () => null,
152
+ shutdown=async () => null,
153
+ )
154
+
155
+ const hardened = use(service, [
156
+ middleware.trustedHosts(["api.example.com", "127.0.0.1"]),
157
+ middleware.cors(origins=["https://app.example.com"], credentials=true),
158
+ middleware.requestId(),
159
+ middleware.securityHeaders(),
160
+ middleware.compression(minimumBytes=1024),
161
+ middleware.timeout(10_000),
162
+ middleware.concurrency(256),
163
+ ])
164
+
165
+ const articleDocs: RouteDocumentation = {summary: "Read article", tags: ["articles"], errors: Map([[404, "Article not found"]])}
166
+ const routeDocs: Map<string, RouteDocumentation> = Map([["GET /api/articles/{id:number}", articleDocs]])
167
+
168
+ export server app:
169
+ ...docs(hardened, title="Article API", version="1.0.0", routes=routeDocs)
170
+ ...staticFiles("/assets", root="public")
171
+ @notFound(request: Request) => {error: "route_not_found", path: request.path}
172
+ ```
173
+
174
+ `prefix` changes a literal route prefix; `bodyLimit` narrows one route
175
+ table’s body budget; `use` attaches middleware only to the routes it receives.
176
+ A middleware continuation is single-use. Built-ins also include access logging
177
+ and explicit error recovery. A timeout response does not pretend downstream
178
+ work was cancelled: its request resources remain alive until that work really
179
+ ends, and the runtime caps unfinished timed-out tasks.
180
+
181
+ `lifecycle` owns paired startup and shutdown hooks. Successful startups unwind
182
+ in reverse order; a failed startup does not run its paired shutdown.
183
+ `background(response, task)` keeps request-scoped resources valid until the
184
+ task finishes. `setCookie` and
185
+ `clearCookie` add checked cookie headers, preserving separate `Set-Cookie`
186
+ fields. Never start long-lived work by
187
+ dropping a Promise; use an owned lifecycle, background task, Worker, or process.
188
+
189
+ `docs` adds a bundled offline UI and OpenAPI 3.1 JSON. Compiler route types
190
+ and response helpers supply parameter, body, response, content-type, and static
191
+ success-status schemas. Applicable framework-generated 400, 401, 413, 415, and
192
+ 422 responses are included automatically; a preceding `///` comment supplies
193
+ the route description. The optional ordinary typed
194
+ `Map<string, RouteDocumentation>` can add
195
+ summary, description, tags, success status, documented error statuses, or hide
196
+ a route, keyed by strings such as `"GET /articles/{id:number}"`. This metadata
197
+ is data, not another `@` category.
198
+
199
+ ## Responses and realtime
200
+
201
+ Ordinary Data returns JSON. Use the explicit helpers only when transport
202
+ semantics matter: `json`, `created`, `noContent`, `redirect`, `text`,
203
+ `file`, `stream`, `sse`, `background`, `setCookie`, and
204
+ `clearCookie`. `HttpError(status, body, headers=null)` is the expected HTTP
205
+ failure. Unexpected failures are reported on stderr and become an opaque 500.
206
+
207
+ `HEAD` reuses `GET` without a body. `OPTIONS` and 405 responses publish a
208
+ complete `Allow` header. Final response statuses are 200 through 599; 204 and
209
+ 304 are bodyless. Streaming follows write backpressure; each chunk and the
210
+ total stream are bounded. SSE accepts text or checked
211
+ `{data, event?, id?, retry?}` events. Static and returned files are canonical
212
+ root-contained, streamed reads with validators and one byte range.
213
+
214
+ `velar/websocket.listen({http: app, ...})` serves a `ServeApp` and WebSocket
215
+ upgrades on one native server and owns the application lifecycle. Connections
216
+ are pull-based. Always consume `next()`, handle backpressure, and stop the
217
+ server.
218
+
219
+ ## Tests
220
+
221
+ Use `velar/server-test` only from `*.test.vel`. It runs the real ServeApp
222
+ router, providers, lifecycle, cookies, forms, uploads, streams, and files in
223
+ process without opening a port:
224
+
225
+ ```velar fragment
226
+ import {client} from "velar/server-test"
227
+ import {expect} from "velar/test"
228
+ import {app} from "./app.vel"
229
+
230
+ test "health endpoint":
231
+ const api = await client(app)
232
+ try:
233
+ const response = await api.get("/api/health")
234
+ expect(response.status).toBe(200)
235
+ expect(await response.text()).toContain("ok")
236
+ finally:
237
+ await api.close()
238
+ ```
239
+
240
+ Pass a `Map<Provider, value>` as the second `client` argument to override
241
+ dependencies. Request options support headers, JSON, text, form Maps, and file
242
+ Maps. Test WebSocket behavior through a real local `velar/websocket` server,
243
+ because WebSocket upgrades are a transport boundary rather than an in-process
244
+ HTTP request.
245
+
246
+ ## Memory and ownership rules
247
+
248
+ The runtime has hard ceilings; application code must preserve them:
249
+
250
+ - Request bodies are at most 16 MiB, with narrower per-route and project limits.
251
+ HTTP request bodies, buffered responses, static files, and stream chunks also
252
+ share one 128 MiB isolated-host budget.
253
+ - Live inbound HTTP requests and middleware concurrency are capped at 4,096.
254
+ ServeApp routes, request providers, app providers, and timed-out unfinished
255
+ work have separate count limits.
256
+ - WebSocket queued bytes and pending-send bytes share a 128 MiB budget. Global
257
+ limits also cover active connections, pending connection objects, queued
258
+ message objects, and pending send Promises, including zero-byte messages.
259
+ - Multipart parsing reuses bounded body storage; an `Upload` is invalidated
260
+ when its request scope ends. Provider caches and release lists are explicitly
261
+ cleared at request or application shutdown.
262
+ - Development rebuilds serialize changes, retain one last-good child, stop the
263
+ old child before replacing it, and delete temporary build sandboxes.
264
+
265
+ Set smaller limits for the domain instead of treating framework maxima as
266
+ defaults. Stream large data, consume pull queues promptly, close every owned
267
+ capability, and keep caches explicitly bounded.
268
+
269
+ ## Concurrency and shutdown rules
270
+
271
+ Concurrency limits are admission control, not a lock around application data.
272
+ The runtime guarantees that an application-scoped provider initializes once,
273
+ concurrent `stop` or `close` calls join the same completion, shutdown refuses
274
+ new work, requests receive cooperative cancellation, and provider release begins
275
+ only after every admitted request has finished its response, timed-out
276
+ continuation, background work, and request cleanup. `stop(grace=30000)` bounds
277
+ the drain wait without releasing live request resources early. WebSocket stop
278
+ closes connections in parallel with a bounded handshake and releases unread
279
+ queues and pending-send reservations.
280
+
281
+ Application code still owns business-level consistency. Do not use an
282
+ unprotected module-level mutable record as a cross-request database. Put
283
+ multi-write invariants in a database transaction or another capability that
284
+ provides atomic operations. Always await stream writes, allow only one active
285
+ pull from an async iterator, and make retryable handlers idempotent. A
286
+ `middleware.concurrency` limit protects capacity; it does not make a shared
287
+ read-modify-write sequence atomic.
288
+
289
+ ## Node capabilities and finish
290
+
291
+ Use `velar/fs`, `velar/path`, `velar/process`, `velar/env`,
292
+ `velar/terminal`, `velar/http`, `velar/worker`, and `velar/websocket` instead of
293
+ ambient Node globals. Databases are ordinary external source packages: use the
294
+ engine-neutral `@velarscript/database` model contract and install an adapter
295
+ such as `@velarscript/sqlite`. Third-party packages cross a checked `extern
296
+ module` adapter first; keep `import js unsafe` at one narrow validation
297
+ boundary.
298
+
299
+ Run `velar format --check`, `velar check`, `velar test`, and
300
+ `velar build`. The complete runnable spelling lives in
301
+ `examples/tour/node/`; current diagnostics outrank this brief.
@@ -0,0 +1,150 @@
1
+ # The VelarScript Web AI skill brief
2
+
3
+ Load this after `velar skill core`. This file contains only the Web extension's
4
+ contract; Core syntax stays owned by the Core brief. It ships with the
5
+ toolchain and `velar skill web` prints it verbatim.
6
+
7
+ ## Ownership
8
+
9
+ The manifest activates Web explicitly:
10
+
11
+ ```json
12
+ {
13
+ "formatVersion": 2,
14
+ "entry": "src/main.vel",
15
+ "extensions": ["@velarscript/web"],
16
+ "web": {"title": "My App"}
17
+ }
18
+ ```
19
+
20
+ `@velarscript/web` owns `component`, JSX, `state`, `computed`, `resource`,
21
+ `action`, `watch`, `look`, `keyframes`, `mount`, Web units, its standard
22
+ modules, and the `web` manifest key. Without that extension these are not Core
23
+ syntax. Web visual builders are named imports from `velar/look`; there is no
24
+ `Look.` namespace.
25
+
26
+ `@name` keeps the same language-wide role: it qualifies a compiler-owned name
27
+ in the current context. Components own `@mounted:` and `@cleanup:`; Look owns
28
+ conditions such as `@hover` and `@before`. They are not decorators, calls, or
29
+ values, and user code cannot declare new `@` names.
30
+
31
+ The toolchain writes `dist/index.html`; do not author it. `web.title` and
32
+ `web.icon` supply document metadata, `public/` is copied through, and other
33
+ assets are content-hashed.
34
+
35
+ ## Components and reactivity
36
+
37
+ A component returns JSX directly. The four reactive cells have distinct jobs:
38
+
39
+ - `state` owns a fact.
40
+ - `computed name = ...` derives synchronously and is read bare.
41
+ - `resource name: T = load()` owns async loading state.
42
+ - `action name():` owns a user operation and exposes `pending` and `error`.
43
+
44
+ ```velar fragment
45
+ component TicketPanel(id: string):
46
+ state draft = ""
47
+ resource ticket: Ticket = loadTicket(id)
48
+ computed heading = ticket.value?.title ?? "Loading"
49
+
50
+ action save():
51
+ await saveDraft(id, draft)
52
+
53
+ watch id:
54
+ async ticket.reload()
55
+
56
+ return <section>
57
+ <h2>{heading}</h2>
58
+ <textarea bind:value={draft}></textarea>
59
+ <button disabled={save.pending} on:click={save}>Save</button>
60
+ </section>
61
+ ```
62
+
63
+ A resource loads once at mount. Refetching after an input changes is an
64
+ explicit `watch` plus detached `async resource.reload()`. Actions do not queue;
65
+ disable or otherwise guard a trigger when concurrent calls are unwanted.
66
+
67
+ `@mounted:` runs after insertion and may await. `@cleanup:` runs before removal
68
+ and is synchronous. A component may still declare ordinary methods named
69
+ `mounted` or `cleanup` because compiler-owned names occupy a separate namespace.
70
+
71
+ Events use `on:click={handler}`. Writable form paths use `bind:value`,
72
+ `bind:checked`, or `bind:group`; do not read `event.target`. A JSX tag body is
73
+ received only through an explicitly declared `children: WebNode` prop.
74
+ Conditional rendering is an expression, and repeated children need stable
75
+ `key` values.
76
+
77
+ Props are live reactive inputs. Their data is mutable unless the author writes
78
+ an explicit `readonly` view.
79
+
80
+ ## Look
81
+
82
+ `look:` is checked visual data. CSS keywords are strings, property names use
83
+ DOM camelCase, and units are literals:
84
+
85
+ ```velar fragment
86
+ import {border, rgb, spacing} from "velar/look"
87
+
88
+ const buttonLook = look:
89
+ border = border(0px, rgb(220, 224, 235))
90
+ borderRadius = 10px
91
+ padding = spacing(10px, 14px)
92
+ cursor = "pointer"
93
+
94
+ if @hover:
95
+ background = rgb(235, 240, 255)
96
+ ```
97
+
98
+ A module-level Look literal is built once and cannot read reactive state. Put a
99
+ changing visual on the element with `look={active ? enabledLook : disabledLook}`
100
+ or a typed `look:color={...}` binding. Checked motion is a module-level
101
+ `keyframes:` value passed to `animate` from `velar/look`; do not use a raw CSS
102
+ animation string. Unsupported styling uses explicit `import css unsafe
103
+ "./file.css" before look` or `after look`.
104
+
105
+ ## Storage and tests
106
+
107
+ `velar/storage` stores JSON and validates on read. A generic type spelling is
108
+ not a runtime value, so name the complete type:
109
+
110
+ ```velar fragment
111
+ import {storage} from "velar/storage"
112
+
113
+ type SavedItem:
114
+ title: string
115
+
116
+ type SavedItems = List<SavedItem>
117
+
118
+ const items = storage.get("reading", SavedItems, [])
119
+ storage.set("reading", items)
120
+ ```
121
+
122
+ Keep `src/main.vel` as the mounted entry and put testable components and logic
123
+ in imported modules. Plain `*.test.vel` files run headlessly. A
124
+ `*.browser.test.vel` file drives the already-built page through
125
+ `velar/web-test`; it does not mount a second app and cannot use JSX or
126
+ `document` in its test body:
127
+
128
+ ```velar fragment
129
+ import {expect} from "velar/test"
130
+ import {browser, localStorage} from "velar/web-test"
131
+
132
+ test "adding a link shows it in the list":
133
+ await browser.open("/")
134
+ await browser.fill("#title", "Vel")
135
+ await browser.click("#add")
136
+ await browser.waitForText("[data-item]", "Vel")
137
+ expect(await browser.text("[data-count]")).toBe("1")
138
+ expect(await localStorage.get("reading")).toBe(`[{"title":"Vel"}]`)
139
+ ```
140
+
141
+ Bare `velar test --browser` means Chromium; use `--browser=all` for a
142
+ cross-browser claim. `velar/web-test` is legal only in browser-test modules.
143
+ Application code that needs the page uses checked `velar/browser` APIs.
144
+
145
+ ## Finish
146
+
147
+ Run `velar format`, `velar check`, `velar test`, the project's browser tests,
148
+ and `velar build`. The complete runnable vocabulary lives in
149
+ `examples/tour/web/`; diagnostics outrank this brief when the two appear to
150
+ disagree.