@abide/abide 0.120.0 → 0.121.0

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/ABIDE.md ADDED
@@ -0,0 +1,152 @@
1
+ # Working on an abide app
2
+
3
+ These instructions ship with `@abide/abide` and update with it — do not edit this file.
4
+
5
+ abide is newer than any model's training data, so read its documentation before writing code,
6
+ rather than guessing from Svelte, Vue or React. It installs with the package:
7
+
8
+ - `node_modules/@abide/abide/docs/abide.md` — every documentation page in reading order, with a
9
+ working example for each task. It is long: read its Contents, then search for the page's
10
+ address, which heads each page as a comment — `<!-- values/show-a-value-that-changes.md -->`.
11
+ - `node_modules/@abide/abide/docs/REGISTRY.md` — every name an app can import or write, with its
12
+ signature and the rules that govern it.
13
+ - `node_modules/@abide/abide/docs/RULEBOOK.md` — every rule, numbered. A compiler or server
14
+ message that ends in `RULEBOOK 23.16.` names a clause in this file — search it for `23.16`.
15
+
16
+ When abide itself misbehaves, do not code around it: leave a `TODO(abide):` comment above the
17
+ affected code saying what it did, and tell the user.
18
+
19
+ ## Checking your work
20
+
21
+ - `bun run check` — runs `abide check`, the type checker over `.abide` files. `tsc` and an editor's
22
+ TypeScript service do not read `.abide` files, so a clean `tsc` says nothing about them. Run
23
+ `bun run check` after every change, and treat its warnings as bugs: several of them name a read
24
+ that will not update when its value changes.
25
+ Where the read is meant, `// abide-ignore` and the clause the warning cites, on the line above
26
+ (`// abide-ignore 14.15`), silences that one (RULEBOOK 14.19); a read hoisted out of its place
27
+ only to quiet a warning is the bug it named.
28
+ - `bun run test` — runs `bun test`. Every handler file has a test that imports the handler and
29
+ calls it. Every component has a test that `mount`s it and counts the work an
30
+ interaction did with `measure`, both from `@abide/harness/abide` (RULEBOOK 38.119, 43.23) — a
31
+ test that only reads the text back passes against a component doing ten times the work.
32
+ A test waits on a value landing — `await` the handler call, or the `Reactive` the component
33
+ reads, which is thenable (RULEBOOK 1.4) — never on `Bun.sleep` or a timer. Break the code once and
34
+ watch a new test fail; a test that has never failed has not been shown to test anything.
35
+ Called outside a request, a `GET` keeps its answer for the whole test process: a test that changes
36
+ the data behind one calls its `invalidate()` in `beforeEach`. A handler that reads `config()` or
37
+ `principal` runs inside `app.run(…)` of `await createApp()`, where the app's `onConfig` has run.
38
+ `mount` sets no route, so a page stays thin: it reads the route and hands what it needs to a
39
+ component in `lib/`, and the test mounts that component.
40
+ - `bun run bench` — runs `harness-bench`: every `*.bench.ts` under `src/`, kept beside the code it
41
+ times. Each export is a function returning `batch()` from `@abide/harness/report`, an op at two
42
+ sizes; a `CEILINGS` export, `{ [bench]: { [arm]: milliseconds } }`, names the most each arm may
43
+ take, and an arm over it, or a ceiling naming no bench or arm, fails the run (RULEBOOK 43.29,
44
+ 43.31, 43.32, 43.33).
45
+ - `bun run format` — `abide format` over every `.abide`, then `bun fmt` over the rest. Run it once
46
+ your changes are done.
47
+ - `bun run dev` — serves the app on a local port and rebuilds when a file changes.
48
+ - `bun run build` then `bun run start` — the production build, and the app served from it.
49
+
50
+ ## Layout
51
+
52
+ - A file's path below `src/` is its address. `src/invoices/index.abide` answers `/invoices`,
53
+ `src/invoices/[id].abide` answers `/invoices/123`, and `layout.abide` wraps the pages below it;
54
+ the outermost one writes `<html>`. Run `bun run routes` to see every address and the file behind it.
55
+ - A `<name>.handler.ts` beside the pages is a handler: `src/invoices/getInvoice.handler.ts` holds
56
+ `export default GET(…)` and answers `/invoices/getInvoice`. It is the app's public API, for pages,
57
+ scripts, the CLI and MCP alike.
58
+ - A `.abide` cannot export. A `<script server>` in one holds that file's private handlers
59
+ (`const save = POST(…)`), callable by that file alone, and its hooks (`onStart`, `middleware`, …).
60
+ - A directory holds addresses, tests, benches, `.d.ts` declarations and two fenced directories
61
+ alone: `lib/` for components and modules, and `public/` for files served as they are. Anything
62
+ else beside the pages is a build error.
63
+ - Either fence may sit in any directory, at the root or beside the pages that use it.
64
+ `src/lib/` and `src/invoices/lib/` import alike (`#src/…`); the one difference is a lifecycle
65
+ hook a `lib/` file calls, filed at the route of the directory holding that `lib/` (RULEBOOK 37.1).
66
+ A `public/` file answers at the route of the directory holding it: `src/public/logo.png` answers
67
+ `/logo.png`, and `src/blog/public/cover.png` answers `/blog/cover.png`.
68
+ - Put a module in the `lib/` beside the pages that use it, and in `src/lib/` only once pages in
69
+ different directories share it. Within a `lib/`, group by what the code is about (`cart/`,
70
+ `catalog/`), not by which side runs it — the `.server.ts` name already says that.
71
+ - A test is a `.test.ts`, and a bench a `.bench.ts`, kept beside the file it tests or times — a
72
+ page, a handler, or a module in `lib/` (RULEBOOK 23.22). There is no `tests/` folder.
73
+ A browser test (playwright) is a `.test.ts` too, under `e2e/` beside `src/`: `bun test` reads
74
+ `src/` alone (`root` in `bunfig.toml`), so it never runs one.
75
+ - A module the browser never loads is named `<name>.server.ts` and lives in `lib/`
76
+ (`src/invoices/lib/db.server.ts`); importing one from browser code is a compile error. A module it
77
+ imports is not fenced by it.
78
+ - Import the app's own modules as `#src/…` (see `imports` in `package.json`).
79
+ - A test imports `.abide` files directly: `bunfig.toml` preloads `@abide/harness/abide/preload`,
80
+ a DOM to mount into and then `@abide/abide/test`.
81
+
82
+ ## Reactive values
83
+
84
+ - Export a `Reactive` itself, never wrapped in an object — one per file, even when several belong
85
+ together: an `.abide` file reads and writes it by name (RULEBOOK 31.1), and one reached through a
86
+ property is left to `x()` and `x.set(v)` (31.7).
87
+ - Change part of a value by writing through its path — `edits.kind = kind`, `items.push(item)`
88
+ (RULEBOOK 31.8, 31.9) — not by rebuilding it (`edits = { ...edits, kind }`,
89
+ `items = [...items, item]`). Bind through the path too: `bind:value={edits.kind}` (32.5), not a
90
+ `{ get, set }` pair. In a `.ts` file the same write is `edits.patch((value) => { value.kind = kind })`,
91
+ not `edits.set({ ...edits(), kind })`.
92
+ - Derive a value with `reactive(() => …)`. `watch` is only for reaching outside the reactive graph —
93
+ the DOM, a timer, an imperative API — and never assigns state; a user action's effect belongs in
94
+ its event handler. A `watch` runs during a server render too (RULEBOOK 12.5), so one that starts a
95
+ timer or touches a browser global returns a `Disposer`.
96
+ - A preference the page renders — a currency, a theme, a panel left open — lives in a cookie:
97
+ `const theme = reactive(() => cookies().get('theme') ?? 'light')`, written with
98
+ `cookies().set('theme', next)`. `cookies()` is the request's on the server and the document's in
99
+ the browser, and a read by name is tracked (RULEBOOK 22.2, 22.4), so the first paint is already
100
+ right and a write repaints. The browser sends it, so check what it holds before trusting it.
101
+ `localStorage` is for a working set the browser alone needs: the server cannot read it, and
102
+ renders the initial value.
103
+ - A value that has not landed leaves its place in markup as it was — empty before it first lands,
104
+ the last value while it reloads — and fills it when it lands (RULEBOOK 32.23), so markup needs no
105
+ guard. Do not paper over it with `?? []` or `x.ready() ? x : undefined`
106
+ — that makes "not loaded yet" read as "empty". Branch on `x.ready()` or `x.busy()` only where a
107
+ placeholder is actually wanted.
108
+
109
+ ## Settings and untrusted input
110
+
111
+ - Settings come from `onConfig` and `config` (RULEBOOK 27.2, 27.9), and cookies from `cookies()`
112
+ (22.2) — never `Bun.env`, `process.env` or a parsed `cookie` header in `src/`, and never a branch on
113
+ `NODE_ENV`. The environment overrides a default `onConfig` returns (27.2, 27.8), and `bun test`
114
+ reads `.env.test`, so a test's database or data directory is a line in `.env.test`, not a check in
115
+ the app's code.
116
+ - Model output, markdown and fetched HTML are untrusted. Never hand them to `raw()` (RULEBOOK 32.2)
117
+ unsanitized. Render markdown on the server — a component in the browser calls a private `POST` in
118
+ its `<script server>` for it. `Bun.markdown.html(text, { noHtmlBlocks: true, noHtmlSpans: true })`
119
+ escapes HTML but keeps a `javascript:` URL, so pass its output through `HTMLRewriter` and drop any
120
+ `href` that is not `http:`, `https:` or `mailto:`, and any `src` that is not `http:` or `https:`.
121
+
122
+ ## Measuring
123
+
124
+ - Measure with `@abide/harness`, not a hand-written timer, bench runner or Chrome DevTools Protocol
125
+ script: `measure` in a test and `batch` in a bench (above), and `traceOp` and `shares` from
126
+ `@abide/harness/engine` for what Chromium did, from a playwright test. The page
127
+ `guide/test-measure-and-ship.md` in `abide.md`, and "The measurement harness" in `REGISTRY.md`,
128
+ document it.
129
+
130
+ ## Code
131
+
132
+ - One export per file, and the file is named after it: `SCREAMING_SNAKE_CASE.ts` for a constant,
133
+ `TitleCase.abide` / `TitleCase.ts` for a component, a class or a type, `camelCase.ts` for a
134
+ function. No barrel files. Before writing a helper, search `lib/` for one to reuse or widen.
135
+ macOS disks ignore case, so two files in one directory never differ by case alone
136
+ (`RecipeStore.ts` beside `recipeStore.ts`): one silently replaces the other.
137
+ - Names say what they hold — `selectedInvoice`, not `sel`, `x` or `S`.
138
+ - A file past a few hundred lines is a component or a module waiting to be split out; split it
139
+ before adding to it.
140
+ - Use Bun's APIs (`Bun.file`, `Bun.write`, `Bun.$`, `bun:sqlite`) before `node:` ones.
141
+ - Style with tailwind classes. `style=` is for a value computed at runtime. Tailwind is wired
142
+ already (RULEBOOK 38.131): `src/lib/app.css`, imported by the root `layout.abide`, is where a theme
143
+ or a plugin goes.
144
+ - In code that runs per row, per frame or per chunk, write a `for` loop rather than a chain of
145
+ `map` / `filter` / `reduce`, which allocates an array per step. Elsewhere, write what reads best.
146
+ - Comment only where the reason is not obvious from the code, in a line or two. A comment is not a
147
+ log: no history ("used to…", "now…") and no file paths that go stale.
148
+
149
+ ## The app's own notes
150
+
151
+ The app's `AGENTS.md` holds instructions — commands, conventions, where things live — and stays
152
+ short. What the product does, how a feature behaves and why it was built that way goes in `docs/`.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @abide/abide
2
2
 
