hackshop-mcp 0.0.4 → 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.
Files changed (64) hide show
  1. package/README.md +34 -34
  2. package/catalog.json +55 -41
  3. package/dist/build-plan/index.d.ts +10 -0
  4. package/dist/build-plan/index.js +550 -0
  5. package/dist/build-plan/index.js.map +1 -0
  6. package/dist/build-plan/types.d.ts +153 -0
  7. package/dist/build-plan/types.js +2 -0
  8. package/dist/build-plan/types.js.map +1 -0
  9. package/dist/catalog/schema.d.ts +13 -7
  10. package/dist/catalog/schema.js +2 -0
  11. package/dist/catalog/schema.js.map +1 -1
  12. package/dist/core/assess.d.ts +36 -0
  13. package/dist/core/assess.js +100 -0
  14. package/dist/core/assess.js.map +1 -0
  15. package/dist/core/errors.d.ts +2 -0
  16. package/dist/core/errors.js +70 -0
  17. package/dist/core/errors.js.map +1 -0
  18. package/dist/core/links.d.ts +3 -0
  19. package/dist/core/links.js +19 -0
  20. package/dist/core/links.js.map +1 -0
  21. package/dist/core/plan-gadget.d.ts +85 -0
  22. package/dist/core/plan-gadget.js +619 -0
  23. package/dist/core/plan-gadget.js.map +1 -0
  24. package/dist/core/resources.d.ts +37 -0
  25. package/dist/core/resources.js +143 -0
  26. package/dist/core/resources.js.map +1 -0
  27. package/dist/core/safety.d.ts +7 -0
  28. package/dist/core/safety.js +28 -0
  29. package/dist/core/safety.js.map +1 -0
  30. package/dist/core/tools.d.ts +247 -0
  31. package/dist/core/tools.js +164 -0
  32. package/dist/core/tools.js.map +1 -0
  33. package/dist/core/types.d.ts +163 -0
  34. package/dist/core/types.js +17 -0
  35. package/dist/core/types.js.map +1 -0
  36. package/dist/platforms/index.d.ts +1 -1
  37. package/dist/platforms/index.js +3 -2
  38. package/dist/platforms/index.js.map +1 -1
  39. package/dist/platforms/schema.d.ts +204 -0
  40. package/dist/platforms/schema.js +11 -0
  41. package/dist/platforms/schema.js.map +1 -1
  42. package/dist/sampling.d.ts +1 -0
  43. package/dist/sampling.js +28 -3
  44. package/dist/sampling.js.map +1 -1
  45. package/dist/server.d.ts +14 -1
  46. package/dist/server.js +97 -85
  47. package/dist/server.js.map +1 -1
  48. package/dist/site-url.d.ts +1 -0
  49. package/dist/site-url.js +4 -0
  50. package/dist/site-url.js.map +1 -0
  51. package/dist/tools/assess_hackability.d.ts +2 -33
  52. package/dist/tools/assess_hackability.js +11 -83
  53. package/dist/tools/assess_hackability.js.map +1 -1
  54. package/dist/tools/get_build_plan.d.ts +6 -0
  55. package/dist/tools/get_build_plan.js +16 -0
  56. package/dist/tools/get_build_plan.js.map +1 -0
  57. package/dist/tools/plan_gadget.d.ts +2 -64
  58. package/dist/tools/plan_gadget.js +9 -401
  59. package/dist/tools/plan_gadget.js.map +1 -1
  60. package/dist/tools/propose_hardware.d.ts +3 -0
  61. package/dist/tools/propose_hardware.js +23 -10
  62. package/dist/tools/propose_hardware.js.map +1 -1
  63. package/package.json +1 -1
  64. package/platforms.json +352 -21
