hackshop-mcp 0.0.3 → 0.0.5
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 +88 -34
- package/catalog.json +1584 -25
- package/dist/build-plan/index.d.ts +10 -0
- package/dist/build-plan/index.js +550 -0
- package/dist/build-plan/index.js.map +1 -0
- package/dist/build-plan/types.d.ts +153 -0
- package/dist/build-plan/types.js +2 -0
- package/dist/build-plan/types.js.map +1 -0
- package/dist/catalog/schema.d.ts +523 -7
- package/dist/catalog/schema.js +49 -0
- package/dist/catalog/schema.js.map +1 -1
- package/dist/core/assess.d.ts +36 -0
- package/dist/core/assess.js +100 -0
- package/dist/core/assess.js.map +1 -0
- package/dist/core/errors.d.ts +2 -0
- package/dist/core/errors.js +70 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/links.d.ts +3 -0
- package/dist/core/links.js +19 -0
- package/dist/core/links.js.map +1 -0
- package/dist/core/plan-gadget.d.ts +85 -0
- package/dist/core/plan-gadget.js +619 -0
- package/dist/core/plan-gadget.js.map +1 -0
- package/dist/core/resources.d.ts +37 -0
- package/dist/core/resources.js +143 -0
- package/dist/core/resources.js.map +1 -0
- package/dist/core/safety.d.ts +7 -0
- package/dist/core/safety.js +28 -0
- package/dist/core/safety.js.map +1 -0
- package/dist/core/tools.d.ts +247 -0
- package/dist/core/tools.js +164 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/core/types.d.ts +163 -0
- package/dist/core/types.js +17 -0
- package/dist/core/types.js.map +1 -0
- package/dist/platforms/index.d.ts +26 -0
- package/dist/platforms/index.js +52 -0
- package/dist/platforms/index.js.map +1 -0
- package/dist/platforms/load.d.ts +4 -0
- package/dist/platforms/load.js +78 -0
- package/dist/platforms/load.js.map +1 -0
- package/dist/platforms/schema.d.ts +587 -0
- package/dist/platforms/schema.js +64 -0
- package/dist/platforms/schema.js.map +1 -0
- package/dist/sampling.d.ts +5 -0
- package/dist/sampling.js +44 -21
- package/dist/sampling.js.map +1 -1
- package/dist/server.d.ts +14 -1
- package/dist/server.js +164 -40
- package/dist/server.js.map +1 -1
- package/dist/site-url.d.ts +1 -0
- package/dist/site-url.js +4 -0
- package/dist/site-url.js.map +1 -0
- package/dist/telemetry.d.ts +29 -0
- package/dist/telemetry.js +100 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tools/assess_hackability.d.ts +2 -29
- package/dist/tools/assess_hackability.js +11 -43
- package/dist/tools/assess_hackability.js.map +1 -1
- package/dist/tools/get_build_plan.d.ts +6 -0
- package/dist/tools/get_build_plan.js +16 -0
- package/dist/tools/get_build_plan.js.map +1 -0
- package/dist/tools/plan_gadget.d.ts +4 -0
- package/dist/tools/plan_gadget.js +14 -0
- package/dist/tools/plan_gadget.js.map +1 -0
- package/dist/tools/propose_hardware.d.ts +5 -0
- package/dist/tools/propose_hardware.js +57 -8
- package/dist/tools/propose_hardware.js.map +1 -1
- package/dist/tools/simulate_assembly.d.ts +315 -0
- package/dist/tools/simulate_assembly.js +145 -0
- package/dist/tools/simulate_assembly.js.map +1 -0
- package/package.json +4 -1
- package/platforms.json +779 -0
- package/tags.md +1 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export declare const NEED_VALUES: readonly ["voice", "screen", "images", "touch", "camera", "air-sensors", "e-ink", "battery", "round", "home-tunnel", "big-screen", "compute", "linux"];
|
|
2
|
+
export type Need = (typeof NEED_VALUES)[number];
|
|
3
|
+
export type Size = "pocket" | "desk" | "wall" | "any";
|
|
4
|
+
export type FeatureValue = boolean | string | number | null;
|
|
5
|
+
export interface Physical {
|
|
6
|
+
orientation: "upright" | "flat";
|
|
7
|
+
shape: "board" | "box" | "round";
|
|
8
|
+
size_mm: {
|
|
9
|
+
w: number;
|
|
10
|
+
h: number;
|
|
11
|
+
t: number | null;
|
|
12
|
+
};
|
|
13
|
+
size_confidence: "published" | "drawing" | "approximate" | "conflicting";
|
|
14
|
+
size_note?: string;
|
|
15
|
+
corner_radius_mm?: number;
|
|
16
|
+
comes_in_case: boolean;
|
|
17
|
+
mass_g: number | null;
|
|
18
|
+
usb: {
|
|
19
|
+
type: string;
|
|
20
|
+
count: number;
|
|
21
|
+
faces: Array<"front" | "back" | "top" | "bottom" | "left" | "right">;
|
|
22
|
+
note?: string;
|
|
23
|
+
} | null;
|
|
24
|
+
mounting: string | null;
|
|
25
|
+
printables: Array<"desk-stand" | "enclosure">;
|
|
26
|
+
source_url: string;
|
|
27
|
+
}
|
|
28
|
+
export interface DeviceEntry {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
category: string;
|
|
32
|
+
idea_fit_tags: string[];
|
|
33
|
+
hack_difficulty: number;
|
|
34
|
+
brick_risk: number;
|
|
35
|
+
brick_provenance: "founder-verified" | "community-reported" | "llm-inferred" | "vendor-docs";
|
|
36
|
+
last_verified: string;
|
|
37
|
+
firmware_links: string[];
|
|
38
|
+
community_size_bucket: string;
|
|
39
|
+
notes: string;
|
|
40
|
+
est_used_price_usd_min?: number;
|
|
41
|
+
est_used_price_usd_max?: number;
|
|
42
|
+
buy_url?: string;
|
|
43
|
+
image_url?: string;
|
|
44
|
+
est_setup_hours_min?: number;
|
|
45
|
+
est_setup_hours_max?: number;
|
|
46
|
+
physical?: Physical;
|
|
47
|
+
}
|
|
48
|
+
export interface PlatformBoardPart {
|
|
49
|
+
name: string;
|
|
50
|
+
qty: number;
|
|
51
|
+
required: boolean;
|
|
52
|
+
note: string;
|
|
53
|
+
buy_url?: string;
|
|
54
|
+
search?: string;
|
|
55
|
+
est_price_usd?: number;
|
|
56
|
+
}
|
|
57
|
+
export interface PlatformBoard {
|
|
58
|
+
device_id: string;
|
|
59
|
+
support: "official" | "possible";
|
|
60
|
+
tier: string;
|
|
61
|
+
kind: string;
|
|
62
|
+
build: string;
|
|
63
|
+
eol?: boolean;
|
|
64
|
+
note: string;
|
|
65
|
+
features: Record<string, FeatureValue>;
|
|
66
|
+
parts: PlatformBoardPart[];
|
|
67
|
+
try_saying: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface Platform {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
vendor: string;
|
|
73
|
+
kind: "agent-gadget";
|
|
74
|
+
launched: string;
|
|
75
|
+
homepage: string;
|
|
76
|
+
sdk_repo: string;
|
|
77
|
+
sdk_path: string;
|
|
78
|
+
docs_url: string;
|
|
79
|
+
license: string;
|
|
80
|
+
summary: string;
|
|
81
|
+
toolchain: string;
|
|
82
|
+
requires: string[];
|
|
83
|
+
setup_steps: string[];
|
|
84
|
+
agent_quickstart: string;
|
|
85
|
+
commands?: string[];
|
|
86
|
+
extending?: string;
|
|
87
|
+
tiers: Array<{
|
|
88
|
+
id: string;
|
|
89
|
+
label: string;
|
|
90
|
+
description: string;
|
|
91
|
+
}>;
|
|
92
|
+
caveats: string[];
|
|
93
|
+
terms: {
|
|
94
|
+
url: string;
|
|
95
|
+
summary: string;
|
|
96
|
+
personal_noncommercial_only?: boolean;
|
|
97
|
+
max_devices_per_token: number;
|
|
98
|
+
selling_allowed: boolean;
|
|
99
|
+
revocable?: boolean;
|
|
100
|
+
};
|
|
101
|
+
community_url?: string;
|
|
102
|
+
boards: PlatformBoard[];
|
|
103
|
+
sources?: string[];
|
|
104
|
+
last_verified?: string;
|
|
105
|
+
}
|
|
106
|
+
export interface Printable {
|
|
107
|
+
part: "desk-stand" | "enclosure";
|
|
108
|
+
title: string;
|
|
109
|
+
stl_url: string;
|
|
110
|
+
step_url: string;
|
|
111
|
+
svg_url: string;
|
|
112
|
+
fab_url: string;
|
|
113
|
+
fab?: PrintableFab;
|
|
114
|
+
}
|
|
115
|
+
export interface PrintableFab {
|
|
116
|
+
print?: {
|
|
117
|
+
orientation?: string;
|
|
118
|
+
supports?: boolean;
|
|
119
|
+
material?: string;
|
|
120
|
+
layer_mm?: number;
|
|
121
|
+
infill_pct?: number;
|
|
122
|
+
};
|
|
123
|
+
params?: {
|
|
124
|
+
clearance?: number;
|
|
125
|
+
cable_d?: number;
|
|
126
|
+
plug_overmold?: number[];
|
|
127
|
+
tilt_deg?: number;
|
|
128
|
+
};
|
|
129
|
+
checks?: Record<string, boolean | null>;
|
|
130
|
+
caveats?: string[];
|
|
131
|
+
source_dims?: {
|
|
132
|
+
w?: number;
|
|
133
|
+
h?: number;
|
|
134
|
+
t?: number | null;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
export interface CoreContext {
|
|
138
|
+
catalog: DeviceEntry[];
|
|
139
|
+
platforms: Platform[];
|
|
140
|
+
printablesFor(device: DeviceEntry, siteUrl: string): Printable[];
|
|
141
|
+
siteUrl: string;
|
|
142
|
+
tags?: string[];
|
|
143
|
+
tagsText?: string;
|
|
144
|
+
}
|
|
145
|
+
export interface DeviceLinks {
|
|
146
|
+
ebay_search_url: string;
|
|
147
|
+
hackaday_search_url: string;
|
|
148
|
+
reddit_search_url: string;
|
|
149
|
+
google_search_url: string;
|
|
150
|
+
}
|
|
151
|
+
export interface AgentPlatform {
|
|
152
|
+
platform_id: string;
|
|
153
|
+
platform_name: string;
|
|
154
|
+
support: "official" | "possible";
|
|
155
|
+
tier: string;
|
|
156
|
+
tier_label: string;
|
|
157
|
+
kind: string;
|
|
158
|
+
build: string;
|
|
159
|
+
eol?: boolean;
|
|
160
|
+
features: Record<string, FeatureValue>;
|
|
161
|
+
note: string;
|
|
162
|
+
}
|
|
163
|
+
export declare const UNRECOVERABLE_BRICK_CATEGORIES: Set<string>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const NEED_VALUES = [
|
|
2
|
+
"voice",
|
|
3
|
+
"screen",
|
|
4
|
+
"images",
|
|
5
|
+
"touch",
|
|
6
|
+
"camera",
|
|
7
|
+
"air-sensors",
|
|
8
|
+
"e-ink",
|
|
9
|
+
"battery",
|
|
10
|
+
"round",
|
|
11
|
+
"home-tunnel",
|
|
12
|
+
"big-screen",
|
|
13
|
+
"compute",
|
|
14
|
+
"linux",
|
|
15
|
+
];
|
|
16
|
+
export const UNRECOVERABLE_BRICK_CATEGORIES = new Set(["handheld", "sbc"]);
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,aAAa;IACb,OAAO;IACP,SAAS;IACT,OAAO;IACP,aAAa;IACb,YAAY;IACZ,SAAS;IACT,OAAO;CACC,CAAC;AA0KX,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DeviceEntry } from "../catalog/schema.js";
|
|
2
|
+
import type { Platform } from "./schema.js";
|
|
3
|
+
export interface AgentPlatform {
|
|
4
|
+
platform_id: string;
|
|
5
|
+
platform_name: string;
|
|
6
|
+
support: "official" | "possible";
|
|
7
|
+
tier: string;
|
|
8
|
+
tier_label: string;
|
|
9
|
+
kind: string;
|
|
10
|
+
build: string;
|
|
11
|
+
eol?: boolean;
|
|
12
|
+
features: Record<string, boolean | string | number | null>;
|
|
13
|
+
note: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Printable {
|
|
16
|
+
part: "desk-stand" | "enclosure";
|
|
17
|
+
title: string;
|
|
18
|
+
stl_url: string;
|
|
19
|
+
step_url: string;
|
|
20
|
+
svg_url: string;
|
|
21
|
+
fab_url: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function setLoadedPlatforms(platforms: Platform[]): void;
|
|
24
|
+
export declare function getLoadedPlatforms(): Platform[];
|
|
25
|
+
export declare function agentPlatformsFor(deviceId: string): AgentPlatform[];
|
|
26
|
+
export declare function printablesFor(device: DeviceEntry, siteUrl?: string): Printable[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { loadCatalog } from "../catalog/load.js";
|
|
2
|
+
import { siteUrlFromEnv } from "../site-url.js";
|
|
3
|
+
import { loadPlatforms } from "./load.js";
|
|
4
|
+
let platformCache = null;
|
|
5
|
+
export function setLoadedPlatforms(platforms) {
|
|
6
|
+
platformCache = platforms;
|
|
7
|
+
}
|
|
8
|
+
export function getLoadedPlatforms() {
|
|
9
|
+
if (platformCache)
|
|
10
|
+
return platformCache;
|
|
11
|
+
const { devices } = loadCatalog();
|
|
12
|
+
platformCache = loadPlatforms(devices);
|
|
13
|
+
return platformCache;
|
|
14
|
+
}
|
|
15
|
+
export function agentPlatformsFor(deviceId) {
|
|
16
|
+
const matches = [];
|
|
17
|
+
for (const platform of getLoadedPlatforms()) {
|
|
18
|
+
const tierLabels = new Map(platform.tiers.map((tier) => [tier.id, tier.label]));
|
|
19
|
+
for (const board of platform.boards) {
|
|
20
|
+
if (board.device_id !== deviceId)
|
|
21
|
+
continue;
|
|
22
|
+
matches.push(toAgentPlatform(platform, board, tierLabels));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return matches;
|
|
26
|
+
}
|
|
27
|
+
export function printablesFor(device, siteUrl = siteUrlFromEnv()) {
|
|
28
|
+
const base = siteUrl.replace(/\/+$/, "");
|
|
29
|
+
return (device.physical?.printables ?? []).map((part) => ({
|
|
30
|
+
part,
|
|
31
|
+
title: part === "desk-stand" ? "Printable desk stand" : "Printable enclosure",
|
|
32
|
+
stl_url: `${base}/cad/${device.id}/${part}.stl`,
|
|
33
|
+
step_url: `${base}/cad/${device.id}/${part}.step`,
|
|
34
|
+
svg_url: `${base}/cad/${device.id}/${part}.svg`,
|
|
35
|
+
fab_url: `${base}/cad/${device.id}/${part}.fab.json`,
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
function toAgentPlatform(platform, board, tierLabels) {
|
|
39
|
+
return {
|
|
40
|
+
platform_id: platform.id,
|
|
41
|
+
platform_name: platform.name,
|
|
42
|
+
support: board.support,
|
|
43
|
+
tier: board.tier,
|
|
44
|
+
tier_label: tierLabels.get(board.tier) ?? board.tier,
|
|
45
|
+
kind: board.kind,
|
|
46
|
+
build: board.build,
|
|
47
|
+
...(board.eol ? { eol: board.eol } : {}),
|
|
48
|
+
features: board.features,
|
|
49
|
+
note: board.note,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/platforms/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAyB1C,IAAI,aAAa,GAAsB,IAAI,CAAC;AAE5C,MAAM,UAAU,kBAAkB,CAAC,SAAqB;IACtD,aAAa,GAAG,SAAS,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IACxC,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAClC,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChF,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,SAAS,KAAK,QAAQ;gBAAE,SAAS;YAC3C,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAmB,EAAE,OAAO,GAAG,cAAc,EAAE;IAC3E,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxD,IAAI;QACJ,KAAK,EAAE,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,qBAAqB;QAC7E,OAAO,EAAE,GAAG,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI,IAAI,MAAM;QAC/C,QAAQ,EAAE,GAAG,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI,IAAI,OAAO;QACjD,OAAO,EAAE,GAAG,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI,IAAI,MAAM;QAC/C,OAAO,EAAE,GAAG,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI,IAAI,WAAW;KACrD,CAAC,CAAC,CAAC;AACN,CAAC;AAED,SAAS,eAAe,CACtB,QAAkB,EAClB,KAAoB,EACpB,UAA+B;IAE/B,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,EAAE;QACxB,aAAa,EAAE,QAAQ,CAAC,IAAI;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI;QACpD,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DeviceEntry } from "../catalog/schema.js";
|
|
2
|
+
import { type Platform } from "./schema.js";
|
|
3
|
+
export declare function loadPlatforms(devices: DeviceEntry[]): Platform[];
|
|
4
|
+
export declare function assertPlatformInvariants(platforms: Platform[], devices: DeviceEntry[]): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { Platforms } from "./schema.js";
|
|
5
|
+
const repoRoot = () => {
|
|
6
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
return join(here, "..", "..");
|
|
8
|
+
};
|
|
9
|
+
export function loadPlatforms(devices) {
|
|
10
|
+
const platformsPath = join(repoRoot(), "platforms.json");
|
|
11
|
+
const raw = readFileSync(platformsPath, "utf8");
|
|
12
|
+
let parsed;
|
|
13
|
+
try {
|
|
14
|
+
parsed = JSON.parse(raw);
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
throw new Error(`platforms.json is not valid JSON: ${e.message}\n` +
|
|
18
|
+
`Path: ${platformsPath}`);
|
|
19
|
+
}
|
|
20
|
+
const result = Platforms.safeParse(parsed);
|
|
21
|
+
if (!result.success) {
|
|
22
|
+
const issues = result.error.issues
|
|
23
|
+
.map((i) => ` - ${i.path.join(".")}: ${i.message}`)
|
|
24
|
+
.join("\n");
|
|
25
|
+
throw new Error(`platforms.json failed schema validation:\n${issues}\n` +
|
|
26
|
+
`Path: ${platformsPath}`);
|
|
27
|
+
}
|
|
28
|
+
assertPlatformInvariants(result.data, devices);
|
|
29
|
+
return result.data;
|
|
30
|
+
}
|
|
31
|
+
export function assertPlatformInvariants(platforms, devices) {
|
|
32
|
+
const deviceIds = new Set(devices.map((device) => device.id));
|
|
33
|
+
const taggedAgentDevices = new Set(devices
|
|
34
|
+
.filter((device) => device.idea_fit_tags.includes("agent-gadget"))
|
|
35
|
+
.map((device) => device.id));
|
|
36
|
+
const platformIds = new Set();
|
|
37
|
+
const platformDevicePairs = new Set();
|
|
38
|
+
const officialAgentDevices = new Set();
|
|
39
|
+
const violations = [];
|
|
40
|
+
for (const platform of platforms) {
|
|
41
|
+
if (platformIds.has(platform.id)) {
|
|
42
|
+
violations.push(` - duplicate platform id "${platform.id}"`);
|
|
43
|
+
}
|
|
44
|
+
platformIds.add(platform.id);
|
|
45
|
+
const tierIds = new Set(platform.tiers.map((tier) => tier.id));
|
|
46
|
+
for (const board of platform.boards) {
|
|
47
|
+
const pairKey = `${platform.id}:${board.device_id}`;
|
|
48
|
+
if (platformDevicePairs.has(pairKey)) {
|
|
49
|
+
violations.push(` - duplicate board pair "${board.device_id}" in platform "${platform.id}"`);
|
|
50
|
+
}
|
|
51
|
+
platformDevicePairs.add(pairKey);
|
|
52
|
+
if (!deviceIds.has(board.device_id)) {
|
|
53
|
+
violations.push(` - platform "${platform.id}" references unknown device "${board.device_id}"`);
|
|
54
|
+
}
|
|
55
|
+
if (!tierIds.has(board.tier)) {
|
|
56
|
+
violations.push(` - board "${board.device_id}" uses unknown tier "${board.tier}" in platform "${platform.id}"`);
|
|
57
|
+
}
|
|
58
|
+
if (board.support === "official") {
|
|
59
|
+
officialAgentDevices.add(board.device_id);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const deviceId of officialAgentDevices) {
|
|
64
|
+
if (!taggedAgentDevices.has(deviceId)) {
|
|
65
|
+
violations.push(` - official platform board "${deviceId}" is missing tag "agent-gadget"`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const deviceId of taggedAgentDevices) {
|
|
69
|
+
if (!officialAgentDevices.has(deviceId)) {
|
|
70
|
+
violations.push(` - device "${deviceId}" has tag "agent-gadget" but is not an official platform board`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (violations.length > 0) {
|
|
74
|
+
throw new Error(`Platform invariant violation:\n${violations.join("\n")}\n\n` +
|
|
75
|
+
`Fix: keep platforms.json, catalog.json and tags.md in sync.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=load.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/platforms/load.ts"],"names":[],"mappings":"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"}
|