3
+ ## 0.121.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 980d729: the agent instructions ship in the package and a scaffolded CLAUDE.md imports them, and the starter comes with tailwind wired (RULEBOOK 38.104, 38.106, 38.131) ([`c95852e`](https://github.com/briancray/abide/commit/c95852e7bc195cb9f5ef53f0623e31700362b302))
8
+
9
+ ### Patch Changes
10
+
11
+ - 980d729: the shipped agent instructions are ABIDE.md, so no agent working on abide reads them as its own, and a gate holds their citations and the starter's tailwind to what resolves (RULEBOOK 38.104, 38.106, 38.131) ([`2880551`](https://github.com/briancray/abide/commit/2880551b777247a88e7042fa5bdd462fab3e40b2))
12
+ - 980d729: one dangling-citation scan and one built-stylesheet read in the tests, and the shipped agent instructions state each rule once ([`602cb8f`](https://github.com/briancray/abide/commit/602cb8fd87f136ea23a58dd006bdac43ca65ebe4))
13
+
3
14
  ## 0.120.0
4
15
 
5
16
  ### Minor Changes
package/docs/REGISTRY.md CHANGED
@@ -858,7 +858,7 @@ rows a runner prints, and an adapter for an abide app.
858
858
 
859
859
  | Command | Meaning | Rules |
860
860
  | --- | --- | --- |
861
- | `abide scaffold <name>` | Writes a starter project. | 38.1, 38.42, 38.103, 38.104, 38.106, 38.112, 38.122, 38.124 |
861
+ | `abide scaffold <name>` | Writes a starter project. | 38.1, 38.42, 38.103, 38.104, 38.106, 38.112, 38.122, 38.124, 38.131 |
862
862
  | `abide run <file> [args…]` | Runs a script under the abide runtime. | 38.2, 38.57 |
863
863
  | `abide check [dir…]` | The type-checker over a `.abide` tree. | 38.3, 38.31, 38.32, 38.33, 38.40, 38.105, 38.123 |
864
864
  | `abide format [--check] [dir…]` | The formatter over a `.abide` tree. | 38.25, 38.125, 38.126, 38.127, 38.128, 38.129 |
package/docs/RULEBOOK.md CHANGED
@@ -2755,14 +2755,15 @@ open on the refusal, and the `connect` menu role MUST show the connect dialog op
2755
2755
 
2756
2756
  38.103 The project `abide scaffold` writes MUST carry a `check` script that runs `abide check`.
2757
2757
 
2758
- 38.104 The project `abide scaffold` writes MUST carry instructions for a coding agent that name where
2759
- the installed package holds the documentation, the registry and the rulebook.
2758
+ 38.104 The project `abide scaffold` writes MUST carry instructions for a coding agent that import the
2759
+ ones the installed package holds, and those MUST name where the installed package holds the
2760
+ documentation, the registry and the rulebook.
2760
2761
 
2761
2762
  38.105 Every clause an `abide check` diagnostic or a refusal cites MUST resolve in a rulebook the
2762
2763
  published package holds.
2763
2764
 
2764
- 38.106 The documentation the instructions `abide scaffold` writes name (38.104) MUST be every page
2765
- as one markdown file, in reading order.
2765
+ 38.106 The documentation named by the instructions a project `abide scaffold` writes imports (38.104)
2766
+ MUST be every page as one markdown file, in reading order.
2766
2767
 
2767
2768
  38.107 `onLauncher` called anywhere but `src/launcher.abide` MUST be a build error naming that file.
2768
2769
 
@@ -2847,6 +2848,9 @@ line, MUST go on formatting the rest, and MUST exit non-zero where it reports on
2847
2848
  38.130 `abide lsp` MUST answer a formatting request with what `abide format` makes of the text the
2848
2849
  editor holds.
2849
2850
 
2851
+ 38.131 The project `abide scaffold` writes MUST carry Tailwind wired: `bun-plugin-tailwind` declared
2852
+ in its `bunfig.toml` (38.43), and a stylesheet importing `tailwindcss` that its root layout imports.
2853
+
2850
2854
  # 39. Head and view transitions
2851
2855
 
2852
2856
  39.1 A `<head>` element in a `.abide` file MUST contribute its children to the document head.
package/docs/abide.md CHANGED
@@ -10736,7 +10736,7 @@ CLI: what is written in place rather than imported.
10736
10736
 
10737
10737
  | Command | Meaning | Rules |
10738
10738
  | --- | --- | --- |
10739
- | `abide scaffold <name>` | Writes a starter project. | [38.1](/rulebook#38.1), [38.42](/rulebook#38.42), [38.103](/rulebook#38.103), [38.104](/rulebook#38.104), [38.106](/rulebook#38.106), [38.112](/rulebook#38.112), [38.122](/rulebook#38.122), [38.124](/rulebook#38.124) |
10739
+ | `abide scaffold <name>` | Writes a starter project. | [38.1](/rulebook#38.1), [38.42](/rulebook#38.42), [38.103](/rulebook#38.103), [38.104](/rulebook#38.104), [38.106](/rulebook#38.106), [38.112](/rulebook#38.112), [38.122](/rulebook#38.122), [38.124](/rulebook#38.124), [38.131](/rulebook#38.131) |
10740
10740
  | `abide run <file> [args…]` | Runs a script under the abide runtime. | [38.2](/rulebook#38.2), [38.57](/rulebook#38.57) |
10741
10741
  | `abide check [dir…]` | The type-checker over a `.abide` tree. | [38.3](/rulebook#38.3), [38.31](/rulebook#38.31), [38.32](/rulebook#38.32), [38.33](/rulebook#38.33), [38.40](/rulebook#38.40), [38.105](/rulebook#38.105), [38.123](/rulebook#38.123) |
10742
10742
  | `abide format [--check] [dir…]` | The formatter over a `.abide` tree. | [38.25](/rulebook#38.25), [38.125](/rulebook#38.125), [38.126](/rulebook#38.126), [38.127](/rulebook#38.127), [38.128](/rulebook#38.128), [38.129](/rulebook#38.129) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abide/abide",
3
- "version": "0.120.0",
3
+ "version": "0.121.0",
4
4
  "type": "module",
5
5
  "description": "Isomorphic type-safe framework for reactive async interfaces for humans and machines",
6
6
  "license": "MIT",
@@ -72,6 +72,7 @@
72
72
  "prepack": "bun ../../scripts/packDocs.ts"
73
73
  },
74
74
  "files": [
75
+ "ABIDE.md",
75
76
  "src",
76
77
  "bin",
77
78
  "scaffold",
@@ -1,76 +1,9 @@
1
1
  # Working on this app
2
2
 
3
- This is an abide app. abide is newer than any model's training data, so read its documentation
4
- before writing code, rather than guessing from Svelte, Vue or React. It installs with the package:
3
+ This is an abide app. Before writing code, read `node_modules/@abide/abide/ABIDE.md`: how an abide
4
+ app is laid out, checked and tested, and what this file is for.
5
5
 
6
- - `node_modules/@abide/abide/docs/abide.md` — every documentation page in reading order, with a
7
- working example for each task. It is long: read its Contents, then search for the page's
8
- address, which heads each page as a comment — `<!-- values/show-a-value-that-changes.md -->`.
9
- - `node_modules/@abide/abide/docs/REGISTRY.md` — every name an app can import or write, with its
10
- signature and the rules that govern it.
11
- - `node_modules/@abide/abide/docs/RULEBOOK.md` — every rule, numbered. A compiler or server
12
- message that ends in `RULEBOOK 23.16.` names a clause in this file — search it for `23.16`.
6
+ ## This app
13
7
 
14
- ## Checking your work
15
-
16
- - `bun run check` — runs `abide check`, the type checker over `.abide` files. `tsc` and an editor's
17
- TypeScript service do not read `.abide` files, so a clean `tsc` says nothing about them. Run
18
- `bun run check` after every change, and treat its warnings as bugs: several of them name a read
19
- that will not update when its value changes.
20
- Where the read is meant, `// abide-ignore` and the clause the warning cites, on the line above
21
- (`// abide-ignore 14.15`), silences that one (RULEBOOK 14.19); a read hoisted out of its place
22
- only to quiet a warning is the bug it named.
23
- - `bun run test` — runs `bun test`. `src/getGreeting.test.ts` is the pattern for a handler: a test
24
- imports it and calls it. `src/index.test.ts` is the pattern for a page: `mount` it, then count
25
- the work a click did with `measure`, both from `@abide/harness/abide` (RULEBOOK 38.119, 43.23).
26
- - `bun run bench` — runs `harness-bench`: every `*.bench.ts` under `src/`, kept beside the code it
27
- times. Each export is a function returning `batch()` from `@abide/harness/report`, an op at two
28
- sizes; a `CEILINGS` export, `{ [bench]: { [arm]: milliseconds } }`, names the most each arm may
29
- take, and an arm over it, or a ceiling naming no bench or arm, fails the run (RULEBOOK 43.29,
30
- 43.31, 43.32, 43.33).
31
- - `bun run dev` — serves the app on a local port and rebuilds when a file changes.
32
- - `bun run build` then `bun run start` — the production build, and the app served from it.
33
-
34
- ## Layout
35
-
36
- - A file's path below `src/` is its address. `src/invoices/index.abide` answers `/invoices`,
37
- `src/invoices/[id].abide` answers `/invoices/123`, and `layout.abide` wraps the pages below it;
38
- the outermost one writes `<html>`. Run `bun run routes` to see every address and the file behind it.
39
- - A `<name>.handler.ts` beside the pages is a handler: `src/invoices/getInvoice.handler.ts` holds
40
- `export default GET(…)` and answers `/invoices/getInvoice`. It is the app's public API, for pages,
41
- scripts, the CLI and MCP alike.
42
- - A `.abide` cannot export. A `<script server>` in one holds that file's private handlers
43
- (`const save = POST(…)`), callable by that file alone, and its hooks (`onStart`, `middleware`, …).
44
- - A directory holds addresses, tests, benches, `.d.ts` declarations and two fenced directories alone: `lib/` for components and
45
- modules, and `public/` for files served as they are. Anything else beside the pages is a build error.
46
- - Either fence may sit in any directory, at the root or beside the pages that use it.
47
- `src/lib/` and `src/invoices/lib/` import alike (`#src/…`); the one difference is a lifecycle
48
- hook a `lib/` file calls, filed at the route of the directory holding that `lib/` (RULEBOOK 37.1).
49
- A `public/` file answers at the route of the directory holding it: `src/public/logo.png` answers
50
- `/logo.png`, and `src/blog/public/cover.png` answers `/blog/cover.png`.
51
- - A test is a `.test.ts`, and a bench a `.bench.ts`, kept beside the file it tests or times — a
52
- page, a handler, or a module in `lib/` (RULEBOOK 23.22).
53
- A browser test (playwright) is a `.test.ts` too, under `e2e/` beside `src/`: `bun test` reads
54
- `src/` alone (`root` in `bunfig.toml`), so it never runs one.
55
- - A module the browser never loads is named `<name>.server.ts` and lives in `lib/`
56
- (`src/invoices/lib/db.server.ts`); importing one from browser code is a compile error. A module it
57
- imports is not fenced by it.
58
- - Import the app's own modules as `#src/…` (see `imports` in `package.json`).
59
- - A test imports `.abide` files directly: `bunfig.toml` preloads `@abide/harness/abide/preload`,
60
- a DOM to mount into and then `@abide/abide/test`.
61
-
62
- ## Habits
63
-
64
- - Measure with `@abide/harness`, not a hand-written timer, bench runner or Chrome DevTools Protocol
65
- script. Its three lanes: `measure` from `@abide/harness/abide` is the DOM work and wakes an op
66
- did, under `bun test`; `batch` from `@abide/harness/report` is time, in a bench; `traceOp` and
67
- `shares` from `@abide/harness/engine` are what Chromium did, from a playwright test. The page
68
- `guide/test-measure-and-ship.md` in `abide.md`, and "The measurement harness" in `REGISTRY.md`,
69
- document it.
70
-
71
- - Export a `Reactive` itself, never wrapped in an object: an `.abide` file reads and writes it by
72
- name (RULEBOOK 31.1), and one reached through a property is left to `x()` and `x.set(v)` (31.7).
73
- - Model output and fetched HTML are untrusted. Never hand them to `raw()` (RULEBOOK 32.2)
74
- unsanitized.
75
- - Settings come from `onConfig` and `config` (RULEBOOK 27.2, 27.9), which already read the
76
- environment, and cookies from `cookies()` (22.2) — not `Bun.env` or a parsed `cookie` header.
8
+ - `src/getGreeting.handler.ts` and its test are the pattern for a handler and the test that calls
9
+ it; `src/index.test.ts` is the pattern for a page test that counts the work a click did.
@@ -1 +1,2 @@
1
+ @node_modules/@abide/abide/ABIDE.md
1
2
  @AGENTS.md
@@ -9,10 +9,10 @@ const greeting = reactive(() => getGreeting({ name: 'world' }))
9
9
 
10
10
  <head><title>Hello</title></head>
11
11
 
12
- <main>
13
- <h1>{greeting}</h1>
12
+ <main class="mx-auto flex max-w-md flex-col gap-4 p-8">
13
+ <h1 class="text-2xl font-semibold">{greeting}</h1>
14
14
  <p>Clicked {count} times.</p>
15
- <button onclick={() => {
15
+ <button class="self-start rounded bg-black px-4 py-2 text-white" onclick={() => {
16
16
  count = count + 1
17
17
  }}>Click</button>
18
18
  </main>
@@ -7,6 +7,10 @@ onStart(async (start) => {
7
7
  })
8
8
  </script>
9
9
 
10
+ <script>
11
+ import '#src/lib/app.css'
12
+ </script>
13
+
10
14
  <html lang="en">
11
15
  <head>
12
16
  <meta charset="utf-8" />
@@ -0,0 +1 @@
1
+ @import "tailwindcss" source("..");
@@ -40,7 +40,7 @@ const SOURCE_ALIAS = { '#src/*': ['./src/*', './src/*.ts'] }
40
40
  * lands first on the PATH inside `bun run`, shadowing the bun that runs everything else.
41
41
  */
42
42
  export const BUNFIG =
43
- '# 38.122 — a peer is not installed: an installed `bun` would shadow this one inside `bun run`.\n[install]\npeer = false\n\n# 38.109, 38.119 — a DOM to mount into and measure, then the app\'s `.abide` files as modules.\n[test]\nroot = "src"\npreload = ["@abide/harness/abide/preload"]\n\n# What `bun fmt` and `abide format` print.\n[fmt]\ntabWidth = 4\nsemi = false\nsingleQuote = true\nsortImports = true\n'
43
+ '# 38.122 — a peer is not installed: an installed `bun` would shadow this one inside `bun run`.\n[install]\npeer = false\n\n# 38.43, 38.131 — the plugin that builds the stylesheet `src/lib/app.css` opens.\n[serve.static]\nplugins = ["bun-plugin-tailwind"]\n\n# 38.109, 38.119 — a DOM to mount into and measure, then the app\'s `.abide` files as modules.\n[test]\nroot = "src"\npreload = ["@abide/harness/abide/preload"]\n\n# What `bun fmt` and `abide format` print.\n[fmt]\ntabWidth = 4\nsemi = false\nsingleQuote = true\nsortImports = true\n'
44
44
 
45
45
  // WRITTEN, NOT COPIED, beside the manifests: a packer drops a `bunfig.toml` or a `.gitignore` from
46
46
  // the tarball (`bun pm pack` both, `npm pack` the second), so neither survives as a starter file.
@@ -80,10 +80,12 @@ function filesFor(name: string): Record<string, string> {
80
80
  // `Bun`, `bun:sqlite` and the rest of the runtime a server module reaches for are
81
81
  // typed by these, and `abide check` reports every one untyped without them. The
82
82
  // harness is what the starter's tests measure the work a click does with (38.119), and
83
- // what `bench` runs (38.124).
83
+ // what `bench` runs (38.124). The stylesheet is tailwind's, built by its bun plugin (38.131).
84
84
  devDependencies: {
85
85
  '@abide/harness': HARNESS_DEPENDENCY,
86
86
  '@types/bun': 'latest',
87
+ 'bun-plugin-tailwind': '^0.1.2',
88
+ tailwindcss: '^4.3.3',
87
89
  },
88
90
  },
89
91
  null,