@@ -0,0 +1,153 @@
1
+ export type FeatureValue = boolean | string | number | null;
2
+ export interface DeviceEntry {
3
+ id: string;
4
+ name: string;
5
+ buy_url?: string;
6
+ firmware_links: string[];
7
+ est_used_price_usd_min?: number;
8
+ est_used_price_usd_max?: number;
9
+ est_setup_hours_min?: number;
10
+ est_setup_hours_max?: number;
11
+ }
12
+ export interface PlatformBoardPart {
13
+ name: string;
14
+ qty: number;
15
+ required: boolean;
16
+ note: string;
17
+ buy_url?: string;
18
+ search?: string;
19
+ est_price_usd?: number;
20
+ }
21
+ export interface PlatformBoard {
22
+ device_id: string;
23
+ support: "official" | "possible";
24
+ tier: string;
25
+ kind: string;
26
+ build: string;
27
+ eol?: boolean;
28
+ note: string;
29
+ features: Record<string, FeatureValue>;
30
+ parts: PlatformBoardPart[];
31
+ try_saying: string[];
32
+ }
33
+ export interface Platform {
34
+ id: string;
35
+ name: string;
36
+ homepage: string;
37
+ sdk_repo: string;
38
+ sdk_path: string;
39
+ docs_url: string;
40
+ toolchain: string;
41
+ setup_steps: string[];
42
+ tiers: Array<{
43
+ id: string;
44
+ label: string;
45
+ description: string;
46
+ }>;
47
+ caveats: string[];
48
+ terms: {
49
+ url: string;
50
+ summary: string;
51
+ max_devices_per_token: number;
52
+ selling_allowed: boolean;
53
+ };
54
+ }
55
+ export interface Printable {
56
+ part: "desk-stand" | "enclosure";
57
+ title: string;
58
+ stl_url: string;
59
+ step_url: string;
60
+ svg_url: string;
61
+ fab_url: string;
62
+ fab?: {
63
+ print?: {
64
+ orientation?: string;
65
+ supports?: boolean;
66
+ material?: string;
67
+ layer_mm?: number;
68
+ infill_pct?: number;
69
+ };
70
+ params?: {
71
+ clearance?: number;
72
+ cable_d?: number;
73
+ plug_overmold?: number[];
74
+ tilt_deg?: number;
75
+ };
76
+ checks?: Record<string, boolean | null>;
77
+ caveats?: string[];
78
+ };
79
+ }
80
+ export interface BuildPlanPart {
81
+ id: string;
82
+ name: string;
83
+ qty: number;
84
+ required: boolean;
85
+ note: string;
86
+ buy_url: string | null;
87
+ search_url: string | null;
88
+ kind: "board" | "part" | "printed";
89
+ est_price_usd: number | null;
90
+ }
91
+ export interface BuildPlanStep {
92
+ id: string;
93
+ title: string;
94
+ why: string;
95
+ body_md: string;
96
+ commands: string[];
97
+ links: Array<{
98
+ label: string;
99
+ url: string;
100
+ }>;
101
+ }
102
+ export interface AssemblyStep {
103
+ id: string;
104
+ order: number;
105
+ action: "print" | "place" | "insert" | "connect" | "route_cable" | "fasten" | "power" | "flash" | "pair" | "verify";
106
+ part_ids: string[];
107
+ tools: string[];
108
+ instruction: string;
109
+ check: string;
110
+ robot: {
111
+ feasible: boolean;
112
+ notes: string;
113
+ };
114
+ }
115
+ export interface ShoppingList {
116
+ items: Array<{
117
+ part_id: string;
118
+ name: string;
119
+ qty: number;
120
+ url: string | null;
121
+ url_kind: "buy" | "search";
122
+ est_price_usd: number | null;
123
+ required: boolean;
124
+ }>;
125
+ est_total_usd: number | null;
126
+ currency: "USD";
127
+ purchase_policy: string;
128
+ }
129
+ export interface BuildPlan {
130
+ device_id: string;
131
+ name: string;
132
+ platform_id: string | null;
133
+ tier_label: string | null;
134
+ summary: string;
135
+ est_cost_label: string | null;
136
+ est_time_label: string | null;
137
+ parts: BuildPlanPart[];
138
+ shopping_list: ShoppingList;
139
+ steps: BuildPlanStep[];
140
+ assembly: AssemblyStep[];
141
+ try_saying: string[];
142
+ caveats: string[];
143
+ terms: {
144
+ summary: string;
145
+ url: string;
146
+ } | null;
147
+ agent_brief_md: string;
148
+ urls: {
149
+ build_page: string;
150
+ build_md: string;
151
+ muse_page: string | null;
152
+ };
153
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/build-plan/types.ts"],"names":[],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const Category: z.ZodEnum<["display", "speaker", "input", "sensor", "bulb", "sbc", "handheld", "mini-pc", "wearable", "router", "other"]>;
3
- export declare const Provenance: z.ZodEnum<["founder-verified", "community-reported", "llm-inferred"]>;
3
+ export declare const Provenance: z.ZodEnum<["founder-verified", "community-reported", "llm-inferred", "vendor-docs"]>;
4
4
  export declare const CommunitySize: z.ZodEnum<["tiny", "small", "active", "thriving"]>;
5
5
  export declare const Physical: z.ZodEffects<z.ZodObject<{
6
6
  orientation: z.ZodEnum<["upright", "flat"]>;
@@ -138,13 +138,14 @@ export declare const DeviceEntry: z.ZodObject<{
138
138
  idea_fit_tags: z.ZodArray<z.ZodString, "many">;
139
139
  hack_difficulty: z.ZodNumber;
140
140
  brick_risk: z.ZodNumber;
141
- brick_provenance: z.ZodEnum<["founder-verified", "community-reported", "llm-inferred"]>;
141
+ brick_provenance: z.ZodEnum<["founder-verified", "community-reported", "llm-inferred", "vendor-docs"]>;
142
142
  last_verified: z.ZodString;
143
143
  firmware_links: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
144
144
  community_size_bucket: z.ZodEnum<["tiny", "small", "active", "thriving"]>;
145
145
  notes: z.ZodString;
146
146
  est_used_price_usd_min: z.ZodOptional<z.ZodNumber>;
147
147
  est_used_price_usd_max: z.ZodOptional<z.ZodNumber>;
148
+ buy_url: z.ZodOptional<z.ZodString>;
148
149
  image_url: z.ZodOptional<z.ZodString>;
149
150
  est_setup_hours_min: z.ZodOptional<z.ZodNumber>;
150
151
  est_setup_hours_max: z.ZodOptional<z.ZodNumber>;
@@ -284,13 +285,14 @@ export declare const DeviceEntry: z.ZodObject<{
284
285
  idea_fit_tags: string[];
285
286
  hack_difficulty: number;
286
287
  brick_risk: number;
287
- brick_provenance: "founder-verified" | "community-reported" | "llm-inferred";
288
+ brick_provenance: "founder-verified" | "community-reported" | "llm-inferred" | "vendor-docs";
288
289
  last_verified: string;
289
290
  firmware_links: string[];
290
291
  community_size_bucket: "tiny" | "small" | "active" | "thriving";
291
292
  notes: string;
292
293
  est_used_price_usd_min?: number | undefined;
293
294
  est_used_price_usd_max?: number | undefined;
295
+ buy_url?: string | undefined;
294
296
  image_url?: string | undefined;
295
297
  est_setup_hours_min?: number | undefined;
296
298
  est_setup_hours_max?: number | undefined;
@@ -324,13 +326,14 @@ export declare const DeviceEntry: z.ZodObject<{
324
326
  idea_fit_tags: string[];
325
327
  hack_difficulty: number;
326
328
  brick_risk: number;
327
- brick_provenance: "founder-verified" | "community-reported" | "llm-inferred";
329
+ brick_provenance: "founder-verified" | "community-reported" | "llm-inferred" | "vendor-docs";
328
330
  last_verified: string;
329
331
  community_size_bucket: "tiny" | "small" | "active" | "thriving";
330
332
  notes: string;
331
333
  firmware_links?: string[] | undefined;
332
334
  est_used_price_usd_min?: number | undefined;
333
335
  est_used_price_usd_max?: number | undefined;
336
+ buy_url?: string | undefined;
334
337
  image_url?: string | undefined;
335
338
  est_setup_hours_min?: number | undefined;
336
339
  est_setup_hours_max?: number | undefined;
@@ -369,13 +372,14 @@ export declare const Catalog: z.ZodArray<z.ZodObject<{
369
372
  idea_fit_tags: z.ZodArray<z.ZodString, "many">;
370
373
  hack_difficulty: z.ZodNumber;
371
374
  brick_risk: z.ZodNumber;
372
- brick_provenance: z.ZodEnum<["founder-verified", "community-reported", "llm-inferred"]>;
375
+ brick_provenance: z.ZodEnum<["founder-verified", "community-reported", "llm-inferred", "vendor-docs"]>;
373
376
  last_verified: z.ZodString;
374
377
  firmware_links: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
375
378
  community_size_bucket: z.ZodEnum<["tiny", "small", "active", "thriving"]>;
376
379
  notes: z.ZodString;
377
380
  est_used_price_usd_min: z.ZodOptional<z.ZodNumber>;
378
381
  est_used_price_usd_max: z.ZodOptional<z.ZodNumber>;
382
+ buy_url: z.ZodOptional<z.ZodString>;
379
383
  image_url: z.ZodOptional<z.ZodString>;
380
384
  est_setup_hours_min: z.ZodOptional<z.ZodNumber>;
381
385
  est_setup_hours_max: z.ZodOptional<z.ZodNumber>;
@@ -515,13 +519,14 @@ export declare const Catalog: z.ZodArray<z.ZodObject<{
515
519
  idea_fit_tags: string[];
516
520
  hack_difficulty: number;
517
521
  brick_risk: number;
518
- brick_provenance: "founder-verified" | "community-reported" | "llm-inferred";
522
+ brick_provenance: "founder-verified" | "community-reported" | "llm-inferred" | "vendor-docs";
519
523
  last_verified: string;
520
524
  firmware_links: string[];
521
525
  community_size_bucket: "tiny" | "small" | "active" | "thriving";
522
526
  notes: string;
523
527
  est_used_price_usd_min?: number | undefined;
524
528
  est_used_price_usd_max?: number | undefined;
529
+ buy_url?: string | undefined;
525
530
  image_url?: string | undefined;
526
531
  est_setup_hours_min?: number | undefined;
527
532
  est_setup_hours_max?: number | undefined;
@@ -555,13 +560,14 @@ export declare const Catalog: z.ZodArray<z.ZodObject<{
555
560
  idea_fit_tags: string[];
556
561
  hack_difficulty: number;
557
562
  brick_risk: number;
558
- brick_provenance: "founder-verified" | "community-reported" | "llm-inferred";
563
+ brick_provenance: "founder-verified" | "community-reported" | "llm-inferred" | "vendor-docs";
559
564
  last_verified: string;
560
565
  community_size_bucket: "tiny" | "small" | "active" | "thriving";
561
566
  notes: string;
562
567
  firmware_links?: string[] | undefined;
563
568
  est_used_price_usd_min?: number | undefined;
564
569
  est_used_price_usd_max?: number | undefined;
570
+ buy_url?: string | undefined;
565
571
  image_url?: string | undefined;
566
572
  est_setup_hours_min?: number | undefined;
567
573
  est_setup_hours_max?: number | undefined;
@@ -16,6 +16,7 @@ export const Provenance = z.enum([
16
16
  "founder-verified",
17
17
  "community-reported",
18
18
  "llm-inferred",
19
+ "vendor-docs",
19
20
  ]);
20
21
  export const CommunitySize = z.enum(["tiny", "small", "active", "thriving"]);
21
22
  const UsbFace = z.enum(["front", "back", "top", "bottom", "left", "right"]);
@@ -73,6 +74,7 @@ export const DeviceEntry = z.object({
73
74
  notes: z.string().max(500, "notes capped at 500 chars to discourage dumping"),
74
75
  est_used_price_usd_min: z.number().int().nonnegative().optional(),
75
76
  est_used_price_usd_max: z.number().int().nonnegative().optional(),
77
+ buy_url: z.string().url().optional(),
76
78
  image_url: z.string().url().optional(),
77
79
  est_setup_hours_min: z.number().nonnegative().optional(),
78
80
  est_setup_hours_max: z.number().nonnegative().optional(),
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/catalog/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/catalog/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ import type { AgentPlatform, CoreContext, DeviceEntry, DeviceLinks, Platform, Printable } from "./types.js";
3
+ export declare const assessHackabilityInput: z.ZodObject<{
4
+ device_name: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ device_name: string;
7
+ }, {
8
+ device_name: string;
9
+ }>;
10
+ export type AssessInput = z.infer<typeof assessHackabilityInput>;
11
+ export interface AssessOutput {
12
+ found: boolean;
13
+ device?: {
14
+ id: string;
15
+ name: string;
16
+ category: string;
17
+ hackable: boolean;
18
+ hack_difficulty: number;
19
+ brick_risk: number | null;
20
+ brick_risk_label: string;
21
+ brick_risk_disclaimer: string | null;
22
+ firmware_links: string[];
23
+ community_size: string;
24
+ last_verified: string;
25
+ notes: string;
26
+ links: DeviceLinks;
27
+ build_page_url: string;
28
+ agent_platforms: AgentPlatform[];
29
+ physical: DeviceEntry["physical"] | null;
30
+ printables: Printable[];
31
+ next_steps: string[];
32
+ };
33
+ message?: string;
34
+ }
35
+ export declare function assessHackability(input: AssessInput, ctx: CoreContext): AssessOutput;
36
+ export declare function agentPlatformsFor(deviceId: string, platforms: Platform[]): AgentPlatform[];
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ import { buildUrls } from "../build-plan/index.js";
3
+ import { buildLinks } from "./links.js";
4
+ import { applyBrickRiskSafety } from "./safety.js";
5
+ export const assessHackabilityInput = z.object({
6
+ device_name: z.string().min(1).max(200),
7
+ });
8
+ function norm(s) {
9
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, "");
10
+ }
11
+ export function assessHackability(input, ctx) {
12
+ const target = norm(input.device_name);
13
+ let match = ctx.catalog.find((d) => d.id === input.device_name);
14
+ if (!match)
15
+ match = ctx.catalog.find((d) => norm(d.name) === target);
16
+ if (!match && target.length > 0) {
17
+ const candidates = ctx.catalog.filter((d) => norm(d.name).includes(target));
18
+ if (candidates.length === 1) {
19
+ match = candidates[0];
20
+ }
21
+ else if (candidates.length > 1) {
22
+ const sorted = [...candidates].sort((a, b) => {
23
+ const la = norm(a.name).length;
24
+ const lb = norm(b.name).length;
25
+ if (la !== lb)
26
+ return la - lb;
27
+ if (a.name !== b.name)
28
+ return a.name.localeCompare(b.name);
29
+ return a.id.localeCompare(b.id);
30
+ });
31
+ match = sorted[0];
32
+ }
33
+ }
34
+ if (!match) {
35
+ return {
36
+ found: false,
37
+ message: `"${input.device_name}" is not in the catalog. Cannot assess hackability without verification. Try a more specific name, or check the firmware links section of similar devices.`,
38
+ };
39
+ }
40
+ const safety = applyBrickRiskSafety(match);
41
+ const links = buildLinks(match);
42
+ const agentPlatforms = agentPlatformsFor(match.id, ctx.platforms);
43
+ const hackable = match.firmware_links.length > 0 || match.hack_difficulty <= 4;
44
+ const urls = buildUrls(match.id, ctx.siteUrl, agentPlatforms.length > 0);
45
+ const nextSteps = agentPlatforms.length > 0
46
+ ? [
47
+ `Start a build at ${urls.build_page} to save the parts list, checklist and agent brief to My builds.`,
48
+ ]
49
+ : [];
50
+ return {
51
+ found: true,
52
+ device: {
53
+ id: match.id,
54
+ name: match.name,
55
+ category: match.category,
56
+ hackable,
57
+ hack_difficulty: match.hack_difficulty,
58
+ brick_risk: safety.brick_risk,
59
+ brick_risk_label: safety.brick_risk_label,
60
+ brick_risk_disclaimer: safety.brick_risk_disclaimer,
61
+ firmware_links: match.firmware_links,
62
+ community_size: match.community_size_bucket,
63
+ last_verified: match.last_verified,
64
+ notes: match.notes,
65
+ links,
66
+ build_page_url: urls.build_page,
67
+ agent_platforms: agentPlatforms,
68
+ physical: match.physical ?? null,
69
+ printables: ctx.printablesFor(match, ctx.siteUrl),
70
+ next_steps: nextSteps,
71
+ },
72
+ };
73
+ }
74
+ export function agentPlatformsFor(deviceId, platforms) {
75
+ const matches = [];
76
+ for (const platform of platforms) {
77
+ const tierLabels = new Map(platform.tiers.map((tier) => [tier.id, tier.label]));
78
+ for (const board of platform.boards) {
79
+ if (board.device_id !== deviceId)
80
+ continue;
81
+ matches.push(toAgentPlatform(platform, board, tierLabels));
82
+ }
83
+ }
84
+ return matches;
85
+ }
86
+ function toAgentPlatform(platform, board, tierLabels) {
87
+ return {
88
+ platform_id: platform.id,
89
+ platform_name: platform.name,
90
+ support: board.support,
91
+ tier: board.tier,
92
+ tier_label: tierLabels.get(board.tier) ?? board.tier,
93
+ kind: board.kind,
94
+ build: board.build,
95
+ ...(board.eol ? { eol: board.eol } : {}),
96
+ features: board.features,
97
+ note: board.note,
98
+ };
99
+ }
100
+ //# sourceMappingURL=assess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assess.js","sourceRoot":"","sources":["../../src/core/assess.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export declare function formatInputError(toolName: string, zodError: z.ZodError): string;
@@ -0,0 +1,70 @@
1
+ import { NEED_VALUES } from "./types.js";
2
+ const FIELD_LABELS = {
3
+ idea: "`idea`",
4
+ limit: "`limit`",
5
+ needs: "`needs`",
6
+ platform: "`platform`",
7
+ budget_usd: "`budget_usd`",
8
+ owned_device_ids: "`owned_device_ids`",
9
+ device_id: "`device_id`",
10
+ device_name: "`device_name`",
11
+ size: "`size`",
12
+ };
13
+ export function formatInputError(toolName, zodError) {
14
+ return zodError.issues
15
+ .map((issue) => formatIssue(issue))
16
+ .join(" ");
17
+ }
18
+ function formatIssue(issue) {
19
+ const path = issue.path.map(String);
20
+ const field = fieldLabel(path);
21
+ if (issue.code === "invalid_enum_value") {
22
+ const options = issue.options.map(String);
23
+ return `${field} must be one of: ${options.join(", ")} (got ${JSON.stringify(issue.received)}).`;
24
+ }
25
+ if (issue.code === "too_small") {
26
+ if (issue.type === "string") {
27
+ return `${field} must be at least ${issue.minimum} characters.`;
28
+ }
29
+ if (issue.type === "number") {
30
+ return `${field} must be at least ${issue.minimum}.`;
31
+ }
32
+ if (issue.type === "array") {
33
+ return `${field} must include at least ${issue.minimum} item${issue.minimum === 1 ? "" : "s"}.`;
34
+ }
35
+ }
36
+ if (issue.code === "too_big") {
37
+ if (issue.type === "string") {
38
+ return `${field} must be at most ${issue.maximum} characters.`;
39
+ }
40
+ if (issue.type === "number") {
41
+ const got = typeof issue.path.at(-1) === "number" ? "" : "";
42
+ return `${field} must be at most ${issue.maximum}${got}.`;
43
+ }
44
+ if (issue.type === "array") {
45
+ return `${field} must include at most ${issue.maximum} items.`;
46
+ }
47
+ }
48
+ if (issue.code === "invalid_type") {
49
+ return `${field} must be ${issue.expected}.`;
50
+ }
51
+ if (issue.code === "custom") {
52
+ return `${field} ${issue.message}.`;
53
+ }
54
+ if (path[0] === "needs") {
55
+ return `${field} must be one of: ${NEED_VALUES.join(", ")}.`;
56
+ }
57
+ return `${field} is invalid: ${issue.message}.`;
58
+ }
59
+ function fieldLabel(path) {
60
+ if (path.length === 0)
61
+ return "input";
62
+ const [first, ...rest] = path;
63
+ if (!first)
64
+ return "input";
65
+ const base = FIELD_LABELS[first] ?? `\`${first}\``;
66
+ if (rest.length === 0)
67
+ return base;
68
+ return `\`${[first, ...rest].join(".").replace(/\.(\d+)/g, "[$1]")}\``;
69
+ }
70
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { DeviceEntry, DeviceLinks } from "./types.js";
2
+ export declare function buildEbayQuery(device: DeviceEntry): string;
3
+ export declare function buildLinks(device: DeviceEntry): DeviceLinks;
@@ -0,0 +1,19 @@
1
+ function ebayCondition(brickRisk) {
2
+ if (brickRisk === null)
3
+ return "used";
4
+ return brickRisk >= 4 ? "working" : "used";
5
+ }
6
+ export function buildEbayQuery(device) {
7
+ const cond = ebayCondition(device.brick_risk);
8
+ return `${device.name} ${cond}`;
9
+ }
10
+ export function buildLinks(device) {
11
+ const ebayQuery = buildEbayQuery(device);
12
+ return {
13
+ ebay_search_url: `https://www.ebay.com/sch/i.html?_nkw=${encodeURIComponent(ebayQuery)}&_sop=15`,
14
+ hackaday_search_url: `https://hackaday.com/?s=${encodeURIComponent(device.name)}`,
15
+ reddit_search_url: `https://www.reddit.com/search/?q=${encodeURIComponent(`${device.name} hack`)}&sort=new`,
16
+ google_search_url: `https://www.google.com/search?q=${encodeURIComponent(`${device.name} custom firmware OR hack OR mod`)}`,
17
+ };
18
+ }
19
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/core/links.ts"],"names":[],"mappings":"AAEA,SAAS,aAAa,CAAC,SAAwB;IAC7C,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9C,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO;QACL,eAAe,EAAE,wCAAwC,kBAAkB,CAAC,SAAS,CAAC,UAAU;QAChG,mBAAmB,EAAE,2BAA2B,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QACjF,iBAAiB,EAAE,oCAAoC,kBAAkB,CAAC,GAAG,MAAM,CAAC,IAAI,OAAO,CAAC,WAAW;QAC3G,iBAAiB,EAAE,mCAAmC,kBAAkB,CAAC,GAAG,MAAM,CAAC,IAAI,iCAAiC,CAAC,EAAE;KAC5H,CAAC;AACJ,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { z } from "zod";
2
+ import { NEED_VALUES, type CoreContext, type Need, type Printable, type Size } from "./types.js";
3
+ export { NEED_VALUES, type Need, type Size };
4
+ export declare const planGadgetInput: z.ZodObject<{
5
+ idea: z.ZodString;
6
+ platform: z.ZodDefault<z.ZodEnum<["muse-esp32", "muse-linux", "any"]>>;
7
+ budget_usd: z.ZodOptional<z.ZodNumber>;
8
+ owned_device_ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ needs: z.ZodOptional<z.ZodArray<z.ZodEnum<["voice", "screen", "images", "touch", "camera", "air-sensors", "e-ink", "battery", "round", "home-tunnel", "big-screen", "compute", "linux"]>, "many">>;
10
+ size: z.ZodDefault<z.ZodEnum<["pocket", "desk", "wall", "any"]>>;
11
+ limit: z.ZodDefault<z.ZodNumber>;
12
+ }, "strip", z.ZodTypeAny, {
13
+ size: "pocket" | "desk" | "wall" | "any";
14
+ idea: string;
15
+ platform: "any" | "muse-esp32" | "muse-linux";
16
+ limit: number;
17
+ budget_usd?: number | undefined;
18
+ needs?: ("round" | "e-ink" | "battery" | "voice" | "compute" | "linux" | "screen" | "images" | "touch" | "camera" | "air-sensors" | "home-tunnel" | "big-screen")[] | undefined;
19
+ owned_device_ids?: string[] | undefined;
20
+ }, {
21
+ idea: string;
22
+ size?: "pocket" | "desk" | "wall" | "any" | undefined;
23
+ budget_usd?: number | undefined;
24
+ platform?: "any" | "muse-esp32" | "muse-linux" | undefined;
25
+ limit?: number | undefined;
26
+ needs?: ("round" | "e-ink" | "battery" | "voice" | "compute" | "linux" | "screen" | "images" | "touch" | "camera" | "air-sensors" | "home-tunnel" | "big-screen")[] | undefined;
27
+ owned_device_ids?: string[] | undefined;
28
+ }>;
29
+ export type PlanGadgetInput = z.infer<typeof planGadgetInput>;
30
+ export interface PlanGadgetQuestion {
31
+ id: string;
32
+ question: string;
33
+ why: string;
34
+ options: Array<{
35
+ label: string;
36
+ value: string;
37
+ needs?: Need[];
38
+ budget_usd?: number;
39
+ size?: Size;
40
+ }>;
41
+ }
42
+ export interface PlanGadgetOutput {
43
+ inferred_needs: Need[];
44
+ inferred_preferences: InferredPreference[];
45
+ fit: "all" | "partial" | "none";
46
+ notes: string[];
47
+ warnings: string[];
48
+ questions: PlanGadgetQuestion[];
49
+ picks: Array<{
50
+ device_id: string;
51
+ name: string;
52
+ platform_id: string;
53
+ platform_name: string;
54
+ support: "official" | "possible";
55
+ tier: string;
56
+ tier_label: string;
57
+ score: number;
58
+ why: string;
59
+ gaps: string[];
60
+ needs_met: Need[];
61
+ within_budget: boolean | null;
62
+ price_label: string | null;
63
+ build_page_url: string;
64
+ agent_brief_url: string;
65
+ links: string[];
66
+ build_command: string;
67
+ setup_steps: string[];
68
+ caveats: string[];
69
+ fabrication: {
70
+ printables: Printable[];
71
+ note: string;
72
+ };
73
+ }>;
74
+ terms: Array<{
75
+ platform_id: string;
76
+ summary: string;
77
+ url: string;
78
+ max_devices_per_token: number;
79
+ selling_allowed: boolean;
80
+ }>;
81
+ next_steps: string[];
82
+ }
83
+ type InferredPreference = "cheap";
84
+ export declare function planGadget(input: PlanGadgetInput, ctx: CoreContext): PlanGadgetOutput;
85
+ export declare function inferNeeds(idea: string): Need[];