@craft-ts/mcp 0.7.0-beta.13 → 0.7.0-beta.16
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/content/best-practices.md +1 -1
- package/content/docs-index.json +143 -48
- package/dist/mcp-server.js +78 -3
- package/dist/mcp-server.js.map +1 -1
- package/package.json +3 -2
- package/skills/craft-ts/SKILL.md +29 -2
- package/skills/craft-ts-effect-v4/SKILL.md +15 -1
- package/skills/craft-ts-i18n/SKILL.md +119 -0
- package/skills/craft-ts-style/SKILL.md +116 -0
package/dist/mcp-server.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
1
9
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
10
|
import { z } from 'zod';
|
|
3
11
|
import { findPage, pageUrl, searchPages } from './catalog.js';
|
|
@@ -121,8 +129,77 @@ export function createCraftMcpServer(resources) {
|
|
|
121
129
|
url: `${pageUrl(page.path)}.md`,
|
|
122
130
|
})),
|
|
123
131
|
}));
|
|
132
|
+
registerStyleTools(server);
|
|
124
133
|
return server;
|
|
125
134
|
}
|
|
135
|
+
const DEFAULT_STYLE_DUMP = 'tmp/craft-style-graph.json';
|
|
136
|
+
const STYLE_REPORT_MODULE = '@craft-ts/dev-tools/style-report';
|
|
137
|
+
const styleReport = async () => {
|
|
138
|
+
// Resolved at call time, through a specifier this package's own build does
|
|
139
|
+
// not need to see: `@craft-ts/dev-tools` is a peer of the workspace, not of
|
|
140
|
+
// the published bundle. An installation without it fails here, with a
|
|
141
|
+
// message, rather than failing to start.
|
|
142
|
+
const loaded = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ STYLE_REPORT_MODULE)).catch(() => {
|
|
143
|
+
throw new Error(`The style tools need '${STYLE_REPORT_MODULE}'. Install @craft-ts/dev-tools alongside this server, or use \`craft-graph --style-matrix\` from the repository instead.`);
|
|
144
|
+
}));
|
|
145
|
+
return loaded;
|
|
146
|
+
};
|
|
147
|
+
const DUMP_INPUT = {
|
|
148
|
+
dumpPath: z
|
|
149
|
+
.string()
|
|
150
|
+
.optional()
|
|
151
|
+
.describe(`Path to the style dump the build plugin writes. Defaults to ${DEFAULT_STYLE_DUMP}.`),
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* The style questions, read-only, answered from the emitted dump.
|
|
155
|
+
*
|
|
156
|
+
* They call the same functions the CLI calls rather than reimplementing the
|
|
157
|
+
* queries: one question must not have two answers depending on who asked. The
|
|
158
|
+
* import is dynamic so that opening the server does not pull the graph
|
|
159
|
+
* machinery into memory for an agent that only wanted the documentation.
|
|
160
|
+
*/
|
|
161
|
+
function registerStyleTools(server) {
|
|
162
|
+
const loadDump = async (dumpPath) => {
|
|
163
|
+
const path = dumpPath ?? DEFAULT_STYLE_DUMP;
|
|
164
|
+
const { readFile } = await import('node:fs/promises');
|
|
165
|
+
try {
|
|
166
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
throw new Error(`No style dump at '${path}'. It is written by the build plugin: give craftStyle({ dumpPath }) a path and run a build, or pass dumpPath.`);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
server.registerTool('style_impact', {
|
|
173
|
+
description: 'Which sheet classes a change to one or more CSS custom properties can be seen in. Use it before rerunning a visual suite: changing one token should recapture what reaches it, not everything. Answers `narrowed: false` when a name is unknown to the graph, in which case the answer is the whole application on purpose.',
|
|
174
|
+
inputSchema: {
|
|
175
|
+
changed: z
|
|
176
|
+
.array(z.string().min(1))
|
|
177
|
+
.min(1)
|
|
178
|
+
.describe('Custom property names, e.g. --ds-accent'),
|
|
179
|
+
...DUMP_INPUT,
|
|
180
|
+
},
|
|
181
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
182
|
+
}, async ({ changed, dumpPath }) => {
|
|
183
|
+
const { styleImpact } = await styleReport();
|
|
184
|
+
return toolResult(styleImpact(await loadDump(dumpPath), changed));
|
|
185
|
+
});
|
|
186
|
+
server.registerTool('style_matrix', {
|
|
187
|
+
description: 'What the application costs to capture: the number of visual states per sheet class, the total, the median and the largest. The median and the largest are the two numbers that decide whether matrix reduction is worth opening at all.',
|
|
188
|
+
inputSchema: { ...DUMP_INPUT },
|
|
189
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
190
|
+
}, async ({ dumpPath }) => {
|
|
191
|
+
const { styleMatrix } = await styleReport();
|
|
192
|
+
return toolResult(styleMatrix(await loadDump(dumpPath)));
|
|
193
|
+
});
|
|
194
|
+
server.registerTool('style_debt', {
|
|
195
|
+
description: 'What the style system is owed: escape hatches taken with their stated reason, context obligations required and discharged nowhere, variables declared and never read, and the components no sheet is known to style. Read `extractionGaps` first — the rest is only worth its answer on a complete graph.',
|
|
196
|
+
inputSchema: { ...DUMP_INPUT },
|
|
197
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
198
|
+
}, async ({ dumpPath }) => {
|
|
199
|
+
const { styleDebt } = await styleReport();
|
|
200
|
+
return toolResult(styleDebt(await loadDump(dumpPath)));
|
|
201
|
+
});
|
|
202
|
+
}
|
|
126
203
|
function serializePage(page) {
|
|
127
204
|
return {
|
|
128
205
|
path: page.path,
|
|
@@ -135,9 +212,7 @@ function serializePage(page) {
|
|
|
135
212
|
}
|
|
136
213
|
function toolResult(result) {
|
|
137
214
|
return {
|
|
138
|
-
content: [
|
|
139
|
-
{ type: 'text', text: JSON.stringify(result, null, 2) },
|
|
140
|
-
],
|
|
215
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
141
216
|
structuredContent: { result },
|
|
142
217
|
};
|
|
143
218
|
}
|
package/dist/mcp-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@craft-ts/mcp",
|
|
3
|
-
"version": "0.7.0-beta.
|
|
3
|
+
"version": "0.7.0-beta.16",
|
|
4
4
|
"description": "MCP server, Agent Skills, and LLM files for coding agents using @craft-ts/core",
|
|
5
5
|
"author": "Romain Geffrault",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,9 +32,10 @@
|
|
|
32
32
|
"bundle-docs": "node scripts/bundle-docs.mjs",
|
|
33
33
|
"build": "node scripts/build.mjs",
|
|
34
34
|
"start": "npm run build && node dist/main.js",
|
|
35
|
-
"test": "vitest run"
|
|
35
|
+
"test": "vitest run --config vitest.config.mts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
+
"@craft-ts/dev-tools": "^0.7.0-beta.0",
|
|
38
39
|
"@modelcontextprotocol/sdk": "1.26.0",
|
|
39
40
|
"zod": "4.3.6"
|
|
40
41
|
},
|
package/skills/craft-ts/SKILL.md
CHANGED
|
@@ -19,7 +19,20 @@ required and must not be introduced just to solve a Craft problem.
|
|
|
19
19
|
- `craft-ts-routes` — type-safe routes and DI checks
|
|
20
20
|
- `craft-ts-service-migration` — Angular services → `craftService`
|
|
21
21
|
- `migrate-to-craft-ts` — run `craft-migrate`, then finish diagnostics
|
|
22
|
-
- `craft-ts-effect-v4` — use Effect v4 services, Layers
|
|
22
|
+
- `craft-ts-effect-v4` — use Effect v4 services, Layers, `queryEffect`, and
|
|
23
|
+
the synchronous-member declaration (`SyncOp` / `computedEffect`)
|
|
24
|
+
- `craft-ts-style` — the typed design system: sheets, axes, the visual
|
|
25
|
+
matrix, context obligations
|
|
26
|
+
- `craft-ts-i18n` — typed catalogues, locale parity, semantic tokens
|
|
27
|
+
|
|
28
|
+
For a project created by `craft create`, keep the generated development
|
|
29
|
+
surface enabled. Run `npm run logs:server` for the local JSONL ingestion
|
|
30
|
+
server and `npm run registry:mcp` for the browser page MCP bridge; the
|
|
31
|
+
generated `.mcp.json` also registers the Craft guidance and log-reader MCP
|
|
32
|
+
servers. Use Craft `Console.*` for entries that must be searchable through
|
|
33
|
+
`npm run logs:mcp`; raw `console.*` calls stay in the browser or server
|
|
34
|
+
process console. These facilities are development-only and must not be added
|
|
35
|
+
to a production provider graph.
|
|
23
36
|
|
|
24
37
|
If MCP is not configured, read https://ng-angular-stack.github.io/craft/llms.txt and the `AGENTS.md` snippet in this package (`content/agents.md`).
|
|
25
38
|
|
|
@@ -36,8 +49,22 @@ If MCP is not configured, read https://ng-angular-stack.github.io/craft/llms.txt
|
|
|
36
49
|
required, and `hydrateCraft` when hydration must be forced or customized.
|
|
37
50
|
- Use `renderCraft` for one isolated SSR request. Create a new render per
|
|
38
51
|
request; never reuse its injector, platform, primitive registry, or history.
|
|
39
|
-
- Keep SSR data behavior explicit with `
|
|
52
|
+
- Keep SSR data behavior explicit with `pendingNode({ ssr: 'block' | 'fallback' | 'client' })`
|
|
40
53
|
or a route-level `ssr` policy. Do not let a suspended source reach SSR
|
|
41
54
|
without a policy.
|
|
55
|
+
- Visual rules live in a `*.style.ts` sheet. Static variation becomes a class
|
|
56
|
+
the emitter wrote; dynamic variation goes through a typed custom property.
|
|
57
|
+
Never assemble a class string at render time — the template sets one constant
|
|
58
|
+
class and a `data-*` attribute. `@craft-ts/style` is a **build step**: without
|
|
59
|
+
`craftStyle()` from `@craft-ts/style/vite` in the Vite config, the sheets
|
|
60
|
+
typecheck and emit nothing. Load `craft-ts-style` before touching one.
|
|
61
|
+
- Translations live in a `@craft-ts/i18n` catalogue: `defineCatalog` + `msg` for
|
|
62
|
+
the reference locale, `defineLocaleLike` for every other one, so a missing key
|
|
63
|
+
is a compile error. `@craft-ts/i18n` has no framework and no Effect import;
|
|
64
|
+
use `@craft-ts/i18n-effect` only inside an Effect program. Load
|
|
65
|
+
`craft-ts-i18n` before adding a key, a locale or a token.
|
|
42
66
|
- Run existing architecture tests. Do not add an architecture rule for the feature.
|
|
67
|
+
- Keep `npm run typecheck` in the project CI; for generated projects this is
|
|
68
|
+
already wired into `.github/workflows/ci.yml` alongside the architecture
|
|
69
|
+
and build checks.
|
|
43
70
|
- Confirm symbols against the installed `node_modules/@craft-ts/core`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: craft-ts-effect-v4
|
|
3
|
-
description: Build Effect v4 integrations in framework-independent CraftTS applications with typed services, Layers, queryEffect and Effect diagnostics. Use when a project selected EffectTS during craft create or when editing Effect domain code.
|
|
3
|
+
description: Build Effect v4 integrations in framework-independent CraftTS applications with typed services, Layers, queryEffect, methodEffect, synchronous members (SyncOp / computedEffect / syncEffect) and Effect diagnostics. Use when a project selected EffectTS during craft create or when editing Effect domain code.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# CraftTS + Effect v4
|
|
@@ -16,6 +16,20 @@ examples copied from older documentation.
|
|
|
16
16
|
the Craft app config.
|
|
17
17
|
- UI data loading uses `queryEffect`; do not call `Effect.runPromise` from a
|
|
18
18
|
component or bypass the Craft reactive lifecycle.
|
|
19
|
+
- `Effect<A, E, R>` does not say whether running it suspends, and a service
|
|
20
|
+
member hides it further: a `Layer` closes over its dependencies, so a network
|
|
21
|
+
call and a pure calculation both surface as `R = never`. Declare the members
|
|
22
|
+
that never suspend by putting `SyncOp` in their requirements — in the shape
|
|
23
|
+
when it is written by hand, with `yield* SyncOp` when `R` is inferred.
|
|
24
|
+
- A declared-synchronous Effect is the only one allowed where Craft runs the
|
|
25
|
+
synchronous driver. Use `computedEffect` for a derived value (the Effect
|
|
26
|
+
counterpart of `craftComputed`) and `methodEffect` for a callable method (the
|
|
27
|
+
Effect counterpart of `craftMethod`). Use `syncEffect(...)` directly in a
|
|
28
|
+
`params`, a `craftMethod` or a `state` updater. Anything that suspends belongs
|
|
29
|
+
to a `loader`.
|
|
30
|
+
- Never declare `SyncOp` on a member that can suspend. The claim is checked by
|
|
31
|
+
`craft-ts/sync-effect-body` on the body and by `Effect.runSyncExitWith` at
|
|
32
|
+
runtime, which throws `CraftEffectNotSynchronous` on the first call.
|
|
19
33
|
- Install `installCraftEffectBridge()` once during bootstrap.
|
|
20
34
|
- Run the Effect diagnostics command from `package.json` after changing an
|
|
21
35
|
Effect generator, service, schema or Layer.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-ts-i18n
|
|
3
|
+
description: Build and review type-safe internationalisation in a CraftTS project with @craft-ts/i18n — closed key unions, locale parity, typed message parameters, per-locale plural categories, semantic tokens, the reactive translator, and the @craft-ts/i18n-effect adapter. Use when adding a translation, a locale, a token, or when a translation typecheck or i18n:check fails.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CraftTS type-safe i18n
|
|
7
|
+
|
|
8
|
+
`@craft-ts/i18n` has **no CraftTS, Angular or Effect import**. The catalogue is
|
|
9
|
+
a plain TypeScript value and the runtime works in a browser, a server, a worker
|
|
10
|
+
or a test without a framework. Do not reach for Effect to translate a string.
|
|
11
|
+
|
|
12
|
+
The contract it enforces, all at typecheck time:
|
|
13
|
+
|
|
14
|
+
1. the set of keys is a **closed union** — an unknown key does not compile;
|
|
15
|
+
2. every locale has the **same keys with the same parameters**;
|
|
16
|
+
3. message parameters are **typed by their token**, so a date cannot be passed
|
|
17
|
+
where a currency amount belongs;
|
|
18
|
+
4. a plural message must carry **every category the locale requires** — Polish
|
|
19
|
+
needs `one`, `few`, `many`, `other`; French needs `one` and `other`.
|
|
20
|
+
|
|
21
|
+
## Writing a catalogue
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { defineCatalog, defineLocale, defineLocaleLike, money, msg, number, plural } from '@craft-ts/i18n';
|
|
25
|
+
|
|
26
|
+
const amount = money('amount', undefined, { currency: 'EUR' });
|
|
27
|
+
const count = number('count');
|
|
28
|
+
|
|
29
|
+
const en = defineLocale('en-US', defineCatalog({
|
|
30
|
+
order: {
|
|
31
|
+
total: msg`Order total ${amount}.`,
|
|
32
|
+
items: plural(count, {
|
|
33
|
+
one: msg`${count} item is in the order.`,
|
|
34
|
+
other: msg`${count} items are in the order.`,
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const fr = defineLocaleLike(en, 'fr-FR', { order: { /* same shape */ } });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`msg` is a **tagged template**: the interpolations are tokens, and the params
|
|
43
|
+
type of the message is derived from them. `defineLocale` is for the reference
|
|
44
|
+
locale; every other locale uses `defineLocaleLike(reference, id, catalog)`,
|
|
45
|
+
which is what turns a missing or renamed key into a compile error instead of a
|
|
46
|
+
runtime fallback. Keys nest freely; a key is the dotted path.
|
|
47
|
+
|
|
48
|
+
## Tokens
|
|
49
|
+
|
|
50
|
+
Shipped, semantic, and locale-aware through `Intl`: `number`, `integer`,
|
|
51
|
+
`percent`, `compactNumber`, `money`, `dateShort`, `dateLong`, `dateTime`,
|
|
52
|
+
`relativeTime`. Each is a factory — `factory(name, adapter?, options?)` — where
|
|
53
|
+
`name` becomes the parameter name.
|
|
54
|
+
|
|
55
|
+
For a business value, `defineToken({ name, kind, tokenId, validate, format })`;
|
|
56
|
+
for a family of them, `defineTokenFactory({ kind, format })`. Keep business
|
|
57
|
+
vocabulary in the project, in `src/i18n/project-tokens.ts`, not in the shared
|
|
58
|
+
library.
|
|
59
|
+
|
|
60
|
+
## The runtime
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const i18n = createI18nRuntime({ locales, defaultLocale: 'en-US' });
|
|
64
|
+
i18n.t('order.total', { amount: 1234.5 });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- `t` is `translate`; both take the key and, when the message has parameters, a
|
|
68
|
+
typed params object.
|
|
69
|
+
- `strict` defaults to **on**: every catalogue is validated and every locale is
|
|
70
|
+
checked for parity against the first one at construction.
|
|
71
|
+
- `setLocale(id)` throws `I18nRuntimeError('LOCALE_NOT_LOADED')` for a locale
|
|
72
|
+
that was never loaded. Note the current limit: `setLocale` and `loadLocale`
|
|
73
|
+
are keyed on the ids in `locales`, and a locale listed there already counts as
|
|
74
|
+
loaded — so list every locale, and treat `createI18nLoader` as the retry-safe
|
|
75
|
+
cache (it evicts failed loads) rather than as a fully lazy catalogue.
|
|
76
|
+
- `timeZone` belongs on the runtime, not on each call site.
|
|
77
|
+
|
|
78
|
+
### Reactive translation
|
|
79
|
+
|
|
80
|
+
`runtime.bind(dependency)` returns a translator whose result re-reads when the
|
|
81
|
+
dependency changes. The dependency is a Craft reader — typically the `state`
|
|
82
|
+
holding the current locale — so a component consumes one service rather than
|
|
83
|
+
building a local binding:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
return { language, setLocale: language.setLocale, translate: runtime.bind(language) };
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`bind(...)('key', params)` returns a generator the template yields, like any
|
|
90
|
+
other Craft reader.
|
|
91
|
+
|
|
92
|
+
## With Effect
|
|
93
|
+
|
|
94
|
+
`@craft-ts/i18n-effect` is the adapter, and only the adapter:
|
|
95
|
+
|
|
96
|
+
- `provideI18nRuntime(runtime)` → `Layer.Layer<I18nEffectService>`;
|
|
97
|
+
- `translateEffect(key, params)` →
|
|
98
|
+
`Effect.Effect<string, never, I18nEffectService>`.
|
|
99
|
+
|
|
100
|
+
Same keys, same params, same result as `runtime.t`. Use it inside an Effect
|
|
101
|
+
program; in plain component code, call `t` directly.
|
|
102
|
+
|
|
103
|
+
**`translateEffect` cannot infer the locales.** It has no value parameter
|
|
104
|
+
carrying them, so called bare its key parameter resolves to `never` and even a
|
|
105
|
+
valid key is rejected. Either pass the type arguments —
|
|
106
|
+
`translateEffect<typeof locales, 'order.total'>(…)` — or bind them once in a
|
|
107
|
+
project-local wrapper, which is the pattern in `/guide/i18n/effect`.
|
|
108
|
+
|
|
109
|
+
## Checks
|
|
110
|
+
|
|
111
|
+
- `npm run i18n:check` — catalogue validity and locale parity, outside the
|
|
112
|
+
typechecker.
|
|
113
|
+
- `npm run i18n:test` — the runtime behaviour.
|
|
114
|
+
|
|
115
|
+
Run both after touching `src/i18n/`. A failing parity check names the key and
|
|
116
|
+
the locale; add the key rather than loosening the catalogue type.
|
|
117
|
+
|
|
118
|
+
Full guide: `/guide/i18n/`, `/guide/i18n/catalog`, `/guide/i18n/tokens`,
|
|
119
|
+
`/guide/i18n/runtime`, `/guide/i18n/effect`.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-ts-style
|
|
3
|
+
description: Build and review the typed design system of a CraftTS project with @craft-ts/style — palettes, axes, typed custom properties, sheets, context obligations, the visual matrix, and the style_impact / style_matrix / style_debt MCP tools. Use when adding or changing visual rules, a variant, a theme, dark mode, or a visual test.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CraftTS typed styles
|
|
7
|
+
|
|
8
|
+
`@craft-ts/style` makes a component's visual surface **derivable** rather than
|
|
9
|
+
guessed: what the exhaustive set of visual states is, which are impossible, and
|
|
10
|
+
whether the context a rule needs exists — all from the same values the CSS is
|
|
11
|
+
emitted from.
|
|
12
|
+
|
|
13
|
+
## First: is it wired at all?
|
|
14
|
+
|
|
15
|
+
The system is a **build step**, not a runtime library. Before writing a rule,
|
|
16
|
+
confirm three things exist; without them the sheets typecheck and emit nothing.
|
|
17
|
+
|
|
18
|
+
1. `@craft-ts/style` in `dependencies`, `@craft-ts/style-testing` in
|
|
19
|
+
`devDependencies`.
|
|
20
|
+
2. `craftStyle()` from `@craft-ts/style/vite` in the Vite `plugins` array, with
|
|
21
|
+
a `dumpPath`. The dump is what the graph and the MCP tools below read; no
|
|
22
|
+
`dumpPath`, no answers.
|
|
23
|
+
3. `import 'virtual:craft-style.css'` once, at the app entry.
|
|
24
|
+
|
|
25
|
+
A project created by `craft create` already has all three.
|
|
26
|
+
|
|
27
|
+
## Hard rules
|
|
28
|
+
|
|
29
|
+
- **Static variation goes to a class the emitter wrote; dynamic variation goes
|
|
30
|
+
through a typed custom property.** No class is ever assembled in the browser.
|
|
31
|
+
- **A variant is an axis, never a class name.** The template sets one constant
|
|
32
|
+
class and a `data-*` attribute. `class:` bound to a string, a template
|
|
33
|
+
literal or a function is a visual state nothing recorded — `no-raw-class`
|
|
34
|
+
reports it in every file that imports `@craft-ts/style`.
|
|
35
|
+
- **A `*.style.ts` imports vocabulary and nothing else.** That is what makes it
|
|
36
|
+
safe for the plugin to import it in Node. `style-file-boundary` enforces it.
|
|
37
|
+
- **Components read theme variables, never palette tokens.** The theme is the
|
|
38
|
+
one place that decides what a variable holds in light and in dark, which is
|
|
39
|
+
what makes dark mode one rule instead of one per component.
|
|
40
|
+
- **No value is a string.** `space(4)`, `unit.rem(1.5)`, `palette.text.strong` —
|
|
41
|
+
never `'12px'`. The scales are closed; when a step is missing, add it to the
|
|
42
|
+
scale. `no-raw-css-value` reports the rest.
|
|
43
|
+
- **`overflow` is not in the property table.** The only road to
|
|
44
|
+
`overflow-block: auto` is `provides(scrollPort.block)`.
|
|
45
|
+
- **`:has()` is not free-form.** `no-free-has` reports a hand-written one; use
|
|
46
|
+
the `descendant` axis.
|
|
47
|
+
- Escape hatches — `unsafeLength(value, reason)`, `unsafeAssume(id, reason)` —
|
|
48
|
+
compile and propagate `unproven` to the graph, where the debt is counted.
|
|
49
|
+
Take one only with a reason a reader can act on.
|
|
50
|
+
|
|
51
|
+
## Where things are declared
|
|
52
|
+
|
|
53
|
+
| you need | call |
|
|
54
|
+
| --------------------- | ------------------------------------------- |
|
|
55
|
+
| colours | `definePalette({ group: { token: { light, dark } } })` |
|
|
56
|
+
| viewport breakpoints | `defineBreakpoints({ md: at.minInlineSize(unit.rem(48)) })` |
|
|
57
|
+
| a state variant | `defineStateAxis('tone', ['neutral', 'danger'])` |
|
|
58
|
+
| an axis that may only write one kind | `defineAxis(name, values, onlyVarsOfKind(kind.color))` |
|
|
59
|
+
| the size of a box | `defineContainer({ name, type }, points)` |
|
|
60
|
+
| typed custom properties | `cssVars('prefix', { ink: kind.color(token) })` |
|
|
61
|
+
| the rules themselves | `craftStyles('name', { root: [...] }, { axes: [...] })` |
|
|
62
|
+
|
|
63
|
+
`scheme`, `motion`, `forcedColors`, `contrast`, `scrollState` and `descendant`
|
|
64
|
+
ship with the package and need no declaration.
|
|
65
|
+
|
|
66
|
+
Two details the types cannot enforce and the browser does:
|
|
67
|
+
|
|
68
|
+
- a registered `initial-value` must be computationally independent —
|
|
69
|
+
`kind.length(unit.px(16))`, never `unit.rem(1)`, or the browser drops the
|
|
70
|
+
`@property` rule silently;
|
|
71
|
+
- `inherits: true` belongs to theme variables and to nothing else.
|
|
72
|
+
|
|
73
|
+
## Context obligations
|
|
74
|
+
|
|
75
|
+
`requires(scrollPort.block)` on a class travels up the tree until a
|
|
76
|
+
`provides(...)` answers it, and becomes an error only where a component seals
|
|
77
|
+
(`{ seals: [true] }`) or `seal(node)` closes it. Put the provider on the layout
|
|
78
|
+
component that owns the area — an `overflow` on the direct parent creates a
|
|
79
|
+
second scroll port and moves the bug instead of fixing it.
|
|
80
|
+
|
|
81
|
+
Level 3 is a **per-route** guarantee. One component in the path handing back a
|
|
82
|
+
loosely typed subtree stops the requirement travelling, and a partial adoption
|
|
83
|
+
gives zero of the guarantee, not most of it.
|
|
84
|
+
|
|
85
|
+
## Testing
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { applyScenario, visualMatrix } from '@craft-ts/style-testing';
|
|
89
|
+
|
|
90
|
+
for (const scenario of visualMatrix(sheet)) {
|
|
91
|
+
await applyScenario(page, scenario);
|
|
92
|
+
await expect(page).toHaveScreenshot(`${scenario.id}.png`);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`visualMatrix` takes **sheets**, not a component. `assertExhaustiveVisualMatrix`
|
|
97
|
+
fails in both directions: a baseline nothing produces any more is as wrong as a
|
|
98
|
+
missing one.
|
|
99
|
+
|
|
100
|
+
## Asking the graph
|
|
101
|
+
|
|
102
|
+
Three MCP tools read the dump, so you do not have to write a script:
|
|
103
|
+
|
|
104
|
+
- `style_impact` — which classes a change to given custom properties reaches.
|
|
105
|
+
Run it before rerunning a visual suite; changing one token should not
|
|
106
|
+
recapture everything.
|
|
107
|
+
- `style_matrix` — what the app costs to capture, with the median and the
|
|
108
|
+
largest. Those two numbers decide whether matrix reduction is worth opening.
|
|
109
|
+
- `style_debt` — escape hatches with their reasons, obligations discharged
|
|
110
|
+
nowhere, variables never read, components no sheet is known to style. Read
|
|
111
|
+
`extractionGaps` first; the rest is only meaningful on a complete graph.
|
|
112
|
+
|
|
113
|
+
An empty `style_matrix` is the signature of a missing `dumpPath`.
|
|
114
|
+
|
|
115
|
+
Full guide: `/guide/style/setup`, `/guide/style/define`, `/guide/style/tokens`,
|
|
116
|
+
`/guide/style/variants`, `/guide/style/obligations`, `/guide/style/testing`.
|