@tetherto/mdk-skill 0.0.0 → 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 (62) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +133 -0
  3. package/dist/skills/mdk/SKILL.md +114 -0
  4. package/dist/skills/mdk/references/architecture.md +89 -0
  5. package/dist/skills/mdk/references/glossary.md +27 -0
  6. package/dist/skills/mdk/references/mdk-contract.schema.json +138 -0
  7. package/dist/skills/mdk/references/package-index.md +53 -0
  8. package/dist/skills/mdk/references/protocol.md +95 -0
  9. package/dist/skills/mdk-create-app/SKILL.md +231 -0
  10. package/dist/skills/mdk-deployment/SKILL.md +161 -0
  11. package/dist/skills/mdk-gateway-plugin/SKILL.md +192 -0
  12. package/dist/skills/mdk-gateway-plugin/references/controller-patterns.md +99 -0
  13. package/dist/skills/mdk-gateway-plugin/references/plugin-authoring.md +121 -0
  14. package/dist/skills/mdk-publish-security/SKILL.md +177 -0
  15. package/dist/skills/mdk-publish-security/references/vuln-classes.md +151 -0
  16. package/dist/skills/mdk-publish-security/scripts/scan-packages.mjs +544 -0
  17. package/dist/skills/mdk-site-sizing/SKILL.md +160 -0
  18. package/dist/skills/mdk-site-sizing/eval/held-out.json +104 -0
  19. package/dist/skills/mdk-site-sizing/eval/profiles/cap-100devices-2workers-mixed.json +24 -0
  20. package/dist/skills/mdk-site-sizing/eval/profiles/cap-100devices-2workers.json +23 -0
  21. package/dist/skills/mdk-site-sizing/eval/profiles/cap-10devices-1workers.json +23 -0
  22. package/dist/skills/mdk-site-sizing/eval/profiles/cap-15devices-2workers.json +24 -0
  23. package/dist/skills/mdk-site-sizing/eval/profiles/cap-200devices-4workers.json +23 -0
  24. package/dist/skills/mdk-site-sizing/eval/profiles/cap-500devices-4workers.json +23 -0
  25. package/dist/skills/mdk-site-sizing/eval/profiles/cap-50devices-2workers.json +23 -0
  26. package/dist/skills/mdk-site-sizing/references/envelope.json +284 -0
  27. package/dist/skills/mdk-site-sizing/references/envelope.md +42 -0
  28. package/dist/skills/mdk-site-sizing/scripts/compile-envelope.mjs +45 -0
  29. package/dist/skills/mdk-site-sizing/scripts/eval-held-out.mjs +50 -0
  30. package/dist/skills/mdk-site-sizing/scripts/lib.mjs +591 -0
  31. package/dist/skills/mdk-site-sizing/scripts/parse-site.mjs +25 -0
  32. package/dist/skills/mdk-site-sizing/scripts/size-site.mjs +49 -0
  33. package/dist/skills/mdk-ui-component/SKILL.md +207 -0
  34. package/dist/skills/mdk-ui-component/references/page-recipe.md +78 -0
  35. package/dist/skills/mdk-ui-component/references/ui-registry.json +1 -0
  36. package/dist/skills/mdk-worker-plugin/SKILL.md +198 -0
  37. package/dist/skills/mdk-worker-plugin/assets/mdk-contract.template.json +45 -0
  38. package/dist/skills/mdk-worker-plugin/assets/worker-template/README.md +93 -0
  39. package/dist/skills/mdk-worker-plugin/assets/worker-template/mdk-contract.json +26 -0
  40. package/dist/skills/mdk-worker-plugin/assets/worker-template/mock/server.js +93 -0
  41. package/dist/skills/mdk-worker-plugin/assets/worker-template/package.json +23 -0
  42. package/dist/skills/mdk-worker-plugin/assets/worker-template/smoke.config.js +41 -0
  43. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/client.js +47 -0
  44. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/commands/reboot.js +5 -0
  45. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/commands/set-power-mode.js +10 -0
  46. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/hashrate-rt.js +5 -0
  47. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/power-mode.js +5 -0
  48. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/power.js +5 -0
  49. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/temperature.js +5 -0
  50. package/dist/skills/mdk-worker-plugin/references/contract-authoring.md +135 -0
  51. package/dist/skills/mdk-worker-plugin/references/device-families.md +96 -0
  52. package/dist/skills/mdk-worker-plugin/references/local-testing.md +134 -0
  53. package/dist/skills/mdk-worker-plugin/references/mdk-contract.schema.json +138 -0
  54. package/dist/skills/mdk-worker-plugin/references/worker-base-api.md +152 -0
  55. package/dist/skills/mdk-worker-plugin/scripts/validate-contract.mjs +129 -0
  56. package/dist/skills/mdk-worker-plugin/scripts/worker-smoke.mjs +256 -0
  57. package/package.json +47 -1
  58. package/src/assemble.mjs +11 -0
  59. package/src/index.d.ts +57 -0
  60. package/src/index.mjs +254 -0
  61. package/src/install.mjs +57 -0
  62. package/src/sources.map.json +34 -0
