@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,284 @@
1
+ {
2
+ "compiledAt": "1970-01-01T00:00:00.000Z",
3
+ "provenance": {
4
+ "kind": "fixture",
5
+ "note": "Fixture envelope for skill eval. Replace eval/profiles with committed harness reports (PE-1) and re-run compile-envelope.mjs."
6
+ },
7
+ "thresholds": {
8
+ "headroomGreenBelow": 0.7,
9
+ "headroomAmberBelow": 1,
10
+ "actionSubmitP99Ms": 2000,
11
+ "steadyCpuPctOfOneCore": 80
12
+ },
13
+ "profiles": [
14
+ {
15
+ "profileId": "cap-100devices-2workers",
16
+ "tier": "site-server",
17
+ "hardware": {
18
+ "referenceTier": "site-server",
19
+ "cpuCoresPhysical": 16,
20
+ "cpuCoresLogical": 32,
21
+ "ramGiB": 64,
22
+ "diskType": "nvme"
23
+ },
24
+ "deviceCount": 100,
25
+ "workerCount": 2,
26
+ "workers": [
27
+ {
28
+ "type": "mdk-worker-whatsminer",
29
+ "model": "m56s",
30
+ "deviceCount": 100
31
+ }
32
+ ],
33
+ "status": "green",
34
+ "headroomRatio": 0.55,
35
+ "rssSumMiB": 1200,
36
+ "cpuSumPct": 60,
37
+ "readP99Ms": 70,
38
+ "actionP99Ms": 110,
39
+ "source": "fixture"
40
+ },
41
+ {
42
+ "profileId": "cap-100devices-2workers-mixed",
43
+ "tier": "site-server",
44
+ "hardware": {
45
+ "referenceTier": "site-server",
46
+ "cpuCoresPhysical": 16,
47
+ "cpuCoresLogical": 32,
48
+ "ramGiB": 64,
49
+ "diskType": "nvme"
50
+ },
51
+ "deviceCount": 100,
52
+ "workerCount": 2,
53
+ "workers": [
54
+ {
55
+ "type": "mdk-worker-whatsminer",
56
+ "model": "m56s",
57
+ "deviceCount": 60
58
+ },
59
+ {
60
+ "type": "mdk-worker-antminer",
61
+ "model": "s19xp",
62
+ "deviceCount": 40
63
+ }
64
+ ],
65
+ "status": "green",
66
+ "headroomRatio": 0.5,
67
+ "rssSumMiB": 1300,
68
+ "cpuSumPct": 65,
69
+ "readP99Ms": 75,
70
+ "actionP99Ms": 120,
71
+ "source": "fixture"
72
+ },
73
+ {
74
+ "profileId": "cap-10devices-1workers",
75
+ "tier": "edge",
76
+ "hardware": {
77
+ "referenceTier": "edge",
78
+ "cpuCoresPhysical": 4,
79
+ "cpuCoresLogical": 4,
80
+ "ramGiB": 8,
81
+ "diskType": "sata"
82
+ },
83
+ "deviceCount": 10,
84
+ "workerCount": 1,
85
+ "workers": [
86
+ {
87
+ "type": "mdk-worker-whatsminer",
88
+ "model": "m56s",
89
+ "deviceCount": 10
90
+ }
91
+ ],
92
+ "status": "green",
93
+ "headroomRatio": 0.15,
94
+ "rssSumMiB": 400,
95
+ "cpuSumPct": 20,
96
+ "readP99Ms": 40,
97
+ "actionP99Ms": 70,
98
+ "source": "fixture"
99
+ },
100
+ {
101
+ "profileId": "cap-15devices-2workers",
102
+ "tier": "custom",
103
+ "hardware": {
104
+ "referenceTier": "custom",
105
+ "cpuCoresPhysical": 8,
106
+ "cpuCoresLogical": 16,
107
+ "ramGiB": 32,
108
+ "diskType": "sata"
109
+ },
110
+ "deviceCount": 15,
111
+ "workerCount": 2,
112
+ "workers": [
113
+ {
114
+ "type": "mdk-worker-whatsminer",
115
+ "model": "m56s",
116
+ "deviceCount": 10
117
+ },
118
+ {
119
+ "type": "mdk-worker-antminer",
120
+ "model": "s19xp",
121
+ "deviceCount": 5
122
+ }
123
+ ],
124
+ "status": "green",
125
+ "headroomRatio": 0.2,
126
+ "rssSumMiB": 500,
127
+ "cpuSumPct": 25,
128
+ "readP99Ms": 50,
129
+ "actionP99Ms": 85,
130
+ "source": "fixture"
131
+ },
132
+ {
133
+ "profileId": "cap-200devices-4workers",
134
+ "tier": "site-server",
135
+ "hardware": {
136
+ "referenceTier": "site-server",
137
+ "cpuCoresPhysical": 16,
138
+ "cpuCoresLogical": 32,
139
+ "ramGiB": 64,
140
+ "diskType": "nvme"
141
+ },
142
+ "deviceCount": 200,
143
+ "workerCount": 4,
144
+ "workers": [
145
+ {
146
+ "type": "mdk-worker-whatsminer",
147
+ "model": "m56s",
148
+ "deviceCount": 200
149
+ }
150
+ ],
151
+ "status": "amber",
152
+ "headroomRatio": 0.85,
153
+ "rssSumMiB": 2000,
154
+ "cpuSumPct": 90,
155
+ "readP99Ms": 140,
156
+ "actionP99Ms": 220,
157
+ "source": "fixture"
158
+ },
159
+ {
160
+ "profileId": "cap-500devices-4workers",
161
+ "tier": "site-server",
162
+ "hardware": {
163
+ "referenceTier": "site-server",
164
+ "cpuCoresPhysical": 16,
165
+ "cpuCoresLogical": 32,
166
+ "ramGiB": 64,
167
+ "diskType": "nvme"
168
+ },
169
+ "deviceCount": 500,
170
+ "workerCount": 4,
171
+ "workers": [
172
+ {
173
+ "type": "mdk-worker-whatsminer",
174
+ "model": "m56s",
175
+ "deviceCount": 500
176
+ }
177
+ ],
178
+ "status": "red",
179
+ "headroomRatio": 1.4,
180
+ "rssSumMiB": 4500,
181
+ "cpuSumPct": 180,
182
+ "readP99Ms": 800,
183
+ "actionP99Ms": 2100,
184
+ "source": "fixture"
185
+ },
186
+ {
187
+ "profileId": "cap-50devices-2workers",
188
+ "tier": "site-server",
189
+ "hardware": {
190
+ "referenceTier": "site-server",
191
+ "cpuCoresPhysical": 16,
192
+ "cpuCoresLogical": 32,
193
+ "ramGiB": 64,
194
+ "diskType": "nvme"
195
+ },
196
+ "deviceCount": 50,
197
+ "workerCount": 2,
198
+ "workers": [
199
+ {
200
+ "type": "mdk-worker-whatsminer",
201
+ "model": "m56s",
202
+ "deviceCount": 50
203
+ }
204
+ ],
205
+ "status": "green",
206
+ "headroomRatio": 0.35,
207
+ "rssSumMiB": 800,
208
+ "cpuSumPct": 40,
209
+ "readP99Ms": 55,
210
+ "actionP99Ms": 90,
211
+ "source": "fixture"
212
+ }
213
+ ],
214
+ "supportedUpTo": {
215
+ "site-server": {
216
+ "mdk-worker-whatsminer": {
217
+ "devices": 100,
218
+ "workers": 2,
219
+ "profileId": "cap-100devices-2workers"
220
+ },
221
+ "mdk-worker-antminer,mdk-worker-whatsminer": {
222
+ "devices": 100,
223
+ "workers": 2,
224
+ "profileId": "cap-100devices-2workers-mixed"
225
+ }
226
+ },
227
+ "edge": {
228
+ "mdk-worker-whatsminer": {
229
+ "devices": 10,
230
+ "workers": 1,
231
+ "profileId": "cap-10devices-1workers"
232
+ }
233
+ },
234
+ "custom": {
235
+ "mdk-worker-antminer,mdk-worker-whatsminer": {
236
+ "devices": 15,
237
+ "workers": 2,
238
+ "profileId": "cap-15devices-2workers"
239
+ }
240
+ }
241
+ },
242
+ "formulas": {
243
+ "site-server|mdk-worker-whatsminer": {
244
+ "rssMiB": {
245
+ "base": 400,
246
+ "perDevice": 8
247
+ },
248
+ "cpuPct": {
249
+ "base": 23.333333333333336,
250
+ "perDevice": 0.3333333333333333
251
+ }
252
+ },
253
+ "site-server|mdk-worker-antminer,mdk-worker-whatsminer": {
254
+ "rssMiB": {
255
+ "base": 0,
256
+ "perDevice": 13
257
+ },
258
+ "cpuPct": {
259
+ "base": 0,
260
+ "perDevice": 0.65
261
+ }
262
+ },
263
+ "edge|mdk-worker-whatsminer": {
264
+ "rssMiB": {
265
+ "base": 0,
266
+ "perDevice": 40
267
+ },
268
+ "cpuPct": {
269
+ "base": 0,
270
+ "perDevice": 2
271
+ }
272
+ },
273
+ "custom|mdk-worker-antminer,mdk-worker-whatsminer": {
274
+ "rssMiB": {
275
+ "base": 0,
276
+ "perDevice": 33.333333333333336
277
+ },
278
+ "cpuPct": {
279
+ "base": 0,
280
+ "perDevice": 1.6666666666666667
281
+ }
282
+ }
283
+ }
284
+ }
@@ -0,0 +1,42 @@
1
+ # Measured envelope
2
+
3
+ `envelope.json` is the only number source this skill may quote. It is compiled
4
+ from capacity profiles (harness reports or the fixture set under `eval/profiles/`).
5
+
6
+ ## Profile shape
7
+
8
+ Each profile is either a full harness report (`backend/tests/benchmark/results/<id>.json`)
9
+ or the slim fields `compile-envelope.mjs` keeps:
10
+
11
+ - `profileId`, `tier`, `hardware`
12
+ - `deviceCount`, `workerCount`, `workers[]` (`type`, `model`, `deviceCount`)
13
+ - `status` (`green` / `amber` / `red`)
14
+ - `headroomRatio`, `rssSumMiB`, `cpuSumPct`, `readP99Ms`, `actionP99Ms`
15
+ - `source` (`measured` or `fixture`)
16
+
17
+ Pass/fail uses the same bars as the harness (`headroomGreenBelow` 0.7,
18
+ `headroomAmberBelow` 1.0, action submit p99 2000 ms, steady CPU 80% of one
19
+ core). **Supported up to** is the densest green profile on that family mix and
20
+ tier, matching the [capacity metrics template](../../../../../../docs/guides/deployment/capacity-metrics-template.md).
21
+
22
+ ## Compile
23
+
24
+ ```bash
25
+ # fixtures (default) — what the held-out bar runs against until PE-1
26
+ node scripts/compile-envelope.mjs
27
+
28
+ # a real results/ directory from npm run benchmark
29
+ node scripts/compile-envelope.mjs --from <repo>/backend/tests/benchmark/results
30
+ ```
31
+
32
+ `--from` must contain one `.json` per profile. Replacing fixtures with
33
+ committed harness reports (the 1.0 PE-1 gate) is how this envelope becomes
34
+ measured. After that, re-run `eval-held-out.mjs` and keep any case whose
35
+ expected window still matches; drop or rewrite cases the new data invalidates.
36
+
37
+ ## Lookup
38
+
39
+ `size-site.mjs` does not invent a topology. It picks the smallest covering
40
+ profile (`deviceCount >= requested`) at the best status, interpolates RSS/CPU
41
+ between the next-smaller green point and that cover, and refuses to label
42
+ anything past the last non-red point as supported.
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ // Compile measured (or fixture) capacity profiles into references/envelope.json.
3
+ //
4
+ // node compile-envelope.mjs
5
+ // node compile-envelope.mjs --from ../../../../../backend/tests/benchmark/results
6
+ // node compile-envelope.mjs --from ./eval/profiles --out ../references/envelope.json
7
+
8
+ import fs from 'node:fs'
9
+ import path from 'node:path'
10
+ import { fileURLToPath } from 'node:url'
11
+ import { compileEnvelope } from './lib.mjs'
12
+
13
+ const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url))
14
+ const SKILL_DIR = path.resolve(SCRIPT_DIR, '..')
15
+ const DEFAULT_FROM = path.join(SKILL_DIR, 'eval', 'profiles')
16
+ const DEFAULT_OUT = path.join(SKILL_DIR, 'references', 'envelope.json')
17
+
18
+ const args = process.argv.slice(2)
19
+ let fromDir = DEFAULT_FROM
20
+ let outPath = DEFAULT_OUT
21
+ for (let i = 0; i < args.length; i++) {
22
+ if (args[i] === '--from') fromDir = path.resolve(args[++i])
23
+ else if (args[i] === '--out') outPath = path.resolve(args[++i])
24
+ else {
25
+ console.error(`unknown flag ${args[i]}`)
26
+ process.exit(2)
27
+ }
28
+ }
29
+
30
+ if (!fs.existsSync(fromDir)) {
31
+ console.error(`compile-envelope: source dir missing: ${fromDir}`)
32
+ process.exit(1)
33
+ }
34
+
35
+ const files = fs.readdirSync(fromDir).filter((n) => n.endsWith('.json')).sort()
36
+ if (!files.length) {
37
+ console.error(`compile-envelope: no .json profiles in ${fromDir}`)
38
+ process.exit(1)
39
+ }
40
+
41
+ const raw = files.map((n) => JSON.parse(fs.readFileSync(path.join(fromDir, n), 'utf8')))
42
+ const envelope = compileEnvelope(raw, { compiledAt: '1970-01-01T00:00:00.000Z' })
43
+ fs.mkdirSync(path.dirname(outPath), { recursive: true })
44
+ fs.writeFileSync(outPath, JSON.stringify(envelope, null, 2) + '\n')
45
+ console.error(`compiled ${envelope.profiles.length} profile(s) -> ${outPath} (${envelope.provenance.kind})`)
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ // Held-out bar: parse each site description, size it, match the measured envelope.
3
+ // Exit 0 only when every case matches. This is the skill's acceptance test.
4
+ //
5
+ // node eval-held-out.mjs
6
+ // node eval-held-out.mjs --held-out ../eval/held-out.json --envelope ../references/envelope.json
7
+
8
+ import fs from 'node:fs'
9
+ import path from 'node:path'
10
+ import { fileURLToPath } from 'node:url'
11
+ import { parseSiteDescription, sizeSite, matchRecommendation } from './lib.mjs'
12
+
13
+ const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url))
14
+ const SKILL_DIR = path.resolve(SCRIPT_DIR, '..')
15
+
16
+ const args = process.argv.slice(2)
17
+ let heldOutPath = path.join(SKILL_DIR, 'eval', 'held-out.json')
18
+ let envelopePath = path.join(SKILL_DIR, 'references', 'envelope.json')
19
+ for (let i = 0; i < args.length; i++) {
20
+ if (args[i] === '--held-out') heldOutPath = path.resolve(args[++i])
21
+ else if (args[i] === '--envelope') envelopePath = path.resolve(args[++i])
22
+ else {
23
+ console.error(`unknown flag ${args[i]}`)
24
+ process.exit(2)
25
+ }
26
+ }
27
+
28
+ const heldOut = JSON.parse(fs.readFileSync(heldOutPath, 'utf8'))
29
+ const envelope = JSON.parse(fs.readFileSync(envelopePath, 'utf8'))
30
+ const cases = heldOut.cases || []
31
+
32
+ let failed = 0
33
+ for (const c of cases) {
34
+ const facts = parseSiteDescription(c.description)
35
+ const rec = sizeSite(facts, envelope)
36
+ const result = matchRecommendation(rec, c.expected)
37
+ if (result.ok) {
38
+ console.log(`PASS ${c.id}`)
39
+ } else {
40
+ failed++
41
+ console.log(`FAIL ${c.id}`)
42
+ for (const e of result.errors) console.log(` ${e}`)
43
+ console.log(` facts: ${JSON.stringify({ devices: facts.devices, deviceCount: facts.deviceCount, host: facts.host })}`)
44
+ console.log(` rec: ${JSON.stringify({ status: rec.status, tier: rec.tier, workerCount: rec.workerCount, matchingProfileId: rec.matchingProfileId, rssSumMiB: rec.rssSumMiB, supportedUpTo: rec.envelope?.supportedUpTo })}`)
45
+ }
46
+ }
47
+
48
+ const n = cases.length
49
+ console.log(`${n - failed}/${n} held-out descriptions match the measured envelope`)
50
+ process.exit(failed ? 1 : 0)