@weft-js/cli 0.1.2 → 0.1.4
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 +516 -60
- package/package.json +4 -4
- package/src/load-config/schema.mjs +1 -0
- package/src/mcp.mjs +1 -1
package/README.md
CHANGED
|
@@ -1,67 +1,419 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/Ravonus/weft">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/Ravonus/weft/main/site/public/logo.svg" width="88" height="88" alt="Weft">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
|
-
>
|
|
7
|
+
<h1 align="center">@weft-js/cli</h1>
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
<strong>The <code>weft</code> command: run, check, build, audit and deploy a Weft app.</strong><br>
|
|
11
|
+
Every finding has a code, a reason and a fix, as text for you and as JSON or MCP tools for an agent.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://www.npmjs.com/package/@weft-js/cli"><img src="https://img.shields.io/npm/v/@weft-js/cli?color=145c3c&label=npm" alt="npm version"></a>
|
|
16
|
+
<a href="https://github.com/Ravonus/weft/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-145c3c" alt="MIT license"></a>
|
|
17
|
+
<a href="https://github.com/Ravonus/weft/actions"><img src="https://img.shields.io/github/actions/workflow/status/Ravonus/weft/quality.yml?branch=main&label=checks" alt="checks"></a>
|
|
18
|
+
<img src="https://img.shields.io/badge/node-%3E%3D24-145c3c" alt="Node 24 or later">
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<a href="#quick-start">Quick start</a> ·
|
|
23
|
+
<a href="https://github.com/Ravonus/weft/tree/main/packages/cli/docs">Docs</a> ·
|
|
24
|
+
<a href="https://github.com/Ravonus/weft/tree/main/examples">Examples</a> ·
|
|
25
|
+
<a href="https://github.com/Ravonus/weft/blob/main/CHANGELOG.md">Changelog</a> ·
|
|
26
|
+
<a href="https://github.com/Ravonus/weft">GitHub</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
> [!IMPORTANT]
|
|
30
|
+
> **Early release (0.1.x).** The command works end to end, and commands, flags and output can still change between
|
|
31
|
+
> minor versions.
|
|
32
|
+
|
|
33
|
+
`weft` is the one command a Weft app needs. It runs the app (`dev`, `build`, `start`), checks it (`check`, `tsc`, `fix`,
|
|
34
|
+
`audit`, `test --gate`), ships it (`deploy`), serves its docs to people and agents (`docs`, `agents-md`, `map`, `mcp`)
|
|
35
|
+
and manages plugins (`add`, `plugins`). An app made with
|
|
36
|
+
[`npm create @weft-js`](https://github.com/Ravonus/weft/tree/main/packages/create) already has it.
|
|
37
|
+
|
|
38
|
+
It is built for two readers. A person gets short lines on stderr, and a tool gets the same result as JSON on stdout
|
|
39
|
+
with `--json`, or as MCP tools through `weft mcp`.
|
|
40
|
+
|
|
41
|
+
## Highlights
|
|
42
|
+
|
|
43
|
+
- **Diagnostics with fixes.** `weft check` compiles every component in check mode. Each problem prints as
|
|
44
|
+
`file:line:col CODE severity why`, with a `fix:` line under it, and `weft fix` applies the safe ones.
|
|
45
|
+
- **Docs that match the install.** `weft docs W014` prints the page for a code, with whether the installed Weft reports
|
|
46
|
+
it. `weft agents-md` writes an `AGENTS.md` for the version you have.
|
|
47
|
+
- **A build that audits itself.** `weft build` opens the built pages in a clean Chrome at a phone's and a desktop's
|
|
48
|
+
width, runs axe-core's WCAG rules, and fails on an error.
|
|
49
|
+
- **The running app, driven from the terminal.** `weft browser snapshot`, `act` and `assert` work against any browser
|
|
50
|
+
connected to the dev server, and `record` turns a session into a test.
|
|
51
|
+
- **A test gate on the diff.** `weft test --gate` checks that new tests fail on the old code, kill mutants of the changed
|
|
52
|
+
lines, and that no existing test got weaker.
|
|
53
|
+
- **Deploys that say why not.** `weft deploy hosts` says which hosts can run this app before you have an account, and
|
|
54
|
+
`weft deploy` is a dry run until you pass `--yes`.
|
|
55
|
+
- **An MCP server.** `weft mcp` serves `docs`, `check`, `audit`, the style tools, the test gate and the `browser_*`
|
|
56
|
+
tools on stdio.
|
|
57
|
+
|
|
58
|
+
## Contents
|
|
59
|
+
|
|
60
|
+
- [Install](#install)
|
|
61
|
+
- [Quick start](#quick-start)
|
|
62
|
+
- [Global flags, output and exit codes](#global-flags-output-and-exit-codes)
|
|
63
|
+
- [Commands](#commands)
|
|
64
|
+
- [Run the app](#run-the-app): `dev`, `build`, `start`
|
|
65
|
+
- [Check it](#check-it): `check`, `tsc`, `fix`, `doctor`, `audit`, `routes`, `surfaces`
|
|
66
|
+
- [Test and verify](#test-and-verify): `test --gate`, `browser`
|
|
67
|
+
- [Deploy](#deploy): `deploy`, `deploy hosts`, `deploy init`
|
|
68
|
+
- [Data](#data): `db generate`, `db live`, `db listen`
|
|
69
|
+
- [Add things](#add-things): `add`, `plugins`
|
|
70
|
+
- [Docs for people and agents](#docs-for-people-and-agents): `docs`, `agents-md`, `map`, `mcp`, `tasks`, `run`
|
|
71
|
+
- [Style and design](#style-and-design): `style`, `tokens`, `icons`
|
|
72
|
+
- [Editors](#editors): `lsp`
|
|
73
|
+
- [The diagnostic shape](#the-diagnostic-shape)
|
|
74
|
+
- [Diagnostic families](#diagnostic-families)
|
|
75
|
+
- [The package API](#the-package-api)
|
|
76
|
+
- [Troubleshooting](#troubleshooting)
|
|
77
|
+
- [Related packages](#related-packages)
|
|
78
|
+
|
|
79
|
+
## Install
|
|
80
|
+
|
|
81
|
+
A new app already lists it in `devDependencies`. To add it to an existing one:
|
|
8
82
|
|
|
9
83
|
```bash
|
|
10
84
|
npm install -D @weft-js/cli
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pnpm add -D @weft-js/cli
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bun add -d @weft-js/cli
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
deno add -D npm:@weft-js/cli
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
It needs Node 24 or later, or Bun or Deno in its place. `@weft-js/core` is a peer dependency: the CLI uses the project's
|
|
100
|
+
own compiler, and falls back to its own copy only when the project has none.
|
|
101
|
+
|
|
102
|
+
## Quick start
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Compile every component, report diagnostics with fixes
|
|
11
106
|
npx weft check
|
|
107
|
+
npx weft dev # the dev server, for an app with src/routes
|
|
108
|
+
# The production build into .output/, then the audit
|
|
109
|
+
npx weft build
|
|
110
|
+
npx weft start # run the build
|
|
12
111
|
```
|
|
13
112
|
|
|
14
|
-
|
|
15
|
-
|
|
113
|
+
When `check` finds something, it looks like this:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
src/routes/counter.tsx:8:8 W015 error
|
|
117
|
+
`count` is a box; JSX needs its value.
|
|
118
|
+
fix: Read `count.value`. (autofix)
|
|
119
|
+
weft check: 12 files, 1 errors, 0 warnings (84 ms)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Then:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npx weft docs W015 # the page for that code
|
|
126
|
+
npx weft fix # apply the safe autofixes
|
|
127
|
+
npx weft check --json # the same result, for a tool
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`npx weft help` prints the full command list.
|
|
131
|
+
|
|
132
|
+
## Global flags, output and exit codes
|
|
133
|
+
|
|
134
|
+
Every command takes these:
|
|
135
|
+
|
|
136
|
+
| Flag | Default | What it does |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `--root <dir>` (or `--root=<dir>`) | the working directory | The app to work on |
|
|
139
|
+
| `--json` | off | Print the result as JSON on stdout. Text for people still goes to stderr |
|
|
140
|
+
| `--check` | off | Used by `agents-md`: report, don't write |
|
|
141
|
+
| `--stdout` | off | Used by `agents-md`, `map` and `style matrix`: print instead of writing a file |
|
|
142
|
+
|
|
143
|
+
A flag that takes a value accepts `--flag value` or `--flag=value`. An unknown flag is a usage error.
|
|
144
|
+
|
|
145
|
+
| Exit code | Meaning |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `0` | OK |
|
|
148
|
+
| `1` | Errors found: diagnostics with `error` severity, a build refused on one, a failed assertion, or a stale `AGENTS.md` under `--check` |
|
|
149
|
+
| `2` | A usage error or an internal error. With `--json`, stdout gets `{ "ok": false, "error": { "code", "message" } }` |
|
|
16
150
|
|
|
17
151
|
## Commands
|
|
18
152
|
|
|
19
|
-
|
|
153
|
+
### Run the app
|
|
154
|
+
|
|
155
|
+
| Command | Flags | What it does |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `weft dev` | `--port <n>` | The dev server for an app with `src/routes` (Vite and Nitro). Loads `.env` under what's already set, writes `.weft/map.md`, and starts any Rust `remote()` sidecars before the server |
|
|
158
|
+
| `weft build` | `--runtime node\|bun\|deno`, `--preset <p>`, `--unsafe-allow <codes>` | The production build, into `.output/`, plus `.weft/contract.json`. Then the built pages are audited (L-codes), and an error fails the build |
|
|
159
|
+
| `weft start` | `--runtime <r>` | Runs `.output/server/index.mjs` on its runtime: `--runtime`, else the config's `runtime`, else the one running `weft`. Starts sidecars first |
|
|
160
|
+
|
|
161
|
+
`--runtime` picks Node, Bun or Deno. `--preset` picks a host preset instead, such as `netlify`, `vercel` or
|
|
162
|
+
`cloudflare_durable`; with `deploy.target` in the config, `weft build` builds for that host.
|
|
163
|
+
|
|
164
|
+
`--unsafe-allow` lets a build go past codes you have looked at: a code (`R002`), a family (`L`), several
|
|
165
|
+
(`L003,R002`) or `all`. Each one it lets through is listed as a warning, every build. To keep that in the config with a
|
|
166
|
+
reason, use `build.unsafeAllow`:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
// weft.config.ts
|
|
170
|
+
export default defineConfig({
|
|
171
|
+
build: {
|
|
172
|
+
unsafeAllow: { L003: 'the legacy page is replaced next sprint' },
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
A build that fails still writes its output, and says so: fix the errors, or force it with `--unsafe-allow <code>`.
|
|
178
|
+
|
|
179
|
+
### Check it
|
|
180
|
+
|
|
181
|
+
| Command | Flags | What it does |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `weft check [files…]` | `--preset <p>`, `--verbose` | Compiles every component in check mode and reports W-, P-, D- and the other codes, with fixes. Files limit it to those. `--verbose` says which compiler ran (native addon or WASM). Ends with `files, errors, warnings (ms)` |
|
|
184
|
+
| `weft tsc` | | Type-checks the whole project with inferred props (tsc or tsgo). For CI |
|
|
185
|
+
| `weft fix [files…]` | | Applies the safe autofixes and lists each one as `file:line:col CODE` |
|
|
186
|
+
| `weft doctor` | `--preset <p>`, `--runtime <r>` | Which compiler this install uses, whether Rust is around (it's optional), and which hosts fit. For an app with `src/realtime.server.ts`, or with `--preset`, also what live data does on that target, what it requires and the options |
|
|
187
|
+
| `weft audit [routes…]` | `--url <u>`, `--indexing public\|private\|auto`, `--all`, `--max <n>` | The built pages, or a running site with `--url`, in a clean Chrome at a phone's and a desktop's width: axe-core's WCAG rules, console errors, deprecations, the head, sideways scroll and layout shift |
|
|
188
|
+
| `weft routes` | `--meta`, `--preset <p>` | The route table, path and file. `--meta` adds each route's merged metadata, tags, card mode and H-diagnostics |
|
|
189
|
+
| `weft surfaces` | | The canvas and WebGL surfaces this project already defines, with their kind, file and props |
|
|
190
|
+
|
|
191
|
+
`weft audit` samples up to 30 pages unless you pass `--all` or `--max <n>`. Without Chrome it skips, with an `L000`
|
|
192
|
+
warning. `--indexing public` makes a `noindex` an error (L024), for a site meant for search. Run it again with `--url`
|
|
193
|
+
after a deploy: a host or proxy can add a header a local build can't see.
|
|
194
|
+
|
|
195
|
+
### Test and verify
|
|
196
|
+
|
|
197
|
+
#### `weft test --gate`
|
|
198
|
+
|
|
199
|
+
The test gate runs on the diff, in scratch copies. Your working tree is never touched.
|
|
200
|
+
|
|
201
|
+
| Flag | Default | What it does |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `--gate` | required | Run the gate. `weft test` without it is a usage error: run the suite itself with vitest |
|
|
204
|
+
| `--base <ref>` | `HEAD` (the uncommitted change) | What the diff is against |
|
|
205
|
+
| `--budget <sec>` | `60`, or `test.gate.mutationBudgetSec` | Time for mutants |
|
|
206
|
+
| `--max-mutants <n>` | `40`, or `test.gate.maxMutants` | Mutants sampled |
|
|
207
|
+
| `--concurrency <n>` | up to 4, from the CPU count | Parallel runs |
|
|
208
|
+
| `--refactor` | off | Promise no behavior change: then no test may change |
|
|
209
|
+
| `--no-mutation` | off | Skip the mutants |
|
|
210
|
+
|
|
211
|
+
It reports **T010** (a new or changed test must fail on the code before the change), **T011** (each new test must kill
|
|
212
|
+
at least one mutant of the changed lines) and **T020** (deleting, skipping or loosening a test needs
|
|
213
|
+
`// weft-allow T020: <reason>`). `weft docs verify` has the details.
|
|
214
|
+
|
|
215
|
+
#### `weft browser <cmd>`
|
|
216
|
+
|
|
217
|
+
Drives the running app. The page is the app open in any browser connected to the dev server: yours, an agent's, or one
|
|
218
|
+
`launch` starts. In a browser that runs JS, the same commands are `await __weft__.agent.run('<command>', args)`.
|
|
219
|
+
|
|
220
|
+
Every `browser` command takes `--url <dev server>`, `--tab <id>` and `--json`.
|
|
221
|
+
|
|
222
|
+
| Command | Flags and arguments | What it does |
|
|
223
|
+
|---|---|---|
|
|
224
|
+
| `tabs` | | Tabs connected to the dev server |
|
|
225
|
+
| `launch [route]` | `--headed` | Starts a headless Chrome on the app, for when you have no browser |
|
|
226
|
+
| `open <route>` | | Navigates the tab and waits for the new page |
|
|
227
|
+
| `snapshot` | `--interactive`, `--delta`, `--scope role:name\|@ref`, `--graph-only`, `--no-graph`, `--full` | Roles, names and refs, plus the reactive graph (`Cart.total = 42.5 ← …`). Long output spills to a file unless `--full` |
|
|
228
|
+
| `act <target> <action> [value]` | | `click`, `dblclick`, `hover`, `focus`, `clear`, `fill`, `type`, `press`, `select`, `check`, `uncheck` (default `click`) |
|
|
229
|
+
| `assert <target> <expectation> [value]` | `--timeout <ms>` | `visible` (default), `absent`, `text`, `exactText`, `value`, `checked`, `unchecked`, `disabled`, `enabled`, `focused`, `count`. Retries until the timeout. Exits 1 on a failure |
|
|
230
|
+
| `graph [filter]` | `--full` | The named reactive graph |
|
|
231
|
+
| `set <Name.box> <json>` | | Writes state by its graph name (dev only) |
|
|
232
|
+
| `time pause\|advance <ms>\|resume\|status` | `--reload` | The page's clock |
|
|
233
|
+
| `net offline\|online\|latency <ms>\|drop\|reset\|status` | | The page's network |
|
|
234
|
+
| `record start\|stop\|note <text>\|code` | `--component`, `--from`, `--props '{…}'`, `--name`, `--out file.test.tsx` | Records actions and assertions; `code` writes them as a test |
|
|
235
|
+
| `logs` | | Console errors and warnings, and uncaught errors, since the last call |
|
|
236
|
+
| `overlay [on\|off]` | | The graph panel in the page (Alt+Shift+G) |
|
|
237
|
+
| `info` | | What the tab is showing, starting with its URL |
|
|
238
|
+
| `reload` | | Reloads the tab |
|
|
239
|
+
| `screenshot` | `--out file.png` | Launched Chrome only; use your own browser's screenshot otherwise |
|
|
240
|
+
| `close` | | Stops the launched Chrome |
|
|
241
|
+
|
|
242
|
+
A target is `<role> <name>` (`button "Add Banana"`), `label <text>`, `text <text>`, or a ref from a snapshot (`@e5`).
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
npx weft browser launch /cart
|
|
246
|
+
npx weft browser act button "Add Banana" click
|
|
247
|
+
npx weft browser assert text Cart text "1 item"
|
|
248
|
+
npx weft browser record code --component Cart \
|
|
249
|
+
--from ./Cart --out src/Cart.test.tsx
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Deploy
|
|
253
|
+
|
|
254
|
+
| Command | Flags | What it does |
|
|
255
|
+
|---|---|---|
|
|
256
|
+
| `weft deploy hosts` | | Which hosts can run this app, why not, what each costs, and the one Weft suggests |
|
|
257
|
+
| `weft deploy init [target]` | `--target <t>`, `--dry-run`, `--force` | Writes the host's files (`netlify.toml`, `fly.toml` and a Dockerfile…), a GitHub workflow that checks and deploys on push, and `deploy` in the config. Then prints the one-time commands to run yourself |
|
|
258
|
+
| `weft deploy` | `--target <t>`, `--prod`, `--yes`, `--unsafe-allow <codes>` | Checks the fit, builds for the target, then runs the host's own CLI and prints the live URL. Without `--yes` it's a dry run that prints what would run and which environment variables it reads. Without `--prod` it's a preview |
|
|
259
|
+
|
|
260
|
+
| Target | Kind | Reads from the environment |
|
|
261
|
+
|---|---|---|
|
|
262
|
+
| `netlify` | functions | `NETLIFY_AUTH_TOKEN`, `NETLIFY_SITE_ID` |
|
|
263
|
+
| `vercel` | functions | `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID` |
|
|
264
|
+
| `cloudflare` | Workers, with Durable Objects | `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID` |
|
|
265
|
+
| `fly` | a server that stays up | `FLY_API_TOKEN` |
|
|
266
|
+
| `render` | a server that stays up | `RENDER_DEPLOY_HOOK_URL` |
|
|
267
|
+
|
|
268
|
+
`weft deploy hosts` also rates AWS Lambda, which `weft deploy` doesn't ship to yet. Nothing in Weft creates a site, an
|
|
269
|
+
app, a volume or a DNS record, and a token written into the config, a host file or a workflow is **E008**.
|
|
270
|
+
`weft docs deploy` covers which app features each host can run (E001–E003), `deploy` in the config, and the CDN.
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
npx weft deploy hosts # fit, cost and the suggestion
|
|
274
|
+
npx weft deploy init fly # host files and the GitHub workflow
|
|
275
|
+
npx weft deploy # dry run: what --yes would run
|
|
276
|
+
npx weft deploy --yes --prod # ship it
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Data
|
|
20
280
|
|
|
21
281
|
| Command | What it does |
|
|
22
282
|
|---|---|
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
| `icons
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
|
|
|
47
|
-
|
|
48
|
-
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
283
|
+
| `weft db generate [name]` | A migration for the schema's changes, through the app's data layer (Drizzle, Prisma or native SQL). It applies on the next request |
|
|
284
|
+
| `weft db live` | A migration that adds change triggers to the tables in `changes` (`src/realtime.server.ts`), on Postgres, SQLite or MySQL. On Prisma or native SQL it prints the SQL for you to add |
|
|
285
|
+
| `weft db listen` | The change feed as its own process, for an app on functions |
|
|
286
|
+
|
|
287
|
+
An app with no database gets a usage error that points at `weft add db`.
|
|
288
|
+
|
|
289
|
+
### Add things
|
|
290
|
+
|
|
291
|
+
#### `weft add <feature>`
|
|
292
|
+
|
|
293
|
+
Installs a package with the app's package manager (found from its lockfile: pnpm, bun, yarn, deno or npm) and wires it
|
|
294
|
+
into the config, whichever format it's in.
|
|
295
|
+
|
|
296
|
+
| Feature | What it does |
|
|
297
|
+
|---|---|
|
|
298
|
+
| `db [engine]` | A database on an app that has none: `sqlite` (default), `postgres` or `mysql`, with `--layer drizzle\|prisma\|native` (default `drizzle`). Writes the same wiring a new app gets, without the todo app. Refuses if the app has a database, or if a file it writes exists |
|
|
299
|
+
| `auth` | Better Auth on an app with a database: `src/auth.server.ts`, `src/server/session.ts`, a sign-in page and the auth tables. Refuses without a database or with an existing `src/auth.server.ts` |
|
|
300
|
+
| `tailwind` | Tailwind: the Vite plugin, a Tailwind entry in `src/app.css` (without its reset when Warp is there), and the layout's import of it |
|
|
301
|
+
| `rust [name]` | A Rust crate, its server module and one working function. `native()` by default (in process); `--remote` for a sidecar behind HTTP |
|
|
302
|
+
| `warp`, `icons`, `text` | `@weft-js/warp`, [`@weft-js/warp-icons`](https://www.npmjs.com/package/@weft-js/warp-icons), [`@weft-js/text`](https://www.npmjs.com/package/@weft-js/text) |
|
|
303
|
+
| `media`, `media-ffmpeg`, `surface-keel` | [`@weft-js/plugin-media`](https://www.npmjs.com/package/@weft-js/plugin-media), [`@weft-js/plugin-media-ffmpeg`](https://www.npmjs.com/package/@weft-js/plugin-media-ffmpeg), [`@weft-js/plugin-surface-keel`](https://www.npmjs.com/package/@weft-js/plugin-surface-keel) |
|
|
304
|
+
| `redis`, `nats` | [`@weft-js/realtime-redis`](https://www.npmjs.com/package/@weft-js/realtime-redis), [`@weft-js/realtime-nats`](https://www.npmjs.com/package/@weft-js/realtime-nats) |
|
|
305
|
+
| `pay`, `pay-stripe` | [`@weft-js/pay`](https://www.npmjs.com/package/@weft-js/pay), `@weft-js/pay/stripe` |
|
|
306
|
+
| any other name | Another `@weft-js/<name>` add-on, or a package name as given |
|
|
307
|
+
|
|
308
|
+
| Flag | What it does |
|
|
309
|
+
|---|---|
|
|
310
|
+
| `--dry-run` | Print what it would install and write, and change nothing |
|
|
311
|
+
| `--no-install` | Wire it in without installing |
|
|
312
|
+
| `--layer drizzle\|prisma\|native` | For `add db` |
|
|
313
|
+
| `--remote` | For `add rust` |
|
|
314
|
+
|
|
315
|
+
Some add-ons (`pay`, `text`, the media plugins and the realtime transports) aren't released on npm yet.
|
|
316
|
+
|
|
317
|
+
#### `weft plugins`
|
|
318
|
+
|
|
319
|
+
| Command | Flags | What it does |
|
|
320
|
+
|---|---|---|
|
|
321
|
+
| `weft plugins` (or `plugins list`) | | Each plugin, its version, the slots it provides and whether they're bound, its tokens, and diagnostics |
|
|
322
|
+
| `weft plugins explain <slot>` | | The binding chain: config, plugin, module, `.weft/slots/<id>.ts` |
|
|
323
|
+
| `weft plugins sync` | | Regenerates `.weft/slots/*`, `.weft/slots.d.ts` and `.weft/tokens/*` |
|
|
324
|
+
| `weft plugins audit` | | Each plugin's permissions and code against `.weft/plugins.lock.json`, and what it uses that it didn't declare |
|
|
325
|
+
| `weft plugins approve [name…]` | `--all` | Records plugins in the lock. With no names and no `--all`, shows what's waiting and writes nothing |
|
|
326
|
+
|
|
327
|
+
`weft docs plugins` walks through writing one.
|
|
328
|
+
|
|
329
|
+
### Docs for people and agents
|
|
330
|
+
|
|
331
|
+
| Command | Flags | What it does |
|
|
332
|
+
|---|---|---|
|
|
333
|
+
| `weft docs [topic\|code]` | | Prints a docs page or a diagnostic (`weft docs props`, `weft docs W014`). With no topic, the index |
|
|
334
|
+
| `weft agents-md` | `--check`, `--stdout` | Writes `AGENTS.md` from the installed Weft. `--check` exits 1 when it's stale; `--stdout` prints it. Any run exits 1 when it's over the 9 KB limit |
|
|
335
|
+
| `weft map` | `--stdout` | Writes `.weft/map.md` and `.weft/map.json`: a matrix of what to call in this app |
|
|
336
|
+
| `weft mcp` | | An MCP server on stdio (below) |
|
|
337
|
+
| `weft tasks` | | The built-in commands and the project's tasks, with arguments, side effects and environments |
|
|
338
|
+
| `weft run <task>` | | Runs a project task from `tasks` in `weft.config.ts` |
|
|
339
|
+
|
|
340
|
+
`weft docs` topics:
|
|
341
|
+
|
|
342
|
+
| Topic | Covers |
|
|
343
|
+
|---|---|
|
|
344
|
+
| `rules` | The nine rules: boxes, derived, live JSX and props, run-once bodies. Start here |
|
|
345
|
+
| `state` | Every reactive function and `defineState` with persist, sync and history |
|
|
346
|
+
| `props` | How props stay live |
|
|
347
|
+
| `lists` | Keyed lists, conditionals and stable items |
|
|
348
|
+
| `async` | `resource`, `<Boundary>`, `@weft-js/core/ssr` and hydrate |
|
|
349
|
+
| `start` | The full stack: routes, `load`, `query`, `mutation`, the database, auth, realtime, runtimes |
|
|
350
|
+
| `rust` | Rust bodies: `native()` addons with a WASM fallback, `remote()` sidecars, `weft add rust` |
|
|
351
|
+
| `deploy` | Hosts, `weft deploy`, the push workflow, the CDN |
|
|
352
|
+
| `plugins` | Building a plugin: slots, server extensions, check hooks, docs, `weft add` |
|
|
353
|
+
| `theme` | `warp()` options, worked looks, button tone channels |
|
|
354
|
+
| `testing` | `@weft-js/core/test`: render, screen, user, flush, clock |
|
|
355
|
+
| `browser` | `@weft-js/core/browser`: online, visible, lifecycle, media, the fakes |
|
|
356
|
+
| `ui-state` | Hover, press and focus as state: `interaction()`, the `ui` prop |
|
|
357
|
+
| `surface` | `@weft-js/core/surface`: canvas and WebGL as layout children |
|
|
358
|
+
| `verify` | `weft browser`, `__weft__.agent` and the test gate |
|
|
359
|
+
| `icons` | `@weft-js/warp-icons`: per-icon exports, tiers, sizes |
|
|
360
|
+
| `fonts` | Fonts with `@weft-js/text` |
|
|
361
|
+
| `meta` | Page metadata and share cards, `weft routes --meta` |
|
|
362
|
+
| `config` | `weft.config.ts`: scope, tasks, environments, plugins |
|
|
363
|
+
| `design` | The design language: `Stack`, `Row`, `Heading`, `Text`, `Link`, `weft fix`, `weft tokens` |
|
|
364
|
+
| `style` | Style groups, `weft style find` and `explain` |
|
|
365
|
+
| `diagnostics` | Every code, and which ones the installed Weft reports |
|
|
366
|
+
| `commands` | This project's commands and tasks |
|
|
367
|
+
| `agents` | The generated `AGENTS.md` |
|
|
368
|
+
|
|
369
|
+
Installed plugins can add their own topics; `weft docs` with no topic lists them.
|
|
370
|
+
|
|
371
|
+
#### `weft mcp`
|
|
372
|
+
|
|
373
|
+
An MCP server on stdio, rooted at `--root`. Its tools:
|
|
374
|
+
|
|
375
|
+
| Tool | Same as |
|
|
376
|
+
|---|---|
|
|
377
|
+
| `docs` | `weft docs` |
|
|
378
|
+
| `check` | `weft check` |
|
|
379
|
+
| `audit` | `weft audit` |
|
|
380
|
+
| `routes_meta` | `weft routes --meta` |
|
|
381
|
+
| `map` | `weft map` |
|
|
382
|
+
| `tasks` | `weft tasks` |
|
|
383
|
+
| `surfaces` | `weft surfaces` |
|
|
384
|
+
| `style_find`, `style_explain` | `weft style find`, `weft style explain` |
|
|
385
|
+
| `test_gate` | `weft test --gate` |
|
|
386
|
+
| `browser_tabs`, `browser_launch`, `browser_open`, `browser_snapshot`, `browser_act`, `browser_assert`, `browser_state`, `browser_time`, `browser_net`, `browser_record`, `browser_logs`, `browser_screenshot` | `weft browser` |
|
|
387
|
+
|
|
388
|
+
To add it to an MCP client:
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"mcpServers": {
|
|
393
|
+
"weft": { "command": "npx", "args": ["weft", "mcp"] }
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Style and design
|
|
399
|
+
|
|
400
|
+
| Command | Flags | What it does |
|
|
401
|
+
|---|---|---|
|
|
402
|
+
| `weft style find <query>` | | Style groups that fit what you're about to style (`card`, `status badge`). Reuse before you write |
|
|
403
|
+
| `weft style explain <group\|selector>` | `--<axis> <value>`, `--states a,b`, `--accent intent:token`, `--part <p>` | The resolved CSS for one variation, and where each value came from. The group's own axes are flags (`--status late`) |
|
|
404
|
+
| `weft style matrix` | `--stdout` | Writes `.weft/styles.json`: every group, with axes, parts, accents, resolved CSS and uses |
|
|
405
|
+
| `weft tokens` | | Warp's resolved tokens as DTCG, in `.weft/tokens/` |
|
|
406
|
+
| `weft icons publish <dir>` | | Every icon and variant as static `.svg` files with a `manifest.json`, for a CDN. Nothing is uploaded: host the folder, then set `icons({ source })` |
|
|
407
|
+
|
|
408
|
+
### Editors
|
|
409
|
+
|
|
410
|
+
| Command | What it does |
|
|
411
|
+
|---|---|
|
|
412
|
+
| `weft lsp` | A language server for editors on TypeScript 7: `tsc --lsp` with inferred props |
|
|
413
|
+
|
|
414
|
+
A new app's `tsconfig.json` also loads `@weft-js/cli/ts-plugin`, which gives the editor the same inferred props.
|
|
415
|
+
|
|
416
|
+
## The diagnostic shape
|
|
65
417
|
|
|
66
418
|
`check`, `tasks` and the MCP tools report the same shape:
|
|
67
419
|
|
|
@@ -85,15 +437,119 @@ The source of each page is in [docs/](docs). Adding a diagnostic is in [CONTRIBU
|
|
|
85
437
|
}
|
|
86
438
|
```
|
|
87
439
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
440
|
+
| Field | What it is |
|
|
441
|
+
|---|---|
|
|
442
|
+
| `span` | 1-based `[line, col, endLine, endCol]`, with columns in UTF-16 units |
|
|
443
|
+
| `offset` | UTF-16 indices into the file's text |
|
|
444
|
+
| `fix.text` | The fix, in words |
|
|
445
|
+
| `fix.edits` | `{ file, span, offset, text }`, when there's a mechanical change |
|
|
446
|
+
| `fix.safe` | Whether `weft fix` applies it without asking |
|
|
447
|
+
| `project` | `true` for a result that needed more than one file to find |
|
|
448
|
+
| `related` | Other places that explain it |
|
|
449
|
+
| `docs` | The command that prints its page |
|
|
450
|
+
|
|
451
|
+
## Diagnostic families
|
|
452
|
+
|
|
453
|
+
`weft docs diagnostics` lists every code and whether the installed Weft reports it.
|
|
454
|
+
|
|
455
|
+
| Prefix | Area |
|
|
456
|
+
|---|---|
|
|
457
|
+
| `W` | Reactivity, from the compiler |
|
|
458
|
+
| `S` | State and `defineState` |
|
|
459
|
+
| `P` | Plugins and config |
|
|
460
|
+
| `D` | Design language and style groups |
|
|
461
|
+
| `H` | Page metadata and hydration |
|
|
462
|
+
| `Q`, `A`, `C`, `F`, `R` | Server functions and the database, auth, the contract, forms, realtime and Rust |
|
|
463
|
+
| `E` | Deploys |
|
|
464
|
+
| `L` | Built pages, from `weft build` and `weft audit` |
|
|
465
|
+
| `T` | Tests and the test gate |
|
|
466
|
+
| `U` | UI state |
|
|
467
|
+
| `X` | Surfaces and text |
|
|
468
|
+
| `M`, `I` | Media and icons |
|
|
469
|
+
|
|
470
|
+
A test that needs a T-code on purpose keeps it with `// weft-allow <code>: <why>`, in the file header or on the line
|
|
471
|
+
above. Adding a diagnostic is in [CONTRIBUTING.md](https://github.com/Ravonus/weft/blob/main/CONTRIBUTING.md).
|
|
472
|
+
|
|
473
|
+
## The package API
|
|
474
|
+
|
|
475
|
+
Most people only run the command. The package also exports what the command is built from:
|
|
476
|
+
|
|
477
|
+
| Import | Exports |
|
|
478
|
+
|---|---|
|
|
479
|
+
| `@weft-js/cli` | `check`, `docs`, `topics`, `agentsMd`, `writeAgentsMd`, `catalog`, `entry`, `probe`, `loadConfig`, `tasks`, `bindSlots`, `slotTable`, and the MCP server's `serve`, `handle` and `tools` |
|
|
480
|
+
| `@weft-js/cli/config` | `defineConfig`. Apps import it from `@weft-js/core/config`; this is the fallback when a project's Weft doesn't resolve |
|
|
481
|
+
|
|
482
|
+
```js
|
|
483
|
+
import { check } from '@weft-js/cli'
|
|
484
|
+
|
|
485
|
+
const result = await check(process.cwd(), {
|
|
486
|
+
files: ['src/routes/index.tsx'],
|
|
487
|
+
})
|
|
488
|
+
console.log(result.summary) // { files, errors, warnings }
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Troubleshooting
|
|
492
|
+
|
|
493
|
+
<details>
|
|
494
|
+
<summary><code>weft is not installed</code> (E_NO_WEFT)</summary>
|
|
495
|
+
|
|
496
|
+
`@weft-js/core/compiler` resolves neither from the project nor from the CLI. Install `@weft-js/core` in the app.
|
|
497
|
+
</details>
|
|
498
|
+
|
|
499
|
+
<details>
|
|
500
|
+
<summary>Which compiler am I running?</summary>
|
|
501
|
+
|
|
502
|
+
`weft doctor`, or `weft check --verbose`. The WASM build gives the same output as the native addon; the addon only adds
|
|
503
|
+
speed. Rust is never needed to use Weft.
|
|
504
|
+
</details>
|
|
505
|
+
|
|
506
|
+
<details>
|
|
507
|
+
<summary><code>weft build</code> refused with a code</summary>
|
|
508
|
+
|
|
509
|
+
The build found an error in the built pages or the target. The message has the fix, and the way past it:
|
|
510
|
+
`--unsafe-allow <code>`, or `build.unsafeAllow` in `weft.config.ts` with a reason. It exits 1, not 2.
|
|
511
|
+
</details>
|
|
512
|
+
|
|
513
|
+
<details>
|
|
514
|
+
<summary><code>weft audit</code> skipped</summary>
|
|
515
|
+
|
|
516
|
+
It needs a Chrome or Chromium on the machine. Without one it reports `L000` as a warning and checks nothing.
|
|
517
|
+
</details>
|
|
518
|
+
|
|
519
|
+
<details>
|
|
520
|
+
<summary><code>weft test</code> says to use vitest</summary>
|
|
521
|
+
|
|
522
|
+
`weft test` only runs the gate, with `--gate`. Run your suite with vitest.
|
|
523
|
+
</details>
|
|
524
|
+
|
|
525
|
+
<details>
|
|
526
|
+
<summary><code>weft agents-md --check</code> fails in CI</summary>
|
|
527
|
+
|
|
528
|
+
`AGENTS.md` is stale for the installed Weft. Run `weft agents-md` and commit the file. A file over 9 KB fails every run.
|
|
529
|
+
</details>
|
|
530
|
+
|
|
531
|
+
## Related packages
|
|
532
|
+
|
|
533
|
+
| Package | What it is |
|
|
534
|
+
|---|---|
|
|
535
|
+
| [`@weft-js/core`](https://www.npmjs.com/package/@weft-js/core) <sup>[source](https://github.com/Ravonus/weft/tree/main/packages/core)</sup> | The runtime, the compiler binding, the Vite plugin, SSR and test utilities |
|
|
536
|
+
| [`@weft-js/start`](https://www.npmjs.com/package/@weft-js/start) <sup>[source](https://github.com/Ravonus/weft/tree/main/packages/start)</sup> | The full stack: file routes, server functions, SSR, a database, auth and live data |
|
|
537
|
+
| [`@weft-js/create`](https://www.npmjs.com/package/@weft-js/create) <sup>[source](https://github.com/Ravonus/weft/tree/main/packages/create)</sup> | `npm create @weft-js`: a new app with this CLI in it |
|
|
538
|
+
| [`@weft-js/db`](https://www.npmjs.com/package/@weft-js/db) <sup>[source](https://github.com/Ravonus/weft/tree/main/packages/db)</sup> | Prisma and native SQL layers, and list sources |
|
|
539
|
+
| [`@weft-js/warp`](https://www.npmjs.com/package/@weft-js/warp) <sup>[source](https://github.com/Ravonus/weft/tree/main/packages/warp)</sup> | Warp's components, and the `warp()` theming plugin |
|
|
540
|
+
|
|
541
|
+
## Contributing
|
|
542
|
+
|
|
543
|
+
[CONTRIBUTING.md](https://github.com/Ravonus/weft/blob/main/CONTRIBUTING.md) has the setup. To work on this package:
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
pnpm --filter @weft-js/cli test
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
The pages `weft docs` prints are in
|
|
550
|
+
[`packages/cli/docs`](https://github.com/Ravonus/weft/tree/main/packages/cli/docs). Report security problems privately,
|
|
551
|
+
as [SECURITY.md](https://github.com/Ravonus/weft/blob/main/.github/SECURITY.md) says.
|
|
93
552
|
|
|
94
|
-
##
|
|
553
|
+
## License
|
|
95
554
|
|
|
96
|
-
|
|
97
|
-
- [Weft on GitHub](https://github.com/Ravonus/weft): the framework, the docs and every package
|
|
98
|
-
- [Changelog](https://github.com/Ravonus/weft/blob/main/CHANGELOG.md)
|
|
99
|
-
- [Issues](https://github.com/Ravonus/weft/issues)
|
|
555
|
+
[MIT](https://github.com/Ravonus/weft/blob/main/LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weft-js/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "The weft command: dev, build, check, the agent layer and the MCP server",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,17 +21,17 @@
|
|
|
21
21
|
"./config": "./src/config.mjs"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
|
-
"node": ">=
|
|
24
|
+
"node": ">=24"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@weft-js/create": "0.1.
|
|
27
|
+
"@weft-js/create": "0.1.4",
|
|
28
28
|
"axe-core": "4.14.0",
|
|
29
29
|
"typescript": "6.0.3",
|
|
30
30
|
"yaml": "2.9.1",
|
|
31
31
|
"zod": "4.6.7"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@weft-js/core": "^0.1.
|
|
34
|
+
"@weft-js/core": "^0.1.4"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
@@ -60,6 +60,7 @@ function baseSchemas(z) {
|
|
|
60
60
|
inlineCss: z.boolean().optional(),
|
|
61
61
|
criticalCss: z.boolean().optional(),
|
|
62
62
|
criticalKeep: z.array(z.string()).optional(),
|
|
63
|
+
csp: z.literal('strict').optional(),
|
|
63
64
|
image: z.union([z.literal('auto'), z.literal(false), z.string().min(1), image]).optional(),
|
|
64
65
|
card: card.optional(),
|
|
65
66
|
head: z.string().optional(),
|
package/src/mcp.mjs
CHANGED
|
@@ -191,7 +191,7 @@ export async function handle(root, msg) {
|
|
|
191
191
|
return reply({
|
|
192
192
|
protocolVersion: versions.includes(asked) ? asked : versions[0],
|
|
193
193
|
capabilities: { tools: { listChanged: false } },
|
|
194
|
-
serverInfo: { name: 'weft', version: '0.1.
|
|
194
|
+
serverInfo: { name: 'weft', version: '0.1.4' },
|
|
195
195
|
instructions:
|
|
196
196
|
'weft is a fine-grained reactive TSX framework, not React. Read `docs` topic `rules` first, and run `check` after every edit. Every page sets `meta` from its own context as part of building it (`docs` topic `meta`). Chrome shared across route sections (a sidebar) goes in one layout above them that follows `currentPath()`, never a layout per section (`docs` topic `start`). Style with groups from @weft-js/core/style, not class lists: `style_find` before you write one. Verify behavior in the running app with the browser_* tools (or `__weft__.agent` in your own browser), and run `test_gate` before you call a change done.',
|
|
197
197
|
})
|