@@ -0,0 +1,207 @@
1
+ ---
2
+ name: mdk-ui-component
3
+ description: >
4
+ Build a UI page/panel that renders data from an MDK Worker or Gateway
5
+ plugin. Use when the task mentions "UI / component / widget / dashboard",
6
+ "show telemetry", "chart / tile / heatmap", "render data from a
7
+ worker/plugin", or prompts like "create a UI to show <metric> for <device>".
8
+ metadata:
9
+ suite: mdk-developer-skill
10
+ mdk_version: "0.5.0"
11
+ license: Apache-2.0
12
+ ---
13
+
14
+ # Build an MDK UI page for worker/plugin data
15
+
16
+ MDK UI shells (`apps/dashboard/`, scaffolded by `mdk create dashboard` — or
17
+ `apps/<name>/` if named explicitly) are **composition only**. Data comes from
18
+ a Gateway route; shaping lives in a hook; visuals come from
19
+ `@tetherto/mdk-react-devkit`. Never invent component prop names — look them
20
+ up in [`references/ui-registry.json`](./references/ui-registry.json).
21
+
22
+ A fresh scaffold ships no example page — build one from these layers (see the
23
+ shell's own [`USAGE.md`](../../../../../examples/mdk-ui-shell-template/USAGE.md), "The pattern every page should follow"):
24
+
25
+ | Layer | Owns |
26
+ | ---------------- | ------------------------------------------------------------------------------ |
27
+ | Gateway route | Your Gateway plugin's route — serves the data |
28
+ | Hook | app-local `src/hooks/use-<thing>.ts` — `useQuery` against the route, shapes the payload in `select` |
29
+ | Page | `apps/dashboard/src/pages/<Name>.tsx` — thin glue, no fetch/shaping |
30
+ | Panel | `apps/dashboard/src/components/<Name>Panel.tsx` — props in, markup out |
31
+ | Route | `apps/dashboard/src/routes.ts` — one line |
32
+
33
+ ## Prerequisites (do these first)
34
+
35
+ 1. **Data source exists.** If no `/api/...` route returns the metric, stop and
36
+ use `mdk-gateway-plugin` to create one. Confirm with `curl` that the JSON shape
37
+ is stable.
38
+ 2. **Contract units known.** Read the Worker `mdk-contract.json` so labels/units
39
+ match (`power` → `W`, etc.). Resolve it from `mdk.yaml` → `spec.workers`:
40
+ local `package` → `<package>/mdk-contract.json` (or legacy
41
+ `<package>/plugin/mdk-contract.json`); npm package → the same under
42
+ `node_modules/<package>/`.
43
+ 3. **Dashboard app exists.** If missing: `mdk create dashboard` (see
44
+ `mdk-deployment`).
45
+
46
+ ## Workflow
47
+
48
+ ```mermaid
49
+ flowchart TD
50
+ intent["Plain-language intent"]
51
+ route{"/api route returns the metric?"}
52
+ gateway["mdk-gateway-plugin: create the route"]
53
+ registry["Pick components from ui-registry.json"]
54
+ contract["Match labels/units to the worker mdk-contract.json"]
55
+ build["Build the hook, panel, and page"]
56
+ wire["Wire the route in routes.ts"]
57
+
58
+ intent --> route
59
+ route -->|no| gateway --> registry
60
+ route -->|yes| registry
61
+ registry --> contract
62
+ contract --> build --> wire
63
+ ```
64
+
65
+ ### 1. Pick the visual from the registry
66
+
67
+ Open [`references/ui-registry.json`](./references/ui-registry.json) (this skill). Use
68
+ `indexes.componentsByName` / `indexes.componentsByCategory`.
69
+
70
+ | Need | Typical component |
71
+ | ----------------------------- | ------------------- |
72
+ | Single numeric metric / total | `SingleStatCard` |
73
+ | Time-series | `LineChartCard` |
74
+ | Fallback text when null | `FALLBACK` constant |
75
+
76
+ Copy **exact** prop names and types from the registry entry. Example
77
+ `SingleStatCard`: `name`, `subtitle`, `value`, `unit`, `variant`, `flash`.
78
+
79
+ ### 2. Add the page scaffold
80
+
81
+ Add the route to `src/routes.ts` yourself — append a one-line entry above the
82
+ `// mdk:routes-end` marker:
83
+
84
+ ```ts
85
+ // src/routes.ts
86
+ export const ROUTES: AppRoute[] = [
87
+ { path: "/<page-name>", label: "<Page Name>", page: () => import("./pages/<PageName>") },
88
+ // mdk:routes-end
89
+ ]
90
+ ```
91
+
92
+ Keep each route on a **single line** and preserve the end marker; the file is
93
+ parsed line-wise by tooling. Do not add feature pages to `router.tsx`.
94
+
95
+ ### 3. Create the data hook (shape the payload)
96
+
97
+ For a **project-local app** (one scaffolded under `apps/<app-name>` by `mdk create app`, referenced by
98
+ its package name in `mdk.yaml` → `spec.apps`), put the hook in the
99
+ dashboard. The Gateway serves the app's routes under `/apps/<app-name>` unless its entry sets
100
+ `mount: /`, so fetch `/apps/<app-name>/api/...`. In dev, the dashboard's Vite proxy must forward
101
+ `/apps` to the Gateway too; add `'/apps': gatewayUrl` next to `/api` in `vite.config.ts` if it is missing:
102
+
103
+ `src/hooks/use-<thing>.ts`
104
+
105
+ ```ts
106
+ import { useQuery } from '@tetherto/mdk-react-adapter'
107
+
108
+ // types matching the route's JSON schema in mdk-plugin.json
109
+ export const useThing = () => {
110
+ const result = useQuery({
111
+ queryKey: ['thing'],
112
+ queryFn: async () => {
113
+ const res = await fetch('/apps/<app-name>/api/...')
114
+ if (!res.ok) throw new Error(`Failed (HTTP ${res.status})`)
115
+ const raw = await res.json()
116
+ // shape → render-ready; never leave shaping to the panel
117
+ return { /* ... */ }
118
+ },
119
+ refetchInterval: 5_000, // live tiles
120
+ })
121
+ return {
122
+ info: result.data ?? EMPTY,
123
+ isLoading: result.isLoading,
124
+ error: result.error,
125
+ refetch: () => { void result.refetch() },
126
+ }
127
+ }
128
+ ```
129
+
130
+ Rules:
131
+
132
+ - Import `useQuery` from `@tetherto/mdk-react-adapter`, **not** from
133
+ `@tanstack/react-query` directly.
134
+ - Hook owns fetch + shaping; panel stays presentational.
135
+ - For reusable MDK-wide endpoints, prefer adding the hook to
136
+ `@tetherto/mdk-react-adapter` (see the dashboard
137
+ [`USAGE.md`](../../../../../examples/mdk-ui-shell-template/USAGE.md)'s layered data
138
+ flow). App-local hooks are correct for project-local plugins.
139
+
140
+ ### 4. Create the presentational panel
141
+
142
+ `src/components/<Name>Panel.tsx`
143
+
144
+ - Props: already-shaped `info` + `isLoading` + `error`
145
+ - No `fetch`, no stores, no inline transforms beyond trivial display
146
+ (`Math.round`)
147
+ - Handle three states: `error`, empty list, data
148
+ - Render registry components with verified props
149
+
150
+ ### 5. Wire a thin page
151
+
152
+ `src/pages/<Name>.tsx`:
153
+
154
+ - Call the hook
155
+ - Wrap in `PageLayout` with title + optional Refresh action
156
+ - Pass hook outputs to the panel
157
+ - Page holds **no** fetch / shaping
158
+
159
+ ### 6. Styles
160
+
161
+ Add a BEM block under the shell namespace in `src/App.scss`, e.g.
162
+ `.mdk-ui-shell-<name>`, matching the `className` on `PageLayout`. Reuse CSS
163
+ variables (`--mdk-color-*`) and mirror the existing blocks in that file for
164
+ structure (refresh button, card, error state).
165
+
166
+ ## Composition rules (do not break)
167
+
168
+ From the dashboard [`USAGE.md`](../../../../../examples/mdk-ui-shell-template/USAGE.md):
169
+
170
+ ```
171
+ Gateway plugin / foundation query
172
+ → adapter or app hook (fetch + shape)
173
+ → thin page (hook → panel)
174
+ → presentational panel + @tetherto/mdk-react-devkit
175
+ ```
176
+
177
+ Forbidden:
178
+
179
+ | Don't | Do |
180
+ | -------------------------------- | -------------------------------------------------------------- |
181
+ | `fetch` inside a panel/component | Hook |
182
+ | Guess `SingleStatCard` props | [`references/ui-registry.json`](./references/ui-registry.json) |
183
+ | Import Ant Design / MUI | `@tetherto/mdk-react-devkit` |
184
+ | Edit `router.tsx` for feature pages | A one-line entry in `routes.ts` |
185
+ | Hard-code units ignoring the contract | Use `unit` from the API payload |
186
+
187
+ ## Worked recipe: "UI to show `<metric>` for `<device family>`"
188
+
189
+ End-to-end chain this kind of prompt implies (router skill expands this):
190
+
191
+ 1. `mdk-gateway-plugin` — ensure `GET /api/<domain>/<resource>` exists and
192
+ returns a shaped payload (e.g. `{ unit, total, devices[] }`) grounded in
193
+ the Worker contract's telemetry channel.
194
+ 2. This skill — hook + `SingleStatCard` grid (total + per-device) + page +
195
+ route.
196
+ 3. `mdk-deployment` — app listed in `mdk.yaml` → `spec.apps`, `mdk run` up (app runtime + Gateway),
197
+ Worker online with a device.
198
+
199
+ Detailed file checklist: [`references/page-recipe.md`](./references/page-recipe.md).
200
+
201
+ ## Hand-off
202
+
203
+ | Problem | Skill |
204
+ | -------------------------- | --------------------------- |
205
+ | No API route / wrong shape | `mdk-gateway-plugin` |
206
+ | Stack not running / app not declared | `mdk-deployment` |
207
+ | Device / telemetry channel missing | `mdk-worker-plugin` |
@@ -0,0 +1,78 @@
1
+ # Page recipe — API-backed metric page
2
+
3
+ Checklist for a new dashboard page that shows live Worker/plugin data.
4
+
5
+ ## Files to add or touch
6
+
7
+ ```
8
+ <dashboard>/
9
+ ├── src/hooks/use-<thing>.ts # fetch + shape (useQuery)
10
+ ├── src/components/<Thing>Panel.tsx # presentational
11
+ ├── src/pages/<Thing>.tsx # thin PageLayout glue
12
+ ├── src/routes.ts # one-line route entry
13
+ └── src/App.scss # .mdk-ui-shell-<thing> block
14
+ ```
15
+
16
+ Optional: `src/constants/navigation.tsx` only if you need a custom nav icon
17
+ (default explorer icon is fine).
18
+
19
+ ## Layer responsibilities
20
+
21
+ | Layer | Owns | Must not |
22
+ | --- | --- | --- |
23
+ | Hook | `fetch`, JSON → typed `info`, polling | JSX |
24
+ | Panel | Markup, loading/empty/error UI, registry components | `fetch`, business rules |
25
+ | Page | Hook call, `PageLayout`, Refresh button | Shaping, direct HTTP |
26
+ | Plugin (backend) | Aggregation across Workers | UI concerns |
27
+
28
+ ## Minimal page skeleton
29
+
30
+ ```tsx
31
+ import { PageLayout } from '../components/PageLayout'
32
+ import { ThingPanel } from '../components/ThingPanel'
33
+ import { useThing } from '../hooks/use-thing'
34
+
35
+ const Thing = () => {
36
+ const { info, isLoading, error, refetch } = useThing()
37
+ return (
38
+ <PageLayout
39
+ title="Thing"
40
+ className="mdk-ui-shell-thing"
41
+ actions={(
42
+ <button type="button" onClick={refetch} disabled={isLoading}>
43
+ {isLoading ? 'Refreshing…' : 'Refresh'}
44
+ </button>
45
+ )}
46
+ >
47
+ <ThingPanel info={info} isLoading={isLoading} error={error} />
48
+ </PageLayout>
49
+ )
50
+ }
51
+
52
+ export default Thing
53
+ ```
54
+
55
+ ## Route entry
56
+
57
+ ```ts
58
+ { path: '/thing', label: 'Thing', page: () => import('./pages/Thing') },
59
+ // mdk:routes-end
60
+ ```
61
+
62
+ Keep on one line. Path becomes the sidebar href.
63
+
64
+ ## Component lookup
65
+
66
+ Before writing JSX:
67
+
68
+ 1. Open [`ui-registry.json`](./ui-registry.json).
69
+ 2. Find the component by name.
70
+ 3. Use only documented `props[]` names/types.
71
+ 4. Prefer `tier: "agent-ready"` / `public: true` components.
72
+
73
+ ## Composition rules
74
+
75
+ See the shell's own [`USAGE.md`](../../../../../../examples/mdk-ui-shell-template/USAGE.md) ("The pattern every page should follow") for the
76
+ layered data flow this checklist implements: a fresh scaffold ships no example
77
+ page, so there is no file in the project to copy — follow the layer
78
+ responsibilities above instead.