@tempad-dev/mcp 0.2.1 → 0.3.0

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 CHANGED
@@ -13,13 +13,29 @@
13
13
  }
14
14
  ```
15
15
 
16
+ Quick setup helpers:
17
+
18
+ - VS Code / Cursor / TRAE: use the deep links in TemPad Dev (Preferences → MCP server).
19
+ - Windsurf: copy the JSON snippet from the same panel.
20
+ - CLI: `claude mcp add --transport stdio "TemPad Dev" -- npx -y @tempad-dev/mcp` or `codex mcp add "TemPad Dev" -- npx -y @tempad-dev/mcp`.
21
+
22
+ Supported tools/resources:
23
+
24
+ - `get_code`: Tailwind-first JSX/Vue markup plus assets and token references.
25
+ - `get_structure`: Hierarchy/geometry outline for the selection.
26
+ - `get_screenshot`: PNG capture with a downloadable asset link.
27
+ - `tempad-assets` resource template (`asset://tempad/{hash}`) for binaries referenced by tool responses.
28
+
16
29
  ## Configuration
17
30
 
18
31
  Optional environment variables:
19
32
 
20
33
  - `TEMPAD_MCP_TOOL_TIMEOUT`: Tool call timeout in milliseconds (default `15000`).
34
+ - `TEMPAD_MCP_AUTO_ACTIVATE_GRACE`: Delay before auto-activating the sole connected extension (default `1500`).
35
+ - `TEMPAD_MCP_MAX_ASSET_BYTES`: Maximum upload size for captured assets/screenshots in bytes (default `8388608`).
21
36
  - `TEMPAD_MCP_RUNTIME_DIR`: Override runtime directory (defaults to system temp under `tempad-dev/run`).
22
37
  - `TEMPAD_MCP_LOG_DIR`: Override log directory (defaults to system temp under `tempad-dev/log`).
38
+ - `TEMPAD_MCP_ASSET_DIR`: Override asset storage directory (defaults to system temp under `tempad-dev/assets`).
23
39
 
24
40
  ## Requirements
25
41
 
package/dist/hub.js CHANGED
@@ -593,13 +593,47 @@ function cleanupAll() {
593
593
 
594
594
  // src/tools.ts
595
595
  import { z as z2 } from "zod";
596
+
597
+ // src/instructions.ts
598
+ var MCP_INSTRUCTIONS = `
599
+ ## MCP Server Instructions (Design to Code)
600
+
601
+ You are connected to a Figma design file via the MCP server. Help convert design elements into code, preserving design intent and fitting the user\u2019s codebase conventions.
602
+
603
+ ### P0 (must)
604
+
605
+ - Do not output \`data-hint*\` attributes. They are guidance only.
606
+ - For SVG/vector assets: use the exact provided asset (preserve \`path\` data and \`viewBox\`). Never redraw or approximate vectors.
607
+
608
+ ### P1 (policy)
609
+
610
+ - Prefer calling \`get_structure\` early to understand hierarchy and layout intent.
611
+ - Treat \`get_code\` as the implementation baseline; refine it to match the current project\u2019s conventions.
612
+ - Use \`get_screenshot\` only when structure and hints cannot resolve major ambiguities, or to sanity-check the final result.
613
+
614
+ ### Layout uncertainty (\`data-hint-auto-layout\`)
615
+
616
+ - If \`data-hint-auto-layout\` is \`none\` or \`inferred\`, treat layout as uncertain.
617
+ - Use \`get_structure\` geometry (positions, sizes, gaps, alignment, bounds) to choose layout. Prefer flex/grid when patterns support it; use absolute only when necessary.
618
+
619
+ ### Component intent (\`data-hint-component\`)
620
+
621
+ - If \`data-hint-component\` suggests a reusable component/variant and repetition supports it, factor it into a component API (props/variants). Do not preserve the hint string in output.
622
+
623
+ ### Assets and tokens
624
+
625
+ - If \`get_code\` references assets or tokens, handle them according to the current project\u2019s conventions (local asset paths, existing token/variable systems, theming rules).
626
+ `.trim();
627
+
628
+ // src/tools.ts
596
629
  var GetCodeParametersSchema = z2.object({
597
- nodeId: z2.string().optional(),
598
- preferredLang: z2.enum(["jsx", "vue"]).optional(),
599
- resolveTokens: z2.boolean().optional()
630
+ nodeId: z2.string().describe("Optional node id to target; defaults to the current single selection.").optional(),
631
+ preferredLang: z2.enum(["jsx", "vue"]).describe("Preferred output language; otherwise uses the design\u2019s hint/detected language, then JSX.").optional(),
632
+ resolveTokens: z2.boolean().describe("Resolve token references to concrete values; default false returns token metadata.").optional()
600
633
  });
601
634
  var GetTokenDefsParametersSchema = z2.object({
602
- nodeId: z2.string().optional()
635
+ names: z2.array(z2.string().regex(/^--[a-zA-Z0-9-_]+$/)).min(1).describe("Canonical token names (CSS variable form) to resolve, e.g., --color-primary."),
636
+ includeAllModes: z2.boolean().describe("Include all token modes instead of just the active one; default false.").optional()
603
637
  });
604
638
  var AssetDescriptorSchema = z2.object({
605
639
  hash: z2.string().min(1),
@@ -611,43 +645,198 @@ var AssetDescriptorSchema = z2.object({
611
645
  height: z2.number().int().positive().optional()
612
646
  });
613
647
  var GetScreenshotParametersSchema = z2.object({
614
- nodeId: z2.string().optional()
648
+ nodeId: z2.string().describe("Optional node id to screenshot; defaults to the current single selection.").optional()
615
649
  });
616
650
  var GetStructureParametersSchema = z2.object({
617
- nodeId: z2.string().optional(),
651
+ nodeId: z2.string().describe("Optional node id to outline; defaults to the current single selection.").optional(),
618
652
  options: z2.object({
619
- depth: z2.number().int().positive().optional()
653
+ depth: z2.number().int().positive().describe("Limit traversal depth; defaults to full tree (subject to safety caps).").optional()
620
654
  }).optional()
621
655
  });
622
656
  var GetAssetsParametersSchema = z2.object({
623
- hashes: z2.array(z2.string().regex(MCP_HASH_PATTERN)).min(1)
657
+ hashes: z2.array(z2.string().regex(MCP_HASH_PATTERN)).min(1).describe("Asset hashes returned from other tools to download/resolve.")
624
658
  });
625
659
  var GetAssetsResultSchema = z2.object({
626
660
  assets: z2.array(AssetDescriptorSchema),
627
661
  missing: z2.array(z2.string().min(1))
628
662
  });
629
- var TOOLS = [
630
- {
663
+ function extTool(definition) {
664
+ return definition;
665
+ }
666
+ function hubTool(definition) {
667
+ return definition;
668
+ }
669
+ var TOOL_DEFS = [
670
+ extTool({
631
671
  name: "get_code",
632
- description: "High fidelity code snapshot for the current selection or provided node ids.",
633
- parameters: GetCodeParametersSchema
634
- },
635
- {
672
+ description: "Get a high-fidelity code snapshot for a nodeId (or current selection), including assets/usedTokens and `codegen` preset/config.",
673
+ parameters: GetCodeParametersSchema,
674
+ target: "extension",
675
+ format: createCodeToolResponse
676
+ }),
677
+ extTool({
636
678
  name: "get_token_defs",
637
- description: "Token definitions referenced by the current selection or provided node ids.",
638
- parameters: GetTokenDefsParametersSchema
639
- },
640
- {
679
+ description: "Resolve canonical token names to values (including modes) for tokens referenced by `get_code`.",
680
+ parameters: GetTokenDefsParametersSchema,
681
+ target: "extension",
682
+ exposed: false
683
+ }),
684
+ extTool({
641
685
  name: "get_screenshot",
642
- description: "Rendered screenshot for the requested node.",
643
- parameters: GetScreenshotParametersSchema
644
- },
645
- {
686
+ description: "Capture a rendered screenshot for a nodeId (or current selection) for visual verification.",
687
+ parameters: GetScreenshotParametersSchema,
688
+ target: "extension",
689
+ format: createScreenshotToolResponse
690
+ }),
691
+ extTool({
646
692
  name: "get_structure",
647
- description: "Structural outline of the current selection or provided node ids.",
648
- parameters: GetStructureParametersSchema
649
- }
693
+ description: "Get a structural + geometry outline for a nodeId (or current selection) to understand hierarchy and layout intent.",
694
+ parameters: GetStructureParametersSchema,
695
+ target: "extension"
696
+ }),
697
+ hubTool({
698
+ name: "get_assets",
699
+ description: "Resolve asset hashes to downloadable URLs/URIs for assets referenced by `get_code`.",
700
+ parameters: GetAssetsParametersSchema,
701
+ target: "hub",
702
+ outputSchema: GetAssetsResultSchema,
703
+ exposed: false
704
+ })
650
705
  ];
706
+ function createToolErrorResponse(toolName, error) {
707
+ const message = error instanceof Error ? error.message || "Unknown error occurred." : typeof error === "string" ? error : "Unknown error occurred.";
708
+ return {
709
+ content: [
710
+ {
711
+ type: "text",
712
+ text: `Tool "${toolName}" failed: ${message}`
713
+ }
714
+ ]
715
+ };
716
+ }
717
+ function formatBytes(bytes) {
718
+ if (bytes < 1024) return `${bytes} B`;
719
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
720
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
721
+ }
722
+ function createCodeToolResponse(payload) {
723
+ if (!isCodeResult(payload)) {
724
+ throw new Error("Invalid get_code payload received from extension.");
725
+ }
726
+ const normalized = normalizeCodeResult(payload);
727
+ const summary = [];
728
+ const codeSize = Buffer.byteLength(normalized.code, "utf8");
729
+ summary.push(`Generated ${normalized.lang.toUpperCase()} snippet (${formatBytes(codeSize)}).`);
730
+ if (normalized.message) {
731
+ summary.push(normalized.message);
732
+ }
733
+ summary.push(
734
+ normalized.assets.length ? `Assets attached: ${normalized.assets.length}. Fetch bytes via resources/read using resourceUri.` : "No binary assets were attached to this response."
735
+ );
736
+ if (normalized.usedTokens?.length) {
737
+ summary.push(`Token references included: ${normalized.usedTokens.length}.`);
738
+ }
739
+ summary.push("Read structuredContent for the full code string and asset metadata.");
740
+ const assetLinks = normalized.assets.length > 0 ? normalized.assets.map((asset) => createAssetResourceLinkBlock(asset)) : [];
741
+ return {
742
+ content: [
743
+ {
744
+ type: "text",
745
+ text: summary.join("\n")
746
+ },
747
+ ...assetLinks
748
+ ],
749
+ structuredContent: normalized
750
+ };
751
+ }
752
+ function createScreenshotToolResponse(payload) {
753
+ if (!isScreenshotResult(payload)) {
754
+ throw new Error("Invalid get_screenshot payload received from extension.");
755
+ }
756
+ const descriptionBlock = {
757
+ type: "text",
758
+ text: describeScreenshot(payload)
759
+ };
760
+ return {
761
+ content: [
762
+ descriptionBlock,
763
+ {
764
+ type: "text",
765
+ text: `![Screenshot](${payload.asset.url})`
766
+ },
767
+ createResourceLinkBlock(payload.asset, payload)
768
+ ],
769
+ structuredContent: payload
770
+ };
771
+ }
772
+ function createResourceLinkBlock(asset, result) {
773
+ return {
774
+ type: "resource_link",
775
+ name: "Screenshot",
776
+ uri: asset.resourceUri,
777
+ mimeType: asset.mimeType,
778
+ description: `Screenshot ${result.width}x${result.height} @${result.scale}x - Download: ${asset.url}`
779
+ };
780
+ }
781
+ function describeScreenshot(result) {
782
+ return `Screenshot ${result.width}x${result.height} @${result.scale}x (${formatBytes(result.bytes)})`;
783
+ }
784
+ function isScreenshotResult(payload) {
785
+ if (typeof payload !== "object" || !payload) return false;
786
+ const candidate = payload;
787
+ return typeof candidate.asset === "object" && candidate.asset !== null && typeof candidate.width === "number" && typeof candidate.height === "number" && typeof candidate.scale === "number" && typeof candidate.bytes === "number" && typeof candidate.format === "string";
788
+ }
789
+ function isCodeResult(payload) {
790
+ if (typeof payload !== "object" || !payload) return false;
791
+ const candidate = payload;
792
+ return typeof candidate.code === "string" && typeof candidate.lang === "string" && Array.isArray(candidate.assets);
793
+ }
794
+ function normalizeCodeResult(result) {
795
+ const rewrittenCode = rewriteCodeAssetUrls(result.code, result.assets);
796
+ return {
797
+ ...result,
798
+ code: rewrittenCode
799
+ };
800
+ }
801
+ function rewriteCodeAssetUrls(code, assets) {
802
+ let updatedCode = code;
803
+ for (const asset of assets) {
804
+ const uriPattern = new RegExp(escapeRegExp(asset.resourceUri), "g");
805
+ updatedCode = updatedCode.replace(uriPattern, asset.url);
806
+ }
807
+ return updatedCode;
808
+ }
809
+ function createAssetResourceLinkBlock(asset) {
810
+ return {
811
+ type: "resource_link",
812
+ name: formatAssetResourceName(asset.hash),
813
+ uri: asset.resourceUri,
814
+ mimeType: asset.mimeType,
815
+ description: `${describeAsset(asset)} - Download: ${asset.url}`
816
+ };
817
+ }
818
+ function describeAsset(asset) {
819
+ return `${asset.mimeType} (${formatBytes(asset.size)})`;
820
+ }
821
+ function formatAssetResourceName(hash) {
822
+ return `asset:${hash.slice(0, 8)}`;
823
+ }
824
+ function escapeRegExp(value) {
825
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
826
+ }
827
+ function coercePayloadToToolResponse(payload) {
828
+ if (payload && typeof payload === "object" && Array.isArray(payload.content)) {
829
+ return payload;
830
+ }
831
+ return {
832
+ content: [
833
+ {
834
+ type: "text",
835
+ text: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)
836
+ }
837
+ ]
838
+ };
839
+ }
651
840
 
652
841
  // src/hub.ts
653
842
  var SHUTDOWN_TIMEOUT = 2e3;
@@ -656,7 +845,36 @@ var extensions = [];
656
845
  var consumerCount = 0;
657
846
  var autoActivateTimer = null;
658
847
  var selectedWsPort = 0;
659
- var mcp = new McpServer({ name: "tempad-dev-mcp", version: "0.1.0" });
848
+ var mcp = new McpServer(
849
+ { name: "tempad-dev-mcp", version: "0.1.0" },
850
+ MCP_INSTRUCTIONS ? { instructions: MCP_INSTRUCTIONS } : void 0
851
+ );
852
+ function enrichToolDefinition(tool) {
853
+ if (tool.target === "extension") {
854
+ return tool;
855
+ }
856
+ switch (tool.name) {
857
+ case "get_assets":
858
+ return {
859
+ ...tool,
860
+ handler: handleGetAssets
861
+ };
862
+ default:
863
+ throw new Error("No handler configured for hub tool.");
864
+ }
865
+ }
866
+ var TOOL_DEFINITIONS = TOOL_DEFS.map(
867
+ (tool) => enrichToolDefinition(tool)
868
+ );
869
+ function hasFormatter(tool) {
870
+ return tool.target === "extension" && "format" in tool;
871
+ }
872
+ var TOOL_BY_NAME = Object.fromEntries(
873
+ TOOL_DEFINITIONS.map((tool) => [tool.name, tool])
874
+ );
875
+ function getToolDefinition(name) {
876
+ return TOOL_BY_NAME[name];
877
+ }
660
878
  var assetStore = createAssetStore();
661
879
  var assetHttpServer = createAssetHttpServer(assetStore);
662
880
  await assetHttpServer.start();
@@ -666,8 +884,8 @@ function registerAssetResources() {
666
884
  list: async () => ({
667
885
  resources: assetStore.list().filter((record) => existsSync3(record.filePath)).map((record) => ({
668
886
  uri: buildAssetResourceUri(record.hash),
669
- name: formatAssetResourceName(record.hash),
670
- description: `${record.mimeType} (${formatBytes(record.size)})`,
887
+ name: formatAssetResourceName2(record.hash),
888
+ description: `${record.mimeType} (${formatBytes2(record.size)})`,
671
889
  mimeType: record.mimeType
672
890
  }))
673
891
  })
@@ -700,7 +918,7 @@ async function readAssetResource(hash) {
700
918
  const estimatedSize = Math.ceil(stat.size / 3) * 4;
701
919
  if (estimatedSize > maxPayloadBytes) {
702
920
  throw new Error(
703
- `Asset ${hash} is too large (${formatBytes(stat.size)}, encoded: ${formatBytes(estimatedSize)}) to read via MCP protocol. Use HTTP download.`
921
+ `Asset ${hash} is too large (${formatBytes2(stat.size)}, encoded: ${formatBytes2(estimatedSize)}) to read via MCP protocol. Use HTTP download.`
704
922
  );
705
923
  }
706
924
  assetStore.touch(hash);
@@ -733,7 +951,7 @@ function isTextualMime(mimeType) {
733
951
  function buildAssetResourceUri(hash) {
734
952
  return `${MCP_ASSET_URI_PREFIX}${hash}`;
735
953
  }
736
- function formatAssetResourceName(hash) {
954
+ function formatAssetResourceName2(hash) {
737
955
  return `asset:${hash.slice(0, 8)}`;
738
956
  }
739
957
  function buildAssetDescriptor(record) {
@@ -747,72 +965,36 @@ function buildAssetDescriptor(record) {
747
965
  height: record.metadata?.height
748
966
  };
749
967
  }
750
- function createAssetResourceLinkBlock(asset) {
968
+ function createAssetResourceLinkBlock2(asset) {
751
969
  return {
752
970
  type: "resource_link",
753
- name: formatAssetResourceName(asset.hash),
971
+ name: formatAssetResourceName2(asset.hash),
754
972
  uri: asset.resourceUri,
755
973
  mimeType: asset.mimeType,
756
- description: `${describeAsset(asset)} - Download: ${asset.url}`
974
+ description: `${describeAsset2(asset)} - Download: ${asset.url}`
757
975
  };
758
976
  }
759
- function describeAsset(asset) {
760
- return `${asset.mimeType} (${formatBytes(asset.size)})`;
977
+ function describeAsset2(asset) {
978
+ return `${asset.mimeType} (${formatBytes2(asset.size)})`;
761
979
  }
762
- function registerHubTools() {
763
- for (const tool of TOOLS) {
764
- registerExtensionTool(tool);
980
+ function registerTools() {
981
+ const registered = [];
982
+ for (const tool of TOOL_DEFINITIONS) {
983
+ if ("exposed" in tool && tool.exposed === false) continue;
984
+ registerTool(tool);
985
+ registered.push(tool.name);
765
986
  }
766
- mcp.registerTool(
767
- "get_assets",
768
- {
769
- description: "Resolve uploaded asset hashes to downloadable URLs and resource URIs for resources/read calls.",
770
- inputSchema: GetAssetsParametersSchema,
771
- outputSchema: GetAssetsResultSchema
772
- },
773
- async (args) => {
774
- const { hashes } = GetAssetsParametersSchema.parse(args);
775
- if (hashes.length > 100) {
776
- throw new Error("Too many hashes requested. Limit is 100.");
777
- }
778
- const unique = Array.from(new Set(hashes));
779
- const records = assetStore.getMany(unique).filter((record) => {
780
- if (existsSync3(record.filePath)) return true;
781
- assetStore.remove(record.hash, { removeFile: false });
782
- return false;
783
- });
784
- const found = new Set(records.map((record) => record.hash));
785
- const payload = GetAssetsResultSchema.parse({
786
- assets: records.map((record) => buildAssetDescriptor(record)),
787
- missing: unique.filter((hash) => !found.has(hash))
788
- });
789
- const summary = [];
790
- summary.push(
791
- payload.assets.length ? `Resolved ${payload.assets.length} asset${payload.assets.length === 1 ? "" : "s"}.` : "No assets were resolved for the requested hashes."
792
- );
793
- if (payload.missing.length) {
794
- summary.push(`Missing: ${payload.missing.join(", ")}`);
795
- }
796
- summary.push(
797
- "Use resources/read with each resourceUri or fetch the fallback URL to download bytes."
798
- );
799
- const content = [
800
- {
801
- type: "text",
802
- text: summary.join("\n")
803
- },
804
- ...payload.assets.map((asset) => createAssetResourceLinkBlock(asset))
805
- ];
806
- return {
807
- content,
808
- structuredContent: payload
809
- };
810
- }
811
- );
987
+ log.info({ tools: registered }, "Registered tools.");
812
988
  }
813
- registerHubTools();
814
- log.info({ tools: TOOLS.map((t) => t.name) }, "Registered tools.");
815
- function registerExtensionTool(tool) {
989
+ registerTools();
990
+ function registerTool(tool) {
991
+ if (tool.target === "extension") {
992
+ registerProxiedTool(tool);
993
+ } else {
994
+ registerLocalTool(tool);
995
+ }
996
+ }
997
+ function registerProxiedTool(tool) {
816
998
  const schema = tool.parameters;
817
999
  mcp.registerTool(
818
1000
  tool.name,
@@ -821,117 +1003,100 @@ function registerExtensionTool(tool) {
821
1003
  inputSchema: schema
822
1004
  },
823
1005
  async (args) => {
824
- const parsedArgs = schema.parse(args);
825
- const activeExt = extensions.find((e) => e.active);
826
- if (!activeExt) throw new Error("No active TemPad Dev extension available.");
827
- const { promise, requestId } = register(activeExt.id, toolTimeoutMs);
828
- const message = {
829
- type: "toolCall",
830
- id: requestId,
831
- payload: {
832
- name: tool.name,
833
- args: parsedArgs
834
- }
835
- };
836
- activeExt.ws.send(JSON.stringify(message));
837
- log.info({ tool: tool.name, req: requestId, extId: activeExt.id }, "Forwarded tool call.");
838
- const payload = await promise;
839
- return createToolResponse(tool.name, payload);
1006
+ try {
1007
+ const parsedArgs = schema.parse(args);
1008
+ const activeExt = extensions.find((e) => e.active);
1009
+ if (!activeExt) throw new Error("No active TemPad Dev extension available.");
1010
+ const { promise, requestId } = register(activeExt.id, toolTimeoutMs);
1011
+ const message = {
1012
+ type: "toolCall",
1013
+ id: requestId,
1014
+ payload: {
1015
+ name: tool.name,
1016
+ args: parsedArgs
1017
+ }
1018
+ };
1019
+ activeExt.ws.send(JSON.stringify(message));
1020
+ log.info({ tool: tool.name, req: requestId, extId: activeExt.id }, "Forwarded tool call.");
1021
+ const payload = await promise;
1022
+ return createToolResponse(tool.name, payload);
1023
+ } catch (error) {
1024
+ log.error({ tool: tool.name, error }, "Tool invocation failed before reaching extension.");
1025
+ return createToolErrorResponse(tool.name, error);
1026
+ }
840
1027
  }
841
1028
  );
842
1029
  }
843
- function createToolResponse(toolName, payload) {
844
- if (toolName === "get_screenshot") {
1030
+ function registerLocalTool(tool) {
1031
+ const schema = tool.parameters;
1032
+ const handler = tool.handler;
1033
+ const registrationOptions = {
1034
+ description: tool.description,
1035
+ inputSchema: schema
1036
+ };
1037
+ if (tool.outputSchema) {
1038
+ registrationOptions.outputSchema = tool.outputSchema;
1039
+ }
1040
+ mcp.registerTool(tool.name, registrationOptions, async (args) => {
845
1041
  try {
846
- return createScreenshotToolResponse(payload);
1042
+ const parsed = schema.parse(args);
1043
+ return await handler(parsed);
847
1044
  } catch (error) {
848
- log.warn({ error }, "Failed to format get_screenshot result; returning raw payload.");
849
- return coercePayloadToToolResponse(payload);
1045
+ log.error({ tool: tool.name, error }, "Local tool invocation failed.");
1046
+ return createToolErrorResponse(tool.name, error);
850
1047
  }
851
- }
852
- if (toolName === "get_code") {
1048
+ });
1049
+ }
1050
+ function createToolResponse(toolName, payload) {
1051
+ const definition = getToolDefinition(toolName);
1052
+ if (definition && hasFormatter(definition)) {
853
1053
  try {
854
- return createCodeToolResponse(payload);
1054
+ const formatter = definition.format;
1055
+ return formatter(payload);
855
1056
  } catch (error) {
856
- log.warn({ error }, "Failed to format get_code result; returning raw payload.");
1057
+ log.warn({ tool: toolName, error }, "Failed to format tool result; returning raw payload.");
857
1058
  return coercePayloadToToolResponse(payload);
858
1059
  }
859
1060
  }
860
1061
  return coercePayloadToToolResponse(payload);
861
1062
  }
862
- function coercePayloadToToolResponse(payload) {
863
- if (payload && typeof payload === "object" && Array.isArray(payload.content)) {
864
- return payload;
1063
+ async function handleGetAssets({ hashes }) {
1064
+ if (hashes.length > 100) {
1065
+ throw new Error("Too many hashes requested. Limit is 100.");
865
1066
  }
866
- return {
867
- content: [
868
- {
869
- type: "text",
870
- text: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)
871
- }
872
- ]
873
- };
874
- }
875
- function createCodeToolResponse(payload) {
876
- if (!isCodeResult(payload)) {
877
- throw new Error("Invalid get_code payload received from extension.");
878
- }
879
- const normalized = normalizeCodeResult(payload);
1067
+ const unique = Array.from(new Set(hashes));
1068
+ const records = assetStore.getMany(unique).filter((record) => {
1069
+ if (existsSync3(record.filePath)) return true;
1070
+ assetStore.remove(record.hash, { removeFile: false });
1071
+ return false;
1072
+ });
1073
+ const found = new Set(records.map((record) => record.hash));
1074
+ const payload = GetAssetsResultSchema.parse({
1075
+ assets: records.map((record) => buildAssetDescriptor(record)),
1076
+ missing: unique.filter((hash) => !found.has(hash))
1077
+ });
880
1078
  const summary = [];
881
- const codeSize = Buffer.byteLength(normalized.code, "utf8");
882
- summary.push(`Generated ${normalized.lang.toUpperCase()} snippet (${formatBytes(codeSize)}).`);
883
- if (normalized.message) {
884
- summary.push(normalized.message);
885
- }
886
1079
  summary.push(
887
- normalized.assets.length ? `Assets attached: ${normalized.assets.length}. Fetch bytes via resources/read using resourceUri or call get_assets.` : "No binary assets were attached to this response."
1080
+ payload.assets.length ? `Resolved ${payload.assets.length} asset${payload.assets.length === 1 ? "" : "s"}.` : "No assets were resolved for the requested hashes."
888
1081
  );
889
- if (normalized.usedTokens?.length) {
890
- summary.push(`Token references included: ${normalized.usedTokens.length}.`);
1082
+ if (payload.missing.length) {
1083
+ summary.push(`Missing: ${payload.missing.join(", ")}`);
891
1084
  }
892
- summary.push("Read structuredContent for the full code string and asset metadata.");
893
- return {
894
- content: [
895
- {
896
- type: "text",
897
- text: summary.join("\n")
898
- }
899
- ],
900
- structuredContent: normalized
901
- };
902
- }
903
- function isCodeResult(payload) {
904
- if (typeof payload !== "object" || !payload) return false;
905
- const candidate = payload;
906
- return typeof candidate.code === "string" && typeof candidate.lang === "string" && Array.isArray(candidate.assets);
907
- }
908
- function normalizeCodeResult(result) {
909
- const updatedAssets = result.assets.map((asset) => enrichAssetDescriptor(asset));
910
- const rewrittenCode = rewriteCodeAssetUrls(result.code, updatedAssets);
1085
+ summary.push(
1086
+ "Use resources/read with each resourceUri or fetch the fallback URL to download bytes."
1087
+ );
1088
+ const content = [
1089
+ {
1090
+ type: "text",
1091
+ text: summary.join("\n")
1092
+ },
1093
+ ...payload.assets.map((asset) => createAssetResourceLinkBlock2(asset))
1094
+ ];
911
1095
  return {
912
- ...result,
913
- code: rewrittenCode,
914
- assets: updatedAssets
1096
+ content,
1097
+ structuredContent: payload
915
1098
  };
916
1099
  }
917
- function rewriteCodeAssetUrls(code, assets) {
918
- let updatedCode = code;
919
- for (const asset of assets) {
920
- const uriPattern = new RegExp(escapeRegExp(asset.resourceUri), "g");
921
- updatedCode = updatedCode.replace(uriPattern, asset.url);
922
- }
923
- return updatedCode;
924
- }
925
- function enrichAssetDescriptor(asset) {
926
- const record = assetStore.get(asset.hash);
927
- if (!record) {
928
- return asset;
929
- }
930
- return buildAssetDescriptor(record);
931
- }
932
- function escapeRegExp(value) {
933
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
934
- }
935
1100
  function getActiveId() {
936
1101
  return extensions.find((e) => e.active)?.id ?? null;
937
1102
  }
@@ -987,48 +1152,11 @@ function rawDataToBuffer(raw) {
987
1152
  if (raw instanceof ArrayBuffer) return Buffer.from(raw);
988
1153
  return Buffer.concat(raw);
989
1154
  }
990
- function createScreenshotToolResponse(payload) {
991
- if (!isScreenshotResult(payload)) {
992
- throw new Error("Invalid get_screenshot payload received from extension.");
993
- }
994
- const descriptionBlock = {
995
- type: "text",
996
- text: describeScreenshot(payload)
997
- };
998
- return {
999
- content: [
1000
- descriptionBlock,
1001
- {
1002
- type: "text",
1003
- text: `![Screenshot](${payload.asset.url})`
1004
- },
1005
- createResourceLinkBlock(payload.asset, payload)
1006
- ],
1007
- structuredContent: payload
1008
- };
1009
- }
1010
- function createResourceLinkBlock(asset, result) {
1011
- return {
1012
- type: "resource_link",
1013
- name: "Screenshot",
1014
- uri: asset.resourceUri,
1015
- mimeType: asset.mimeType,
1016
- description: `Screenshot ${result.width}x${result.height} @${result.scale}x - Download: ${asset.url}`
1017
- };
1018
- }
1019
- function describeScreenshot(result) {
1020
- return `Screenshot ${result.width}x${result.height} @${result.scale}x (${formatBytes(result.bytes)})`;
1021
- }
1022
- function formatBytes(bytes) {
1155
+ function formatBytes2(bytes) {
1023
1156
  if (bytes < 1024) return `${bytes} B`;
1024
1157
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1025
1158
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1026
1159
  }
1027
- function isScreenshotResult(payload) {
1028
- if (typeof payload !== "object" || !payload) return false;
1029
- const candidate = payload;
1030
- return typeof candidate.asset === "object" && candidate.asset !== null && typeof candidate.width === "number" && typeof candidate.height === "number" && typeof candidate.scale === "number" && typeof candidate.bytes === "number" && typeof candidate.format === "string";
1031
- }
1032
1160
  function shutdown() {
1033
1161
  log.info("Hub is shutting down...");
1034
1162
  assetStore.flush();
package/dist/hub.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/hub.ts", "../../mcp/shared/constants.ts", "../src/asset-http-server.ts", "../src/config.ts", "../src/shared.ts", "../src/asset-store.ts", "../src/protocol.ts", "../src/request.ts", "../src/tools.ts"],
4
- "sourcesContent": ["import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { RawData } from 'ws'\n\nimport { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { nanoid } from 'nanoid'\nimport { existsSync, rmSync, chmodSync, readFileSync, statSync } from 'node:fs'\nimport { createServer } from 'node:net'\nimport { WebSocketServer } from 'ws'\n\nimport type { AssetRecord, ExtensionConnection } from './types'\n\nimport {\n MCP_ASSET_RESOURCE_NAME,\n MCP_ASSET_URI_PREFIX,\n MCP_ASSET_URI_TEMPLATE\n} from '../../mcp/shared/constants'\nimport { createAssetHttpServer } from './asset-http-server'\nimport { createAssetStore } from './asset-store'\nimport { getMcpServerConfig } from './config'\nimport {\n MessageFromExtensionSchema,\n RegisteredMessage,\n StateMessage,\n ToolCallMessage,\n ToolResultMessage\n} from './protocol'\nimport { register, resolve, reject, cleanupForExtension, cleanupAll } from './request'\nimport { log, RUNTIME_DIR, SOCK_PATH, ensureDir } from './shared'\nimport {\n TOOLS,\n GetAssetsParametersSchema,\n GetAssetsResultSchema,\n type AssetDescriptor,\n type GetAssetsResult,\n type GetScreenshotResult,\n type ToolResultMap,\n type ToolName\n} from './tools'\n\nconst SHUTDOWN_TIMEOUT = 2000\nconst { wsPortCandidates, toolTimeoutMs, maxPayloadBytes, autoActivateGraceMs } =\n getMcpServerConfig()\n\nconst extensions: ExtensionConnection[] = []\nlet consumerCount = 0\ntype TimeoutHandle = ReturnType<typeof setTimeout>\nlet autoActivateTimer: TimeoutHandle | null = null\nlet selectedWsPort = 0\n\nconst mcp = new McpServer({ name: 'tempad-dev-mcp', version: '0.1.0' })\ntype McpInputSchema = Parameters<typeof mcp.registerTool>[1]['inputSchema']\ntype McpOutputSchema = Parameters<typeof mcp.registerTool>[1]['outputSchema']\ntype RegisteredTool = (typeof TOOLS)[number]\n\nconst assetStore = createAssetStore()\nconst assetHttpServer = createAssetHttpServer(assetStore)\nawait assetHttpServer.start()\nregisterAssetResources()\n\nfunction registerAssetResources(): void {\n const template = new ResourceTemplate(MCP_ASSET_URI_TEMPLATE, {\n list: async () => ({\n resources: assetStore\n .list()\n .filter((record) => existsSync(record.filePath))\n .map((record) => ({\n uri: buildAssetResourceUri(record.hash),\n name: formatAssetResourceName(record.hash),\n description: `${record.mimeType} (${formatBytes(record.size)})`,\n mimeType: record.mimeType\n }))\n })\n })\n\n mcp.registerResource(\n MCP_ASSET_RESOURCE_NAME,\n template,\n {\n description: 'Binary assets captured by the TemPad Dev hub.'\n },\n async (_uri, variables) => {\n const hash = typeof variables.hash === 'string' ? variables.hash : ''\n return readAssetResource(hash)\n }\n )\n}\n\nasync function readAssetResource(hash: string) {\n if (!hash) {\n throw new Error('Missing asset hash in resource URI.')\n }\n const record = assetStore.get(hash)\n if (!record) {\n throw new Error(`Asset ${hash} not found.`)\n }\n\n if (!existsSync(record.filePath)) {\n assetStore.remove(hash, { removeFile: false })\n throw new Error(`Asset ${hash} file is missing.`)\n }\n\n const stat = statSync(record.filePath)\n // Base64 encoding increases size by ~33% (4 bytes for every 3 bytes)\n const estimatedSize = Math.ceil(stat.size / 3) * 4\n if (estimatedSize > maxPayloadBytes) {\n throw new Error(\n `Asset ${hash} is too large (${formatBytes(stat.size)}, encoded: ${formatBytes(estimatedSize)}) to read via MCP protocol. Use HTTP download.`\n )\n }\n\n assetStore.touch(hash)\n const buffer = readFileSync(record.filePath)\n const resourceUri = buildAssetResourceUri(hash)\n\n if (isTextualMime(record.mimeType)) {\n return {\n contents: [\n {\n uri: resourceUri,\n mimeType: record.mimeType,\n text: buffer.toString('utf8')\n }\n ]\n }\n }\n\n return {\n contents: [\n {\n uri: resourceUri,\n mimeType: record.mimeType,\n blob: buffer.toString('base64')\n }\n ]\n }\n}\n\nfunction isTextualMime(mimeType: string): boolean {\n return mimeType === 'image/svg+xml' || mimeType.startsWith('text/')\n}\n\nfunction buildAssetResourceUri(hash: string): string {\n return `${MCP_ASSET_URI_PREFIX}${hash}`\n}\n\nfunction formatAssetResourceName(hash: string): string {\n return `asset:${hash.slice(0, 8)}`\n}\n\nfunction buildAssetDescriptor(record: AssetRecord): AssetDescriptor {\n return {\n hash: record.hash,\n url: `${assetHttpServer.getBaseUrl()}/assets/${record.hash}`,\n mimeType: record.mimeType,\n size: record.size,\n resourceUri: buildAssetResourceUri(record.hash),\n width: record.metadata?.width,\n height: record.metadata?.height\n }\n}\n\nfunction createAssetResourceLinkBlock(asset: AssetDescriptor) {\n return {\n type: 'resource_link' as const,\n name: formatAssetResourceName(asset.hash),\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `${describeAsset(asset)} - Download: ${asset.url}`\n }\n}\n\nfunction describeAsset(asset: AssetDescriptor): string {\n return `${asset.mimeType} (${formatBytes(asset.size)})`\n}\n\nfunction registerHubTools(): void {\n for (const tool of TOOLS) {\n registerExtensionTool(tool)\n }\n\n mcp.registerTool(\n 'get_assets',\n {\n description:\n 'Resolve uploaded asset hashes to downloadable URLs and resource URIs for resources/read calls.',\n inputSchema: GetAssetsParametersSchema as unknown as McpInputSchema,\n outputSchema: GetAssetsResultSchema as unknown as McpOutputSchema\n },\n async (args: unknown) => {\n const { hashes } = GetAssetsParametersSchema.parse(args)\n if (hashes.length > 100) {\n throw new Error('Too many hashes requested. Limit is 100.')\n }\n const unique = Array.from(new Set(hashes))\n const records = assetStore.getMany(unique).filter((record) => {\n if (existsSync(record.filePath)) return true\n assetStore.remove(record.hash, { removeFile: false })\n return false\n })\n const found = new Set(records.map((record) => record.hash))\n const payload: GetAssetsResult = GetAssetsResultSchema.parse({\n assets: records.map((record) => buildAssetDescriptor(record)),\n missing: unique.filter((hash) => !found.has(hash))\n })\n\n const summary: string[] = []\n summary.push(\n payload.assets.length\n ? `Resolved ${payload.assets.length} asset${payload.assets.length === 1 ? '' : 's'}.`\n : 'No assets were resolved for the requested hashes.'\n )\n if (payload.missing.length) {\n summary.push(`Missing: ${payload.missing.join(', ')}`)\n }\n summary.push(\n 'Use resources/read with each resourceUri or fetch the fallback URL to download bytes.'\n )\n\n const content = [\n {\n type: 'text' as const,\n text: summary.join('\\n')\n },\n ...payload.assets.map((asset) => createAssetResourceLinkBlock(asset))\n ]\n\n return {\n content,\n structuredContent: payload\n }\n }\n )\n}\n\nregisterHubTools()\nlog.info({ tools: TOOLS.map((t) => t.name) }, 'Registered tools.')\nfunction registerExtensionTool<T extends RegisteredTool>(tool: T): void {\n type Name = T['name']\n type Result = ToolResultMap[Name]\n\n const schema = tool.parameters\n mcp.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: schema as unknown as McpInputSchema\n },\n async (args: unknown) => {\n const parsedArgs = schema.parse(args)\n const activeExt = extensions.find((e) => e.active)\n if (!activeExt) throw new Error('No active TemPad Dev extension available.')\n\n const { promise, requestId } = register<Result>(activeExt.id, toolTimeoutMs)\n\n const message: ToolCallMessage = {\n type: 'toolCall',\n id: requestId,\n payload: {\n name: tool.name,\n args: parsedArgs\n }\n }\n activeExt.ws.send(JSON.stringify(message))\n log.info({ tool: tool.name, req: requestId, extId: activeExt.id }, 'Forwarded tool call.')\n\n const payload = await promise\n return createToolResponse(tool.name, payload)\n }\n )\n}\n\ntype ToolResponse = CallToolResult\n\nfunction createToolResponse<Name extends ToolName>(\n toolName: Name,\n payload: ToolResultMap[Name]\n): ToolResponse {\n if (toolName === 'get_screenshot') {\n try {\n // TS cannot narrow ToolResultMap[Name] to the screenshot payload even though the tool name is literal.\n return createScreenshotToolResponse(payload as ToolResultMap['get_screenshot'])\n } catch (error) {\n log.warn({ error }, 'Failed to format get_screenshot result; returning raw payload.')\n return coercePayloadToToolResponse(payload)\n }\n }\n if (toolName === 'get_code') {\n try {\n return createCodeToolResponse(payload as ToolResultMap['get_code'])\n } catch (error) {\n log.warn({ error }, 'Failed to format get_code result; returning raw payload.')\n return coercePayloadToToolResponse(payload)\n }\n }\n\n return coercePayloadToToolResponse(payload)\n}\nfunction coercePayloadToToolResponse(payload: unknown): ToolResponse {\n if (payload && typeof payload === 'object' && Array.isArray((payload as ToolResponse).content)) {\n return payload as ToolResponse\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2)\n }\n ]\n }\n}\n\nfunction createCodeToolResponse(payload: ToolResultMap['get_code']): ToolResponse {\n if (!isCodeResult(payload)) {\n throw new Error('Invalid get_code payload received from extension.')\n }\n\n const normalized = normalizeCodeResult(payload)\n const summary: string[] = []\n const codeSize = Buffer.byteLength(normalized.code, 'utf8')\n summary.push(`Generated ${normalized.lang.toUpperCase()} snippet (${formatBytes(codeSize)}).`)\n if (normalized.message) {\n summary.push(normalized.message)\n }\n summary.push(\n normalized.assets.length\n ? `Assets attached: ${normalized.assets.length}. Fetch bytes via resources/read using resourceUri or call get_assets.`\n : 'No binary assets were attached to this response.'\n )\n if (normalized.usedTokens?.length) {\n summary.push(`Token references included: ${normalized.usedTokens.length}.`)\n }\n summary.push('Read structuredContent for the full code string and asset metadata.')\n\n return {\n content: [\n {\n type: 'text' as const,\n text: summary.join('\\n')\n }\n ],\n structuredContent: normalized\n }\n}\n\nfunction isCodeResult(payload: unknown): payload is ToolResultMap['get_code'] {\n if (typeof payload !== 'object' || !payload) return false\n const candidate = payload as Partial<ToolResultMap['get_code'] & Record<string, unknown>>\n return (\n typeof candidate.code === 'string' &&\n typeof candidate.lang === 'string' &&\n Array.isArray(candidate.assets)\n )\n}\n\nfunction normalizeCodeResult(result: ToolResultMap['get_code']): ToolResultMap['get_code'] {\n const updatedAssets = result.assets.map((asset) => enrichAssetDescriptor(asset))\n const rewrittenCode = rewriteCodeAssetUrls(result.code, updatedAssets)\n return {\n ...result,\n code: rewrittenCode,\n assets: updatedAssets\n }\n}\n\nfunction rewriteCodeAssetUrls(code: string, assets: AssetDescriptor[]): string {\n let updatedCode = code\n for (const asset of assets) {\n // Replace asset:// URIs with the HTTP URL\n const uriPattern = new RegExp(escapeRegExp(asset.resourceUri), 'g')\n updatedCode = updatedCode.replace(uriPattern, asset.url)\n }\n return updatedCode\n}\n\nfunction enrichAssetDescriptor(asset: AssetDescriptor): AssetDescriptor {\n const record = assetStore.get(asset.hash)\n if (!record) {\n return asset\n }\n return buildAssetDescriptor(record)\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction getActiveId(): string | null {\n return extensions.find((e) => e.active)?.id ?? null\n}\n\nfunction setActive(targetId: string | null): void {\n extensions.forEach((e) => {\n e.active = targetId !== null && e.id === targetId\n })\n}\n\nfunction clearAutoActivateTimer(): void {\n if (autoActivateTimer) {\n clearTimeout(autoActivateTimer)\n autoActivateTimer = null\n }\n}\n\nfunction scheduleAutoActivate(): void {\n clearAutoActivateTimer()\n\n if (extensions.length !== 1 || getActiveId()) {\n return\n }\n\n const target = extensions[0]\n autoActivateTimer = setTimeout(() => {\n autoActivateTimer = null\n if (extensions.length === 1 && !getActiveId()) {\n setActive(target.id)\n log.info({ id: target.id }, 'Auto-activated sole extension after grace period.')\n broadcastState()\n }\n }, autoActivateGraceMs)\n}\n\nfunction unrefTimer(timer: TimeoutHandle): void {\n if (typeof timer === 'object' && timer !== null) {\n const handle = timer as NodeJS.Timeout\n if (typeof handle.unref === 'function') {\n handle.unref()\n }\n }\n}\n\nfunction broadcastState(): void {\n const activeId = getActiveId()\n const message: StateMessage = {\n type: 'state',\n activeId,\n count: extensions.length,\n port: selectedWsPort,\n assetServerUrl: assetHttpServer.getBaseUrl()\n }\n extensions.forEach((ext) => ext.ws.send(JSON.stringify(message)))\n log.debug({ activeId, count: extensions.length }, 'Broadcasted state.')\n}\n\nfunction rawDataToBuffer(raw: RawData): Buffer {\n if (typeof raw === 'string') return Buffer.from(raw)\n if (Buffer.isBuffer(raw)) return raw\n if (raw instanceof ArrayBuffer) return Buffer.from(raw)\n return Buffer.concat(raw)\n}\n\nfunction createScreenshotToolResponse(payload: ToolResultMap['get_screenshot']): ToolResponse {\n if (!isScreenshotResult(payload)) {\n throw new Error('Invalid get_screenshot payload received from extension.')\n }\n\n const descriptionBlock = {\n type: 'text' as const,\n text: describeScreenshot(payload)\n }\n\n return {\n content: [\n descriptionBlock,\n {\n type: 'text' as const,\n text: `![Screenshot](${payload.asset.url})`\n },\n createResourceLinkBlock(payload.asset, payload)\n ],\n structuredContent: payload\n }\n}\n\nfunction createResourceLinkBlock(asset: AssetDescriptor, result: GetScreenshotResult) {\n return {\n type: 'resource_link' as const,\n name: 'Screenshot',\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `Screenshot ${result.width}x${result.height} @${result.scale}x - Download: ${asset.url}`\n }\n}\n\nfunction describeScreenshot(result: GetScreenshotResult): string {\n return `Screenshot ${result.width}x${result.height} @${result.scale}x (${formatBytes(result.bytes)})`\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction isScreenshotResult(payload: unknown): payload is GetScreenshotResult {\n if (typeof payload !== 'object' || !payload) return false\n const candidate = payload as Partial<GetScreenshotResult & Record<string, unknown>>\n return (\n typeof candidate.asset === 'object' &&\n candidate.asset !== null &&\n typeof candidate.width === 'number' &&\n typeof candidate.height === 'number' &&\n typeof candidate.scale === 'number' &&\n typeof candidate.bytes === 'number' &&\n typeof candidate.format === 'string'\n )\n}\n\nfunction shutdown(): void {\n log.info('Hub is shutting down...')\n assetStore.flush()\n assetHttpServer.stop()\n netServer.close(() => log.info('Net server closed.'))\n wss?.close(() => log.info('WebSocket server closed.'))\n cleanupAll()\n const timer = setTimeout(() => {\n log.warn('Shutdown timed out. Forcing exit.')\n process.exit(1)\n }, SHUTDOWN_TIMEOUT)\n unrefTimer(timer)\n}\n\ntry {\n ensureDir(RUNTIME_DIR)\n if (process.platform !== 'win32' && existsSync(SOCK_PATH)) {\n log.warn({ sock: SOCK_PATH }, 'Removing stale socket file.')\n rmSync(SOCK_PATH)\n }\n} catch (error: unknown) {\n log.error({ err: error }, 'Failed to initialize runtime environment.')\n process.exit(1)\n}\n\nconst netServer = createServer((sock) => {\n consumerCount++\n log.info(`Consumer connected. Total: ${consumerCount}`)\n const transport = new StdioServerTransport(sock, sock)\n mcp.connect(transport).catch((err) => {\n log.error({ err }, 'Failed to attach MCP transport.')\n transport.close().catch((closeErr) => log.warn({ err: closeErr }, 'Transport close failed.'))\n sock.destroy()\n })\n sock.on('error', (err) => {\n log.warn({ err }, 'Consumer socket error.')\n transport.close().catch((closeErr) => log.warn({ err: closeErr }, 'Transport close failed.'))\n })\n sock.on('close', async () => {\n await transport.close()\n consumerCount--\n log.info(`Consumer disconnected. Remaining: ${consumerCount}`)\n if (consumerCount === 0) {\n log.info('Last consumer disconnected. Shutting down.')\n shutdown()\n }\n })\n})\nnetServer.on('error', (err) => {\n log.error({ err }, 'Net server error.')\n process.exit(1)\n})\nnetServer.listen(SOCK_PATH, () => {\n try {\n if (process.platform !== 'win32') chmodSync(SOCK_PATH, 0o600)\n } catch (err) {\n log.error({ err }, 'Failed to set socket permissions. Shutting down.')\n process.exit(1)\n }\n log.info({ sock: SOCK_PATH }, 'Hub socket ready.')\n})\n\nasync function startWebSocketServer(): Promise<{ wss: WebSocketServer; port: number }> {\n for (const candidate of wsPortCandidates) {\n const server = new WebSocketServer({\n host: '127.0.0.1',\n port: candidate,\n maxPayload: maxPayloadBytes\n })\n\n try {\n await new Promise<void>((resolve, reject) => {\n const onError = (err: NodeJS.ErrnoException) => {\n server.off('listening', onListening)\n reject(err)\n }\n const onListening = () => {\n server.off('error', onError)\n resolve()\n }\n server.once('error', onError)\n server.once('listening', onListening)\n })\n return { wss: server, port: candidate }\n } catch (err) {\n server.close()\n const errno = err as NodeJS.ErrnoException\n if (errno.code === 'EADDRINUSE') {\n log.warn({ port: candidate }, 'WebSocket port in use, trying next candidate.')\n continue\n }\n log.error({ err: errno, port: candidate }, 'Failed to start WebSocket server.')\n process.exit(1)\n }\n }\n\n log.error(\n { candidates: wsPortCandidates },\n 'Unable to start WebSocket server on any candidate port.'\n )\n process.exit(1)\n}\n\nconst { wss, port } = await startWebSocketServer()\nselectedWsPort = port\n\n// Add an error handler to prevent crashes from port conflicts, etc.\nwss.on('error', (err) => {\n log.error({ err }, 'WebSocket server critical error. Exiting.')\n process.exit(1)\n})\n\nwss.on('connection', (ws) => {\n const ext: ExtensionConnection = { id: nanoid(), ws, active: false }\n extensions.push(ext)\n log.info({ id: ext.id }, `Extension connected. Total: ${extensions.length}`)\n\n const message: RegisteredMessage = { type: 'registered', id: ext.id }\n ws.send(JSON.stringify(message))\n broadcastState()\n scheduleAutoActivate()\n\n ws.on('message', (raw: RawData, isBinary: boolean) => {\n if (isBinary) {\n log.warn({ extId: ext.id }, 'Unexpected binary message received.')\n return\n }\n\n const messageBuffer = rawDataToBuffer(raw)\n\n let parsedJson: unknown\n try {\n parsedJson = JSON.parse(messageBuffer.toString('utf-8'))\n } catch (e: unknown) {\n log.warn({ err: e, extId: ext.id }, 'Failed to parse message.')\n return\n }\n\n const parseResult = MessageFromExtensionSchema.safeParse(parsedJson)\n if (!parseResult.success) {\n log.warn({ error: parseResult.error.flatten(), extId: ext.id }, 'Invalid message shape.')\n return\n }\n const msg = parseResult.data\n\n switch (msg.type) {\n case 'activate': {\n setActive(ext.id)\n log.info({ id: ext.id }, 'Extension activated.')\n broadcastState()\n scheduleAutoActivate()\n break\n }\n case 'toolResult': {\n const { id, payload, error } = msg as ToolResultMessage\n if (error) {\n reject(id, error instanceof Error ? error : new Error(String(error)))\n } else {\n resolve(id, payload)\n }\n break\n }\n }\n })\n\n ws.on('close', () => {\n const index = extensions.findIndex((e) => e.id === ext.id)\n if (index > -1) extensions.splice(index, 1)\n\n log.info({ id: ext.id }, `Extension disconnected. Remaining: ${extensions.length}`)\n cleanupForExtension(ext.id)\n\n if (ext.active) {\n log.warn({ id: ext.id }, 'Active extension disconnected.')\n setActive(null)\n }\n\n broadcastState()\n scheduleAutoActivate()\n })\n})\n\nlog.info({ port: selectedWsPort }, 'WebSocket server ready.')\n\nprocess.on('SIGINT', shutdown)\nprocess.on('SIGTERM', shutdown)\n", "export const MCP_PORT_CANDIDATES = [6220, 7431, 8127]\n\n// Upper bound for MCP message payloads in bytes.\nexport const MCP_MAX_PAYLOAD_BYTES = 4 * 1024 * 1024\n\n// Default tool timeout used by the MCP hub (ms).\nexport const MCP_TOOL_TIMEOUT_MS = 15000\n\n// Grace period before auto-activating the sole extension (ms).\nexport const MCP_AUTO_ACTIVATE_GRACE_MS = 1500\n\n// Maximum allowed size for uploaded assets (bytes).\nexport const MCP_MAX_ASSET_BYTES = 8 * 1024 * 1024\n\nexport const MCP_ASSET_RESOURCE_NAME = 'tempad-assets'\nexport const MCP_ASSET_URI_PREFIX = 'asset://tempad/'\nexport const MCP_ASSET_URI_TEMPLATE = `${MCP_ASSET_URI_PREFIX}{hash}`\n\nexport const MCP_HASH_PATTERN = /^[a-f0-9]{64}$/i\n", "import { nanoid } from 'nanoid'\nimport { createHash } from 'node:crypto'\nimport {\n createReadStream,\n createWriteStream,\n existsSync,\n renameSync,\n statSync,\n unlinkSync\n} from 'node:fs'\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http'\nimport { join } from 'node:path'\nimport { pipeline, Transform } from 'node:stream'\nimport { URL } from 'node:url'\n\nimport type { AssetStore } from './asset-store'\n\nimport { MCP_HASH_PATTERN } from '../../mcp/shared/constants'\nimport { getMcpServerConfig } from './config'\nimport { ASSET_DIR, log } from './shared'\n\nconst LOOPBACK_HOST = '127.0.0.1'\nconst { maxAssetSizeBytes } = getMcpServerConfig()\n\nexport interface AssetHttpServer {\n start(): Promise<void>\n stop(): void\n getBaseUrl(): string\n}\n\nexport function createAssetHttpServer(store: AssetStore): AssetHttpServer {\n const server = createServer(handleRequest)\n let port: number | null = null\n\n async function start(): Promise<void> {\n if (port !== null) return\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n server.off('listening', onListening)\n reject(error)\n }\n const onListening = () => {\n server.off('error', onError)\n const address = server.address()\n if (address && typeof address === 'object') {\n port = address.port\n resolve()\n } else {\n reject(new Error('Failed to determine HTTP server port.'))\n }\n }\n server.once('error', onError)\n server.once('listening', onListening)\n server.listen(0, LOOPBACK_HOST)\n })\n log.info({ port }, 'Asset HTTP server ready.')\n }\n\n function stop(): void {\n if (port === null) return\n server.close()\n port = null\n }\n\n function getBaseUrl(): string {\n if (port === null) throw new Error('Asset HTTP server is not running.')\n return `http://${LOOPBACK_HOST}:${port}`\n }\n\n function handleRequest(req: IncomingMessage, res: ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Asset-Width, X-Asset-Height')\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204)\n res.end()\n return\n }\n\n if (!req.url) {\n res.writeHead(400)\n res.end('Missing URL')\n return\n }\n\n const url = new URL(req.url, getBaseUrl())\n const segments = url.pathname.split('/').filter(Boolean)\n if (segments.length !== 2 || segments[0] !== 'assets') {\n res.writeHead(404)\n res.end('Not Found')\n return\n }\n\n const hash = segments[1]\n\n if (req.method === 'POST') {\n handleUpload(req, res, hash)\n return\n }\n\n if (req.method === 'GET') {\n handleDownload(req, res, hash)\n return\n }\n\n res.writeHead(405)\n res.end('Method Not Allowed')\n }\n\n function handleDownload(req: IncomingMessage, res: ServerResponse, hash: string): void {\n const record = store.get(hash)\n if (!record) {\n res.writeHead(404)\n res.end('Not Found')\n return\n }\n\n let stat\n try {\n stat = statSync(record.filePath)\n } catch (error) {\n const err = error as NodeJS.ErrnoException\n if (err.code === 'ENOENT') {\n store.remove(hash, { removeFile: false })\n res.writeHead(404)\n res.end('Not Found')\n } else {\n log.error({ error, hash }, 'Failed to stat asset file.')\n res.writeHead(500)\n res.end('Internal Server Error')\n }\n return\n }\n\n res.writeHead(200, {\n 'Content-Type': record.mimeType,\n 'Content-Length': stat.size.toString(),\n 'Cache-Control': 'public, max-age=31536000, immutable'\n })\n\n const stream = createReadStream(record.filePath)\n stream.on('error', (error) => {\n log.warn({ error, hash }, 'Failed to stream asset file.')\n if (!res.headersSent) {\n res.writeHead(500)\n }\n res.end('Internal Server Error')\n })\n stream.on('open', () => {\n store.touch(hash)\n })\n stream.pipe(res)\n }\n\n function handleUpload(req: IncomingMessage, res: ServerResponse, hash: string): void {\n if (!MCP_HASH_PATTERN.test(hash)) {\n res.writeHead(400)\n res.end('Invalid Hash Format')\n return\n }\n\n const mimeType = req.headers['content-type'] || 'application/octet-stream'\n const filePath = join(ASSET_DIR, hash)\n\n const width = parseInt(req.headers['x-asset-width'] as string, 10)\n const height = parseInt(req.headers['x-asset-height'] as string, 10)\n const metadata =\n !isNaN(width) && !isNaN(height) && width > 0 && height > 0 ? { width, height } : undefined\n\n // If asset already exists and file is present, skip write\n if (store.has(hash) && existsSync(filePath)) {\n // Drain request to ensure connection is clean\n req.resume()\n\n const existing = store.get(hash)!\n let changed = false\n if (metadata) {\n existing.metadata = metadata\n changed = true\n }\n if (existing.mimeType !== mimeType) {\n existing.mimeType = mimeType\n changed = true\n }\n if (changed) {\n store.upsert(existing)\n }\n store.touch(hash)\n res.writeHead(200)\n res.end('OK')\n return\n }\n\n const tmpPath = `${filePath}.tmp.${nanoid()}`\n const writeStream = createWriteStream(tmpPath)\n const hasher = createHash('sha256')\n let size = 0\n\n const cleanup = () => {\n if (existsSync(tmpPath)) {\n try {\n unlinkSync(tmpPath)\n } catch (e) {\n log.warn({ error: e, tmpPath }, 'Failed to cleanup temp file.')\n }\n }\n }\n\n const monitor = new Transform({\n transform(chunk, encoding, callback) {\n size += chunk.length\n if (size > maxAssetSizeBytes) {\n callback(new Error('PayloadTooLarge'))\n return\n }\n hasher.update(chunk)\n callback(null, chunk)\n }\n })\n\n pipeline(req, monitor, writeStream, (err) => {\n if (err) {\n cleanup()\n if (err.message === 'PayloadTooLarge') {\n res.writeHead(413)\n res.end('Payload Too Large')\n } else if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') {\n log.warn({ hash }, 'Upload request closed prematurely.')\n } else {\n log.error({ error: err, hash }, 'Upload pipeline failed.')\n if (!res.headersSent) {\n res.writeHead(500)\n res.end('Internal Server Error')\n }\n }\n return\n }\n\n const computedHash = hasher.digest('hex')\n if (computedHash !== hash) {\n cleanup()\n res.writeHead(400)\n res.end('Hash Mismatch')\n return\n }\n\n try {\n renameSync(tmpPath, filePath)\n } catch (error) {\n log.error({ error, hash }, 'Failed to rename temp file to asset.')\n cleanup()\n res.writeHead(500)\n res.end('Internal Server Error')\n return\n }\n\n store.upsert({\n hash,\n filePath,\n mimeType,\n size,\n metadata\n })\n log.info({ hash, size }, 'Stored uploaded asset via HTTP.')\n res.writeHead(201)\n res.end('Created')\n })\n }\n\n return {\n start,\n stop,\n getBaseUrl\n }\n}\n", "import {\n MCP_AUTO_ACTIVATE_GRACE_MS,\n MCP_MAX_ASSET_BYTES,\n MCP_MAX_PAYLOAD_BYTES,\n MCP_PORT_CANDIDATES,\n MCP_TOOL_TIMEOUT_MS\n} from '../../mcp/shared/constants'\n\nfunction parsePositiveInt(envValue: string | undefined, fallback: number): number {\n const parsed = envValue ? Number.parseInt(envValue, 10) : Number.NaN\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback\n}\n\nfunction resolveToolTimeoutMs(): number {\n return parsePositiveInt(process.env.TEMPAD_MCP_TOOL_TIMEOUT, MCP_TOOL_TIMEOUT_MS)\n}\n\nfunction resolveAutoActivateGraceMs(): number {\n return parsePositiveInt(process.env.TEMPAD_MCP_AUTO_ACTIVATE_GRACE, MCP_AUTO_ACTIVATE_GRACE_MS)\n}\n\nfunction resolveMaxAssetSizeBytes(): number {\n return parsePositiveInt(process.env.TEMPAD_MCP_MAX_ASSET_BYTES, MCP_MAX_ASSET_BYTES)\n}\n\nexport function getMcpServerConfig() {\n return {\n wsPortCandidates: [...MCP_PORT_CANDIDATES],\n toolTimeoutMs: resolveToolTimeoutMs(),\n maxPayloadBytes: MCP_MAX_PAYLOAD_BYTES,\n autoActivateGraceMs: resolveAutoActivateGraceMs(),\n maxAssetSizeBytes: resolveMaxAssetSizeBytes()\n }\n}\n", "import { closeSync, mkdirSync, openSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport pino from 'pino'\n\nexport function ensureDir(dirPath: string): void {\n mkdirSync(dirPath, { recursive: true, mode: 0o700 })\n}\n\nfunction resolveRuntimeDir(): string {\n if (process.env.TEMPAD_MCP_RUNTIME_DIR) return process.env.TEMPAD_MCP_RUNTIME_DIR\n return join(tmpdir(), 'tempad-dev', 'run')\n}\n\nfunction resolveLogDir(): string {\n if (process.env.TEMPAD_MCP_LOG_DIR) return process.env.TEMPAD_MCP_LOG_DIR\n return join(tmpdir(), 'tempad-dev', 'log')\n}\n\nfunction resolveAssetDir(): string {\n if (process.env.TEMPAD_MCP_ASSET_DIR) return process.env.TEMPAD_MCP_ASSET_DIR\n return join(tmpdir(), 'tempad-dev', 'assets')\n}\n\nexport const RUNTIME_DIR = resolveRuntimeDir()\nexport const LOG_DIR = resolveLogDir()\nexport const ASSET_DIR = resolveAssetDir()\n\nensureDir(RUNTIME_DIR)\nensureDir(LOG_DIR)\nensureDir(ASSET_DIR)\n\nexport function ensureFile(filePath: string): void {\n const fd = openSync(filePath, 'a')\n closeSync(fd)\n}\n\nexport const LOCK_PATH = join(RUNTIME_DIR, 'mcp.lock')\nensureFile(LOCK_PATH)\n\nconst timestamp = new Date().toISOString().replaceAll(':', '-').replaceAll('.', '-')\nconst pid = process.pid\nconst LOG_FILE = join(LOG_DIR, `mcp-${timestamp}-${pid}.log`)\n\nconst prettyTransport = pino.transport({\n target: 'pino-pretty',\n options: {\n translateTime: 'SYS:HH:MM:ss',\n destination: LOG_FILE\n }\n})\n\nexport const log = pino(\n {\n level: process.env.DEBUG ? 'debug' : 'info',\n msgPrefix: '[tempad-dev/mcp] '\n },\n prettyTransport\n)\n\nexport const SOCK_PATH =\n process.platform === 'win32' ? '\\\\\\\\.\\\\pipe\\\\tempad-mcp' : join(RUNTIME_DIR, 'mcp.sock')\n", "import { existsSync, readFileSync, rmSync, writeFileSync, readdirSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { AssetRecord } from './types'\n\nimport { ASSET_DIR, ensureDir, ensureFile, log } from './shared'\n\nconst INDEX_FILENAME = 'assets.json'\nconst DEFAULT_INDEX_PATH = join(ASSET_DIR, INDEX_FILENAME)\n\nexport interface AssetStoreOptions {\n indexPath?: string\n}\n\nexport interface AssetStore {\n list(): AssetRecord[]\n has(hash: string): boolean\n get(hash: string): AssetRecord | undefined\n getMany(hashes: string[]): AssetRecord[]\n upsert(\n input: Omit<AssetRecord, 'uploadedAt' | 'lastAccess'> &\n Partial<Pick<AssetRecord, 'uploadedAt' | 'lastAccess'>>\n ): AssetRecord\n touch(hash: string): AssetRecord | undefined\n remove(hash: string, opts?: { removeFile?: boolean }): void\n reconcile(): void\n flush(): void\n}\n\nfunction readIndex(indexPath: string): AssetRecord[] {\n if (!existsSync(indexPath)) return []\n try {\n const raw = readFileSync(indexPath, 'utf8').trim()\n if (!raw) return []\n const parsed = JSON.parse(raw)\n return Array.isArray(parsed) ? (parsed as AssetRecord[]) : []\n } catch (error) {\n log.warn({ error, indexPath }, 'Failed to read asset catalog; starting fresh.')\n return []\n }\n}\n\nfunction writeIndex(indexPath: string, values: AssetRecord[]): void {\n const payload = JSON.stringify(values, null, 2)\n writeFileSync(indexPath, payload, 'utf8')\n}\n\nexport function createAssetStore(options: AssetStoreOptions = {}): AssetStore {\n ensureDir(ASSET_DIR)\n const indexPath = options.indexPath ?? DEFAULT_INDEX_PATH\n ensureFile(indexPath)\n const records = new Map<string, AssetRecord>()\n let persistTimer: NodeJS.Timeout | null = null\n\n function loadExisting(): void {\n const list = readIndex(indexPath)\n for (const record of list) {\n if (record?.hash && record?.filePath) {\n records.set(record.hash, record)\n }\n }\n }\n\n function persist(): void {\n if (persistTimer) return\n persistTimer = setTimeout(() => {\n persistTimer = null\n writeIndex(indexPath, [...records.values()])\n }, 5000)\n if (typeof persistTimer.unref === 'function') {\n persistTimer.unref()\n }\n }\n\n function flush(): void {\n if (persistTimer) {\n clearTimeout(persistTimer)\n persistTimer = null\n }\n writeIndex(indexPath, [...records.values()])\n }\n\n function list(): AssetRecord[] {\n return [...records.values()]\n }\n\n function has(hash: string): boolean {\n return records.has(hash)\n }\n\n function get(hash: string): AssetRecord | undefined {\n return records.get(hash)\n }\n\n function getMany(hashes: string[]): AssetRecord[] {\n return hashes\n .map((hash) => records.get(hash))\n .filter((record): record is AssetRecord => !!record)\n }\n\n function upsert(\n input: Omit<AssetRecord, 'uploadedAt' | 'lastAccess'> &\n Partial<Pick<AssetRecord, 'uploadedAt' | 'lastAccess'>>\n ): AssetRecord {\n const now = Date.now()\n const record: AssetRecord = {\n ...input,\n uploadedAt: input.uploadedAt ?? now,\n lastAccess: input.lastAccess ?? now\n }\n records.set(record.hash, record)\n persist()\n return record\n }\n\n function touch(hash: string): AssetRecord | undefined {\n const existing = records.get(hash)\n if (!existing) return undefined\n existing.lastAccess = Date.now()\n persist()\n return existing\n }\n\n function remove(hash: string, { removeFile = true } = {}): void {\n const record = records.get(hash)\n if (!record) return\n records.delete(hash)\n persist()\n\n if (removeFile) {\n try {\n rmSync(record.filePath, { force: true })\n } catch (error) {\n log.warn({ hash, error }, 'Failed to remove asset file on delete.')\n }\n }\n }\n\n function reconcile(): void {\n let changed = false\n for (const [hash, record] of records) {\n if (!existsSync(record.filePath)) {\n records.delete(hash)\n changed = true\n }\n }\n\n try {\n const files = readdirSync(ASSET_DIR)\n const now = Date.now()\n for (const file of files) {\n if (file === INDEX_FILENAME) continue\n\n // Cleanup stale tmp files (> 1 hour)\n if (file.includes('.tmp.')) {\n try {\n const filePath = join(ASSET_DIR, file)\n const stat = statSync(filePath)\n if (now - stat.mtimeMs > 3600 * 1000) {\n rmSync(filePath, { force: true })\n log.info({ file }, 'Cleaned up stale temp file.')\n }\n } catch (e) {\n // Ignore errors during cleanup\n log.debug({ error: e, file }, 'Failed to cleanup stale temp file.')\n }\n continue\n }\n\n if (!/^[a-f0-9]{64}$/i.test(file)) continue\n\n if (!records.has(file)) {\n const filePath = join(ASSET_DIR, file)\n try {\n const stat = statSync(filePath)\n records.set(file, {\n hash: file,\n filePath,\n mimeType: 'application/octet-stream',\n size: stat.size,\n uploadedAt: stat.birthtimeMs,\n lastAccess: stat.atimeMs\n })\n changed = true\n log.info({ hash: file }, 'Recovered orphan asset file.')\n } catch (e) {\n log.warn({ error: e, file }, 'Failed to stat orphan file.')\n }\n }\n }\n } catch (error) {\n log.warn({ error }, 'Failed to scan asset directory for orphans.')\n }\n\n if (changed) flush()\n }\n\n loadExisting()\n reconcile()\n\n return {\n list,\n has,\n get,\n getMany,\n upsert,\n touch,\n remove,\n reconcile,\n flush\n }\n}\n", "import { z } from 'zod'\n\n// Messages from hub to extension\nexport const RegisteredMessageSchema = z.object({\n type: z.literal('registered'),\n id: z.string()\n})\n\nexport const StateMessageSchema = z.object({\n type: z.literal('state'),\n activeId: z.string().nullable(),\n count: z.number().nonnegative(),\n port: z.number().positive(),\n assetServerUrl: z.string().url()\n})\n\nexport const ToolCallPayloadSchema = z.object({\n name: z.string(),\n args: z.unknown()\n})\n\nexport const ToolCallMessageSchema = z.object({\n type: z.literal('toolCall'),\n id: z.string(),\n payload: ToolCallPayloadSchema\n})\n\nexport const MessageToExtensionSchema = z.discriminatedUnion('type', [\n RegisteredMessageSchema,\n StateMessageSchema,\n ToolCallMessageSchema\n])\n\n// Messages from extension to hub\nexport const ActivateMessageSchema = z.object({\n type: z.literal('activate')\n})\n\nexport const ToolResultMessageSchema = z.object({\n type: z.literal('toolResult'),\n id: z.string(),\n payload: z.unknown().optional(),\n error: z.unknown().optional()\n})\n\nexport const MessageFromExtensionSchema = z.discriminatedUnion('type', [\n ActivateMessageSchema,\n ToolResultMessageSchema\n])\n\nexport type RegisteredMessage = z.infer<typeof RegisteredMessageSchema>\nexport type StateMessage = z.infer<typeof StateMessageSchema>\nexport type ToolCallPayload = z.infer<typeof ToolCallPayloadSchema>\nexport type ToolCallMessage = z.infer<typeof ToolCallMessageSchema>\nexport type MessageToExtension = z.infer<typeof MessageToExtensionSchema>\nexport type ActivateMessage = z.infer<typeof ActivateMessageSchema>\nexport type ToolResultMessage = z.infer<typeof ToolResultMessageSchema>\nexport type MessageFromExtension = z.infer<typeof MessageFromExtensionSchema>\n\nexport function parseMessageToExtension(data: string): MessageToExtension | null {\n let parsed: unknown\n try {\n parsed = JSON.parse(data)\n } catch {\n return null\n }\n const result = MessageToExtensionSchema.safeParse(parsed)\n return result.success ? result.data : null\n}\n\nexport function parseMessageFromExtension(data: string): MessageFromExtension | null {\n let parsed: unknown\n try {\n parsed = JSON.parse(data)\n } catch {\n return null\n }\n const result = MessageFromExtensionSchema.safeParse(parsed)\n return result.success ? result.data : null\n}\n", "import { nanoid } from 'nanoid'\n\nimport type { PendingToolCall } from './types'\n\nimport { log } from './shared'\n\nconst pendingCalls = new Map<string, PendingToolCall>()\n\nexport function register<T>(\n extensionId: string,\n timeout: number\n): { promise: Promise<T>; requestId: string } {\n const requestId = nanoid()\n const promise = new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingCalls.delete(requestId)\n reject(new Error(`Extension did not respond within ${timeout / 1000}s.`))\n }, timeout)\n\n pendingCalls.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timer,\n extensionId\n })\n })\n return { promise, requestId }\n}\n\nexport function resolve(requestId: string, payload: unknown): void {\n const call = pendingCalls.get(requestId)\n if (call) {\n const { timer, resolve: finish } = call\n clearTimeout(timer)\n finish(payload)\n pendingCalls.delete(requestId)\n } else {\n log.warn({ reqId: requestId }, 'Received result for unknown/timed-out call.')\n }\n}\n\nexport function reject(requestId: string, error: Error): void {\n const call = pendingCalls.get(requestId)\n if (call) {\n const { timer, reject: fail } = call\n clearTimeout(timer)\n fail(error)\n pendingCalls.delete(requestId)\n } else {\n log.warn({ reqId: requestId }, 'Received error for unknown/timed-out call.')\n }\n}\n\nexport function cleanupForExtension(extensionId: string): void {\n for (const [reqId, call] of pendingCalls.entries()) {\n const { timer, reject: fail, extensionId: extId } = call\n if (extId === extensionId) {\n clearTimeout(timer)\n fail(new Error('Extension disconnected before providing a result.'))\n pendingCalls.delete(reqId)\n log.warn({ reqId, extId: extensionId }, 'Rejected pending call from disconnected extension.')\n }\n }\n}\n\nexport function cleanupAll(): void {\n pendingCalls.forEach((call, reqId) => {\n const { timer, reject: fail } = call\n clearTimeout(timer)\n fail(new Error('Hub is shutting down.'))\n log.debug({ reqId }, 'Rejected pending tool call due to shutdown.')\n })\n pendingCalls.clear()\n}\n", "import { z } from 'zod'\n\nimport type { AssetDescriptor } from '../../mcp/shared/types'\n\nimport { MCP_HASH_PATTERN } from '../../mcp/shared/constants'\n\nexport type { AssetDescriptor }\n\n// get_code\nexport const GetCodeParametersSchema = z.object({\n nodeId: z.string().optional(),\n preferredLang: z.enum(['jsx', 'vue']).optional(),\n resolveTokens: z.boolean().optional()\n})\n\nexport type GetCodeParametersInput = z.input<typeof GetCodeParametersSchema>\nexport type GetCodeResult = {\n code: string\n lang: 'vue' | 'jsx'\n message?: string\n usedTokens?: GetTokenDefsResult['tokens']\n assets: AssetDescriptor[]\n}\n\n// get_token_defs\nexport const GetTokenDefsParametersSchema = z.object({\n nodeId: z.string().optional()\n})\n\nexport type GetTokenDefsParametersInput = z.input<typeof GetTokenDefsParametersSchema>\nexport type GetTokenDefsResult = {\n tokens: Array<{\n name: string\n value: string | Record<string, unknown>\n kind: 'color' | 'spacing' | 'typography' | 'effect' | 'other'\n }>\n}\n\nexport const AssetDescriptorSchema = z.object({\n hash: z.string().min(1),\n url: z.string().url(),\n mimeType: z.string().min(1),\n size: z.number().int().nonnegative(),\n resourceUri: z.string().regex(/^asset:\\/\\/tempad\\/[a-f0-9]{64}$/i),\n width: z.number().int().positive().optional(),\n height: z.number().int().positive().optional()\n})\n\n// get_screenshot\nexport const GetScreenshotParametersSchema = z.object({\n nodeId: z.string().optional()\n})\n\nexport type GetScreenshotParametersInput = z.input<typeof GetScreenshotParametersSchema>\nexport type GetScreenshotResult = {\n format: 'png'\n width: number\n height: number\n scale: number\n bytes: number\n asset: AssetDescriptor\n}\n\n// get_structure\nexport const GetStructureParametersSchema = z.object({\n nodeId: z.string().optional(),\n options: z\n .object({\n depth: z.number().int().positive().optional()\n })\n .optional()\n})\n\nexport type GetStructureParametersInput = z.input<typeof GetStructureParametersSchema>\nexport type OutlineNode = {\n id: string\n name: string\n type: string\n x: number\n y: number\n width: number\n height: number\n children?: OutlineNode[]\n}\nexport type GetStructureResult = {\n roots: OutlineNode[]\n}\n\n// get_assets (hub only)\nexport const GetAssetsParametersSchema = z.object({\n hashes: z.array(z.string().regex(MCP_HASH_PATTERN)).min(1)\n})\n\nexport const GetAssetsResultSchema = z.object({\n assets: z.array(AssetDescriptorSchema),\n missing: z.array(z.string().min(1))\n})\n\nexport type GetAssetsParametersInput = z.input<typeof GetAssetsParametersSchema>\nexport type GetAssetsResult = z.infer<typeof GetAssetsResultSchema>\n\nexport const TOOLS = [\n {\n name: 'get_code',\n description: 'High fidelity code snapshot for the current selection or provided node ids.',\n parameters: GetCodeParametersSchema\n },\n {\n name: 'get_token_defs',\n description: 'Token definitions referenced by the current selection or provided node ids.',\n parameters: GetTokenDefsParametersSchema\n },\n {\n name: 'get_screenshot',\n description: 'Rendered screenshot for the requested node.',\n parameters: GetScreenshotParametersSchema\n },\n {\n name: 'get_structure',\n description: 'Structural outline of the current selection or provided node ids.',\n parameters: GetStructureParametersSchema\n }\n] as const\n\nexport type ToolName = (typeof TOOLS)[number]['name']\n\nexport type ToolResultMap = {\n get_code: GetCodeResult\n get_token_defs: GetTokenDefsResult\n get_screenshot: GetScreenshotResult\n get_structure: GetStructureResult\n}\n"],
5
- "mappings": "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",
6
- "names": ["nanoid", "existsSync", "rmSync", "readFileSync", "statSync", "createServer", "join", "port", "resolve", "reject", "join", "existsSync", "statSync", "join", "join", "existsSync", "list", "statSync", "nanoid", "nanoid", "resolve", "reject", "z", "z", "existsSync", "statSync", "readFileSync", "rmSync", "createServer", "resolve", "reject", "nanoid"]
3
+ "sources": ["../src/hub.ts", "../../mcp/shared/constants.ts", "../src/asset-http-server.ts", "../src/config.ts", "../src/shared.ts", "../src/asset-store.ts", "../src/protocol.ts", "../src/request.ts", "../src/tools.ts", "../src/instructions.ts"],
4
+ "sourcesContent": ["import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { RawData } from 'ws'\nimport type { ZodType } from 'zod'\n\nimport { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { nanoid } from 'nanoid'\nimport { existsSync, rmSync, chmodSync, readFileSync, statSync } from 'node:fs'\nimport { createServer } from 'node:net'\nimport { WebSocketServer } from 'ws'\n\nimport type {\n AssetDescriptor,\n GetAssetsParametersInput,\n GetAssetsResult,\n ToolResultMap,\n ToolName\n} from './tools'\nimport type { AssetRecord, ExtensionConnection } from './types'\n\nimport {\n MCP_ASSET_RESOURCE_NAME,\n MCP_ASSET_URI_PREFIX,\n MCP_ASSET_URI_TEMPLATE\n} from '../../mcp/shared/constants'\nimport { createAssetHttpServer } from './asset-http-server'\nimport { createAssetStore } from './asset-store'\nimport { getMcpServerConfig } from './config'\nimport {\n MessageFromExtensionSchema,\n RegisteredMessage,\n StateMessage,\n ToolCallMessage,\n ToolResultMessage\n} from './protocol'\nimport { register, resolve, reject, cleanupForExtension, cleanupAll } from './request'\nimport { log, RUNTIME_DIR, SOCK_PATH, ensureDir } from './shared'\nimport {\n GetAssetsResultSchema,\n TOOL_DEFS,\n MCP_INSTRUCTIONS,\n coercePayloadToToolResponse,\n createToolErrorResponse\n} from './tools'\n\nconst SHUTDOWN_TIMEOUT = 2000\nconst { wsPortCandidates, toolTimeoutMs, maxPayloadBytes, autoActivateGraceMs } =\n getMcpServerConfig()\n\nconst extensions: ExtensionConnection[] = []\nlet consumerCount = 0\ntype TimeoutHandle = ReturnType<typeof setTimeout>\nlet autoActivateTimer: TimeoutHandle | null = null\nlet selectedWsPort = 0\n\nconst mcp = new McpServer(\n { name: 'tempad-dev-mcp', version: '0.1.0' },\n MCP_INSTRUCTIONS ? { instructions: MCP_INSTRUCTIONS } : undefined\n)\ntype McpInputSchema = Parameters<typeof mcp.registerTool>[1]['inputSchema']\ntype McpOutputSchema = Parameters<typeof mcp.registerTool>[1]['outputSchema']\ntype ToolResponse = CallToolResult\ntype SchemaOutput<Schema extends ZodType> = Schema['_output']\ntype ToolMetadataEntry = (typeof TOOL_DEFS)[number]\ntype ExtensionToolMetadata = Extract<ToolMetadataEntry, { target: 'extension' }>\ntype HubToolMetadata = Extract<ToolMetadataEntry, { target: 'hub' }>\n\ntype HubToolWithHandler<T extends HubToolMetadata = HubToolMetadata> = T & {\n handler: (args: SchemaOutput<T['parameters']>) => Promise<ToolResponse>\n}\n\ntype RegisteredToolDefinition = ExtensionToolMetadata | HubToolWithHandler\n\nfunction enrichToolDefinition(tool: ToolMetadataEntry): RegisteredToolDefinition {\n if (tool.target === 'extension') {\n return tool\n }\n\n switch (tool.name) {\n case 'get_assets':\n return {\n ...tool,\n handler: handleGetAssets\n } satisfies HubToolWithHandler\n default:\n throw new Error('No handler configured for hub tool.')\n }\n}\n\nconst TOOL_DEFINITIONS: ReadonlyArray<RegisteredToolDefinition> = TOOL_DEFS.map((tool) =>\n enrichToolDefinition(tool)\n)\n\ntype RegisteredTool = (typeof TOOL_DEFINITIONS)[number]\ntype ExtensionTool = Extract<RegisteredTool, { target: 'extension' }>\ntype HubOnlyTool = Extract<RegisteredTool, { target: 'hub' }>\n\nfunction hasFormatter(tool: RegisteredToolDefinition): tool is ExtensionTool & {\n format: (payload: unknown) => ToolResponse\n} {\n return tool.target === 'extension' && 'format' in tool\n}\n\ntype ToolDefinitionByName = {\n [T in RegisteredToolDefinition as T['name']]: T\n}\n\nconst TOOL_BY_NAME: ToolDefinitionByName = Object.fromEntries(\n TOOL_DEFINITIONS.map((tool) => [tool.name, tool] as const)\n) as ToolDefinitionByName\n\nfunction getToolDefinition<Name extends ToolName>(name: Name): ToolDefinitionByName[Name] {\n return TOOL_BY_NAME[name]\n}\n\nconst assetStore = createAssetStore()\nconst assetHttpServer = createAssetHttpServer(assetStore)\nawait assetHttpServer.start()\nregisterAssetResources()\n\nfunction registerAssetResources(): void {\n const template = new ResourceTemplate(MCP_ASSET_URI_TEMPLATE, {\n list: async () => ({\n resources: assetStore\n .list()\n .filter((record) => existsSync(record.filePath))\n .map((record) => ({\n uri: buildAssetResourceUri(record.hash),\n name: formatAssetResourceName(record.hash),\n description: `${record.mimeType} (${formatBytes(record.size)})`,\n mimeType: record.mimeType\n }))\n })\n })\n\n mcp.registerResource(\n MCP_ASSET_RESOURCE_NAME,\n template,\n {\n description: 'Binary assets captured by the TemPad Dev hub.'\n },\n async (_uri, variables) => {\n const hash = typeof variables.hash === 'string' ? variables.hash : ''\n return readAssetResource(hash)\n }\n )\n}\n\nasync function readAssetResource(hash: string) {\n if (!hash) {\n throw new Error('Missing asset hash in resource URI.')\n }\n const record = assetStore.get(hash)\n if (!record) {\n throw new Error(`Asset ${hash} not found.`)\n }\n\n if (!existsSync(record.filePath)) {\n assetStore.remove(hash, { removeFile: false })\n throw new Error(`Asset ${hash} file is missing.`)\n }\n\n const stat = statSync(record.filePath)\n // Base64 encoding increases size by ~33% (4 bytes for every 3 bytes)\n const estimatedSize = Math.ceil(stat.size / 3) * 4\n if (estimatedSize > maxPayloadBytes) {\n throw new Error(\n `Asset ${hash} is too large (${formatBytes(stat.size)}, encoded: ${formatBytes(estimatedSize)}) to read via MCP protocol. Use HTTP download.`\n )\n }\n\n assetStore.touch(hash)\n const buffer = readFileSync(record.filePath)\n const resourceUri = buildAssetResourceUri(hash)\n\n if (isTextualMime(record.mimeType)) {\n return {\n contents: [\n {\n uri: resourceUri,\n mimeType: record.mimeType,\n text: buffer.toString('utf8')\n }\n ]\n }\n }\n\n return {\n contents: [\n {\n uri: resourceUri,\n mimeType: record.mimeType,\n blob: buffer.toString('base64')\n }\n ]\n }\n}\n\nfunction isTextualMime(mimeType: string): boolean {\n return mimeType === 'image/svg+xml' || mimeType.startsWith('text/')\n}\n\nfunction buildAssetResourceUri(hash: string): string {\n return `${MCP_ASSET_URI_PREFIX}${hash}`\n}\n\nfunction formatAssetResourceName(hash: string): string {\n return `asset:${hash.slice(0, 8)}`\n}\n\nfunction buildAssetDescriptor(record: AssetRecord): AssetDescriptor {\n return {\n hash: record.hash,\n url: `${assetHttpServer.getBaseUrl()}/assets/${record.hash}`,\n mimeType: record.mimeType,\n size: record.size,\n resourceUri: buildAssetResourceUri(record.hash),\n width: record.metadata?.width,\n height: record.metadata?.height\n }\n}\n\nfunction createAssetResourceLinkBlock(asset: AssetDescriptor) {\n return {\n type: 'resource_link' as const,\n name: formatAssetResourceName(asset.hash),\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `${describeAsset(asset)} - Download: ${asset.url}`\n }\n}\n\nfunction describeAsset(asset: AssetDescriptor): string {\n return `${asset.mimeType} (${formatBytes(asset.size)})`\n}\n\nfunction registerTools(): void {\n const registered: string[] = []\n for (const tool of TOOL_DEFINITIONS) {\n if ('exposed' in tool && tool.exposed === false) continue\n registerTool(tool)\n registered.push(tool.name)\n }\n log.info({ tools: registered }, 'Registered tools.')\n}\n\nregisterTools()\nfunction registerTool(tool: RegisteredTool): void {\n if (tool.target === 'extension') {\n registerProxiedTool(tool)\n } else {\n registerLocalTool(tool)\n }\n}\n\nfunction registerProxiedTool<T extends ExtensionTool>(tool: T): void {\n type Name = T['name']\n type Result = ToolResultMap[Name]\n\n const schema = tool.parameters\n mcp.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: schema as unknown as McpInputSchema\n },\n async (args: unknown) => {\n try {\n const parsedArgs = schema.parse(args)\n const activeExt = extensions.find((e) => e.active)\n if (!activeExt) throw new Error('No active TemPad Dev extension available.')\n\n const { promise, requestId } = register<Result>(activeExt.id, toolTimeoutMs)\n\n const message: ToolCallMessage = {\n type: 'toolCall',\n id: requestId,\n payload: {\n name: tool.name,\n args: parsedArgs\n }\n }\n activeExt.ws.send(JSON.stringify(message))\n log.info({ tool: tool.name, req: requestId, extId: activeExt.id }, 'Forwarded tool call.')\n\n const payload = await promise\n return createToolResponse(tool.name, payload)\n } catch (error) {\n log.error({ tool: tool.name, error }, 'Tool invocation failed before reaching extension.')\n return createToolErrorResponse(tool.name, error)\n }\n }\n )\n}\n\nfunction registerLocalTool(tool: HubOnlyTool): void {\n const schema = tool.parameters\n const handler = tool.handler\n\n const registrationOptions: {\n description: string\n inputSchema: McpInputSchema\n outputSchema?: McpOutputSchema\n } = {\n description: tool.description,\n inputSchema: schema as unknown as McpInputSchema\n }\n\n if (tool.outputSchema) {\n registrationOptions.outputSchema = tool.outputSchema as unknown as McpOutputSchema\n }\n\n mcp.registerTool(tool.name, registrationOptions, async (args: unknown) => {\n try {\n const parsed = schema.parse(args)\n return await handler(parsed)\n } catch (error) {\n log.error({ tool: tool.name, error }, 'Local tool invocation failed.')\n return createToolErrorResponse(tool.name, error)\n }\n })\n}\n\nfunction createToolResponse<Name extends ToolName>(\n toolName: Name,\n payload: ToolResultMap[Name]\n): ToolResponse {\n const definition = getToolDefinition(toolName)\n if (definition && hasFormatter(definition)) {\n try {\n const formatter = definition.format as (input: ToolResultMap[Name]) => ToolResponse\n return formatter(payload)\n } catch (error) {\n log.warn({ tool: toolName, error }, 'Failed to format tool result; returning raw payload.')\n return coercePayloadToToolResponse(payload)\n }\n }\n\n return coercePayloadToToolResponse(payload)\n}\n\nasync function handleGetAssets({ hashes }: GetAssetsParametersInput): Promise<ToolResponse> {\n if (hashes.length > 100) {\n throw new Error('Too many hashes requested. Limit is 100.')\n }\n const unique = Array.from(new Set(hashes))\n const records = assetStore.getMany(unique).filter((record) => {\n if (existsSync(record.filePath)) return true\n assetStore.remove(record.hash, { removeFile: false })\n return false\n })\n const found = new Set(records.map((record) => record.hash))\n const payload: GetAssetsResult = GetAssetsResultSchema.parse({\n assets: records.map((record) => buildAssetDescriptor(record)),\n missing: unique.filter((hash) => !found.has(hash))\n })\n\n const summary: string[] = []\n summary.push(\n payload.assets.length\n ? `Resolved ${payload.assets.length} asset${payload.assets.length === 1 ? '' : 's'}.`\n : 'No assets were resolved for the requested hashes.'\n )\n if (payload.missing.length) {\n summary.push(`Missing: ${payload.missing.join(', ')}`)\n }\n summary.push(\n 'Use resources/read with each resourceUri or fetch the fallback URL to download bytes.'\n )\n\n const content = [\n {\n type: 'text' as const,\n text: summary.join('\\n')\n },\n ...payload.assets.map((asset) => createAssetResourceLinkBlock(asset))\n ]\n\n return {\n content,\n structuredContent: payload\n }\n}\n\nfunction getActiveId(): string | null {\n return extensions.find((e) => e.active)?.id ?? null\n}\n\nfunction setActive(targetId: string | null): void {\n extensions.forEach((e) => {\n e.active = targetId !== null && e.id === targetId\n })\n}\n\nfunction clearAutoActivateTimer(): void {\n if (autoActivateTimer) {\n clearTimeout(autoActivateTimer)\n autoActivateTimer = null\n }\n}\n\nfunction scheduleAutoActivate(): void {\n clearAutoActivateTimer()\n\n if (extensions.length !== 1 || getActiveId()) {\n return\n }\n\n const target = extensions[0]\n autoActivateTimer = setTimeout(() => {\n autoActivateTimer = null\n if (extensions.length === 1 && !getActiveId()) {\n setActive(target.id)\n log.info({ id: target.id }, 'Auto-activated sole extension after grace period.')\n broadcastState()\n }\n }, autoActivateGraceMs)\n}\n\nfunction unrefTimer(timer: TimeoutHandle): void {\n if (typeof timer === 'object' && timer !== null) {\n const handle = timer as NodeJS.Timeout\n if (typeof handle.unref === 'function') {\n handle.unref()\n }\n }\n}\n\nfunction broadcastState(): void {\n const activeId = getActiveId()\n const message: StateMessage = {\n type: 'state',\n activeId,\n count: extensions.length,\n port: selectedWsPort,\n assetServerUrl: assetHttpServer.getBaseUrl()\n }\n extensions.forEach((ext) => ext.ws.send(JSON.stringify(message)))\n log.debug({ activeId, count: extensions.length }, 'Broadcasted state.')\n}\n\nfunction rawDataToBuffer(raw: RawData): Buffer {\n if (typeof raw === 'string') return Buffer.from(raw)\n if (Buffer.isBuffer(raw)) return raw\n if (raw instanceof ArrayBuffer) return Buffer.from(raw)\n return Buffer.concat(raw)\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction shutdown(): void {\n log.info('Hub is shutting down...')\n assetStore.flush()\n assetHttpServer.stop()\n netServer.close(() => log.info('Net server closed.'))\n wss?.close(() => log.info('WebSocket server closed.'))\n cleanupAll()\n const timer = setTimeout(() => {\n log.warn('Shutdown timed out. Forcing exit.')\n process.exit(1)\n }, SHUTDOWN_TIMEOUT)\n unrefTimer(timer)\n}\n\ntry {\n ensureDir(RUNTIME_DIR)\n if (process.platform !== 'win32' && existsSync(SOCK_PATH)) {\n log.warn({ sock: SOCK_PATH }, 'Removing stale socket file.')\n rmSync(SOCK_PATH)\n }\n} catch (error: unknown) {\n log.error({ err: error }, 'Failed to initialize runtime environment.')\n process.exit(1)\n}\n\nconst netServer = createServer((sock) => {\n consumerCount++\n log.info(`Consumer connected. Total: ${consumerCount}`)\n const transport = new StdioServerTransport(sock, sock)\n mcp.connect(transport).catch((err) => {\n log.error({ err }, 'Failed to attach MCP transport.')\n transport.close().catch((closeErr) => log.warn({ err: closeErr }, 'Transport close failed.'))\n sock.destroy()\n })\n sock.on('error', (err) => {\n log.warn({ err }, 'Consumer socket error.')\n transport.close().catch((closeErr) => log.warn({ err: closeErr }, 'Transport close failed.'))\n })\n sock.on('close', async () => {\n await transport.close()\n consumerCount--\n log.info(`Consumer disconnected. Remaining: ${consumerCount}`)\n if (consumerCount === 0) {\n log.info('Last consumer disconnected. Shutting down.')\n shutdown()\n }\n })\n})\nnetServer.on('error', (err) => {\n log.error({ err }, 'Net server error.')\n process.exit(1)\n})\nnetServer.listen(SOCK_PATH, () => {\n try {\n if (process.platform !== 'win32') chmodSync(SOCK_PATH, 0o600)\n } catch (err) {\n log.error({ err }, 'Failed to set socket permissions. Shutting down.')\n process.exit(1)\n }\n log.info({ sock: SOCK_PATH }, 'Hub socket ready.')\n})\n\nasync function startWebSocketServer(): Promise<{ wss: WebSocketServer; port: number }> {\n for (const candidate of wsPortCandidates) {\n const server = new WebSocketServer({\n host: '127.0.0.1',\n port: candidate,\n maxPayload: maxPayloadBytes\n })\n\n try {\n await new Promise<void>((resolve, reject) => {\n const onError = (err: NodeJS.ErrnoException) => {\n server.off('listening', onListening)\n reject(err)\n }\n const onListening = () => {\n server.off('error', onError)\n resolve()\n }\n server.once('error', onError)\n server.once('listening', onListening)\n })\n return { wss: server, port: candidate }\n } catch (err) {\n server.close()\n const errno = err as NodeJS.ErrnoException\n if (errno.code === 'EADDRINUSE') {\n log.warn({ port: candidate }, 'WebSocket port in use, trying next candidate.')\n continue\n }\n log.error({ err: errno, port: candidate }, 'Failed to start WebSocket server.')\n process.exit(1)\n }\n }\n\n log.error(\n { candidates: wsPortCandidates },\n 'Unable to start WebSocket server on any candidate port.'\n )\n process.exit(1)\n}\n\nconst { wss, port } = await startWebSocketServer()\nselectedWsPort = port\n\n// Add an error handler to prevent crashes from port conflicts, etc.\nwss.on('error', (err) => {\n log.error({ err }, 'WebSocket server critical error. Exiting.')\n process.exit(1)\n})\n\nwss.on('connection', (ws) => {\n const ext: ExtensionConnection = { id: nanoid(), ws, active: false }\n extensions.push(ext)\n log.info({ id: ext.id }, `Extension connected. Total: ${extensions.length}`)\n\n const message: RegisteredMessage = { type: 'registered', id: ext.id }\n ws.send(JSON.stringify(message))\n broadcastState()\n scheduleAutoActivate()\n\n ws.on('message', (raw: RawData, isBinary: boolean) => {\n if (isBinary) {\n log.warn({ extId: ext.id }, 'Unexpected binary message received.')\n return\n }\n\n const messageBuffer = rawDataToBuffer(raw)\n\n let parsedJson: unknown\n try {\n parsedJson = JSON.parse(messageBuffer.toString('utf-8'))\n } catch (e: unknown) {\n log.warn({ err: e, extId: ext.id }, 'Failed to parse message.')\n return\n }\n\n const parseResult = MessageFromExtensionSchema.safeParse(parsedJson)\n if (!parseResult.success) {\n log.warn({ error: parseResult.error.flatten(), extId: ext.id }, 'Invalid message shape.')\n return\n }\n const msg = parseResult.data\n\n switch (msg.type) {\n case 'activate': {\n setActive(ext.id)\n log.info({ id: ext.id }, 'Extension activated.')\n broadcastState()\n scheduleAutoActivate()\n break\n }\n case 'toolResult': {\n const { id, payload, error } = msg as ToolResultMessage\n if (error) {\n reject(id, error instanceof Error ? error : new Error(String(error)))\n } else {\n resolve(id, payload)\n }\n break\n }\n }\n })\n\n ws.on('close', () => {\n const index = extensions.findIndex((e) => e.id === ext.id)\n if (index > -1) extensions.splice(index, 1)\n\n log.info({ id: ext.id }, `Extension disconnected. Remaining: ${extensions.length}`)\n cleanupForExtension(ext.id)\n\n if (ext.active) {\n log.warn({ id: ext.id }, 'Active extension disconnected.')\n setActive(null)\n }\n\n broadcastState()\n scheduleAutoActivate()\n })\n})\n\nlog.info({ port: selectedWsPort }, 'WebSocket server ready.')\n\nprocess.on('SIGINT', shutdown)\nprocess.on('SIGTERM', shutdown)\n", "export const MCP_PORT_CANDIDATES = [6220, 7431, 8127]\n\n// Upper bound for MCP message payloads in bytes.\nexport const MCP_MAX_PAYLOAD_BYTES = 4 * 1024 * 1024\n\n// Default tool timeout used by the MCP hub (ms).\nexport const MCP_TOOL_TIMEOUT_MS = 15000\n\n// Grace period before auto-activating the sole extension (ms).\nexport const MCP_AUTO_ACTIVATE_GRACE_MS = 1500\n\n// Maximum allowed size for uploaded assets (bytes).\nexport const MCP_MAX_ASSET_BYTES = 8 * 1024 * 1024\n\nexport const MCP_ASSET_RESOURCE_NAME = 'tempad-assets'\nexport const MCP_ASSET_URI_PREFIX = 'asset://tempad/'\nexport const MCP_ASSET_URI_TEMPLATE = `${MCP_ASSET_URI_PREFIX}{hash}`\n\nexport const MCP_HASH_PATTERN = /^[a-f0-9]{64}$/i\n", "import { nanoid } from 'nanoid'\nimport { createHash } from 'node:crypto'\nimport {\n createReadStream,\n createWriteStream,\n existsSync,\n renameSync,\n statSync,\n unlinkSync\n} from 'node:fs'\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http'\nimport { join } from 'node:path'\nimport { pipeline, Transform } from 'node:stream'\nimport { URL } from 'node:url'\n\nimport type { AssetStore } from './asset-store'\n\nimport { MCP_HASH_PATTERN } from '../../mcp/shared/constants'\nimport { getMcpServerConfig } from './config'\nimport { ASSET_DIR, log } from './shared'\n\nconst LOOPBACK_HOST = '127.0.0.1'\nconst { maxAssetSizeBytes } = getMcpServerConfig()\n\nexport interface AssetHttpServer {\n start(): Promise<void>\n stop(): void\n getBaseUrl(): string\n}\n\nexport function createAssetHttpServer(store: AssetStore): AssetHttpServer {\n const server = createServer(handleRequest)\n let port: number | null = null\n\n async function start(): Promise<void> {\n if (port !== null) return\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n server.off('listening', onListening)\n reject(error)\n }\n const onListening = () => {\n server.off('error', onError)\n const address = server.address()\n if (address && typeof address === 'object') {\n port = address.port\n resolve()\n } else {\n reject(new Error('Failed to determine HTTP server port.'))\n }\n }\n server.once('error', onError)\n server.once('listening', onListening)\n server.listen(0, LOOPBACK_HOST)\n })\n log.info({ port }, 'Asset HTTP server ready.')\n }\n\n function stop(): void {\n if (port === null) return\n server.close()\n port = null\n }\n\n function getBaseUrl(): string {\n if (port === null) throw new Error('Asset HTTP server is not running.')\n return `http://${LOOPBACK_HOST}:${port}`\n }\n\n function handleRequest(req: IncomingMessage, res: ServerResponse): void {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Asset-Width, X-Asset-Height')\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204)\n res.end()\n return\n }\n\n if (!req.url) {\n res.writeHead(400)\n res.end('Missing URL')\n return\n }\n\n const url = new URL(req.url, getBaseUrl())\n const segments = url.pathname.split('/').filter(Boolean)\n if (segments.length !== 2 || segments[0] !== 'assets') {\n res.writeHead(404)\n res.end('Not Found')\n return\n }\n\n const hash = segments[1]\n\n if (req.method === 'POST') {\n handleUpload(req, res, hash)\n return\n }\n\n if (req.method === 'GET') {\n handleDownload(req, res, hash)\n return\n }\n\n res.writeHead(405)\n res.end('Method Not Allowed')\n }\n\n function handleDownload(req: IncomingMessage, res: ServerResponse, hash: string): void {\n const record = store.get(hash)\n if (!record) {\n res.writeHead(404)\n res.end('Not Found')\n return\n }\n\n let stat\n try {\n stat = statSync(record.filePath)\n } catch (error) {\n const err = error as NodeJS.ErrnoException\n if (err.code === 'ENOENT') {\n store.remove(hash, { removeFile: false })\n res.writeHead(404)\n res.end('Not Found')\n } else {\n log.error({ error, hash }, 'Failed to stat asset file.')\n res.writeHead(500)\n res.end('Internal Server Error')\n }\n return\n }\n\n res.writeHead(200, {\n 'Content-Type': record.mimeType,\n 'Content-Length': stat.size.toString(),\n 'Cache-Control': 'public, max-age=31536000, immutable'\n })\n\n const stream = createReadStream(record.filePath)\n stream.on('error', (error) => {\n log.warn({ error, hash }, 'Failed to stream asset file.')\n if (!res.headersSent) {\n res.writeHead(500)\n }\n res.end('Internal Server Error')\n })\n stream.on('open', () => {\n store.touch(hash)\n })\n stream.pipe(res)\n }\n\n function handleUpload(req: IncomingMessage, res: ServerResponse, hash: string): void {\n if (!MCP_HASH_PATTERN.test(hash)) {\n res.writeHead(400)\n res.end('Invalid Hash Format')\n return\n }\n\n const mimeType = req.headers['content-type'] || 'application/octet-stream'\n const filePath = join(ASSET_DIR, hash)\n\n const width = parseInt(req.headers['x-asset-width'] as string, 10)\n const height = parseInt(req.headers['x-asset-height'] as string, 10)\n const metadata =\n !isNaN(width) && !isNaN(height) && width > 0 && height > 0 ? { width, height } : undefined\n\n // If asset already exists and file is present, skip write\n if (store.has(hash) && existsSync(filePath)) {\n // Drain request to ensure connection is clean\n req.resume()\n\n const existing = store.get(hash)!\n let changed = false\n if (metadata) {\n existing.metadata = metadata\n changed = true\n }\n if (existing.mimeType !== mimeType) {\n existing.mimeType = mimeType\n changed = true\n }\n if (changed) {\n store.upsert(existing)\n }\n store.touch(hash)\n res.writeHead(200)\n res.end('OK')\n return\n }\n\n const tmpPath = `${filePath}.tmp.${nanoid()}`\n const writeStream = createWriteStream(tmpPath)\n const hasher = createHash('sha256')\n let size = 0\n\n const cleanup = () => {\n if (existsSync(tmpPath)) {\n try {\n unlinkSync(tmpPath)\n } catch (e) {\n log.warn({ error: e, tmpPath }, 'Failed to cleanup temp file.')\n }\n }\n }\n\n const monitor = new Transform({\n transform(chunk, encoding, callback) {\n size += chunk.length\n if (size > maxAssetSizeBytes) {\n callback(new Error('PayloadTooLarge'))\n return\n }\n hasher.update(chunk)\n callback(null, chunk)\n }\n })\n\n pipeline(req, monitor, writeStream, (err) => {\n if (err) {\n cleanup()\n if (err.message === 'PayloadTooLarge') {\n res.writeHead(413)\n res.end('Payload Too Large')\n } else if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') {\n log.warn({ hash }, 'Upload request closed prematurely.')\n } else {\n log.error({ error: err, hash }, 'Upload pipeline failed.')\n if (!res.headersSent) {\n res.writeHead(500)\n res.end('Internal Server Error')\n }\n }\n return\n }\n\n const computedHash = hasher.digest('hex')\n if (computedHash !== hash) {\n cleanup()\n res.writeHead(400)\n res.end('Hash Mismatch')\n return\n }\n\n try {\n renameSync(tmpPath, filePath)\n } catch (error) {\n log.error({ error, hash }, 'Failed to rename temp file to asset.')\n cleanup()\n res.writeHead(500)\n res.end('Internal Server Error')\n return\n }\n\n store.upsert({\n hash,\n filePath,\n mimeType,\n size,\n metadata\n })\n log.info({ hash, size }, 'Stored uploaded asset via HTTP.')\n res.writeHead(201)\n res.end('Created')\n })\n }\n\n return {\n start,\n stop,\n getBaseUrl\n }\n}\n", "import {\n MCP_AUTO_ACTIVATE_GRACE_MS,\n MCP_MAX_ASSET_BYTES,\n MCP_MAX_PAYLOAD_BYTES,\n MCP_PORT_CANDIDATES,\n MCP_TOOL_TIMEOUT_MS\n} from '../../mcp/shared/constants'\n\nfunction parsePositiveInt(envValue: string | undefined, fallback: number): number {\n const parsed = envValue ? Number.parseInt(envValue, 10) : Number.NaN\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback\n}\n\nfunction resolveToolTimeoutMs(): number {\n return parsePositiveInt(process.env.TEMPAD_MCP_TOOL_TIMEOUT, MCP_TOOL_TIMEOUT_MS)\n}\n\nfunction resolveAutoActivateGraceMs(): number {\n return parsePositiveInt(process.env.TEMPAD_MCP_AUTO_ACTIVATE_GRACE, MCP_AUTO_ACTIVATE_GRACE_MS)\n}\n\nfunction resolveMaxAssetSizeBytes(): number {\n return parsePositiveInt(process.env.TEMPAD_MCP_MAX_ASSET_BYTES, MCP_MAX_ASSET_BYTES)\n}\n\nexport function getMcpServerConfig() {\n return {\n wsPortCandidates: [...MCP_PORT_CANDIDATES],\n toolTimeoutMs: resolveToolTimeoutMs(),\n maxPayloadBytes: MCP_MAX_PAYLOAD_BYTES,\n autoActivateGraceMs: resolveAutoActivateGraceMs(),\n maxAssetSizeBytes: resolveMaxAssetSizeBytes()\n }\n}\n", "import { closeSync, mkdirSync, openSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport pino from 'pino'\n\nexport function ensureDir(dirPath: string): void {\n mkdirSync(dirPath, { recursive: true, mode: 0o700 })\n}\n\nfunction resolveRuntimeDir(): string {\n if (process.env.TEMPAD_MCP_RUNTIME_DIR) return process.env.TEMPAD_MCP_RUNTIME_DIR\n return join(tmpdir(), 'tempad-dev', 'run')\n}\n\nfunction resolveLogDir(): string {\n if (process.env.TEMPAD_MCP_LOG_DIR) return process.env.TEMPAD_MCP_LOG_DIR\n return join(tmpdir(), 'tempad-dev', 'log')\n}\n\nfunction resolveAssetDir(): string {\n if (process.env.TEMPAD_MCP_ASSET_DIR) return process.env.TEMPAD_MCP_ASSET_DIR\n return join(tmpdir(), 'tempad-dev', 'assets')\n}\n\nexport const RUNTIME_DIR = resolveRuntimeDir()\nexport const LOG_DIR = resolveLogDir()\nexport const ASSET_DIR = resolveAssetDir()\n\nensureDir(RUNTIME_DIR)\nensureDir(LOG_DIR)\nensureDir(ASSET_DIR)\n\nexport function ensureFile(filePath: string): void {\n const fd = openSync(filePath, 'a')\n closeSync(fd)\n}\n\nexport const LOCK_PATH = join(RUNTIME_DIR, 'mcp.lock')\nensureFile(LOCK_PATH)\n\nconst timestamp = new Date().toISOString().replaceAll(':', '-').replaceAll('.', '-')\nconst pid = process.pid\nconst LOG_FILE = join(LOG_DIR, `mcp-${timestamp}-${pid}.log`)\n\nconst prettyTransport = pino.transport({\n target: 'pino-pretty',\n options: {\n translateTime: 'SYS:HH:MM:ss',\n destination: LOG_FILE\n }\n})\n\nexport const log = pino(\n {\n level: process.env.DEBUG ? 'debug' : 'info',\n msgPrefix: '[tempad-dev/mcp] '\n },\n prettyTransport\n)\n\nexport const SOCK_PATH =\n process.platform === 'win32' ? '\\\\\\\\.\\\\pipe\\\\tempad-mcp' : join(RUNTIME_DIR, 'mcp.sock')\n", "import { existsSync, readFileSync, rmSync, writeFileSync, readdirSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { AssetRecord } from './types'\n\nimport { ASSET_DIR, ensureDir, ensureFile, log } from './shared'\n\nconst INDEX_FILENAME = 'assets.json'\nconst DEFAULT_INDEX_PATH = join(ASSET_DIR, INDEX_FILENAME)\n\nexport interface AssetStoreOptions {\n indexPath?: string\n}\n\nexport interface AssetStore {\n list(): AssetRecord[]\n has(hash: string): boolean\n get(hash: string): AssetRecord | undefined\n getMany(hashes: string[]): AssetRecord[]\n upsert(\n input: Omit<AssetRecord, 'uploadedAt' | 'lastAccess'> &\n Partial<Pick<AssetRecord, 'uploadedAt' | 'lastAccess'>>\n ): AssetRecord\n touch(hash: string): AssetRecord | undefined\n remove(hash: string, opts?: { removeFile?: boolean }): void\n reconcile(): void\n flush(): void\n}\n\nfunction readIndex(indexPath: string): AssetRecord[] {\n if (!existsSync(indexPath)) return []\n try {\n const raw = readFileSync(indexPath, 'utf8').trim()\n if (!raw) return []\n const parsed = JSON.parse(raw)\n return Array.isArray(parsed) ? (parsed as AssetRecord[]) : []\n } catch (error) {\n log.warn({ error, indexPath }, 'Failed to read asset catalog; starting fresh.')\n return []\n }\n}\n\nfunction writeIndex(indexPath: string, values: AssetRecord[]): void {\n const payload = JSON.stringify(values, null, 2)\n writeFileSync(indexPath, payload, 'utf8')\n}\n\nexport function createAssetStore(options: AssetStoreOptions = {}): AssetStore {\n ensureDir(ASSET_DIR)\n const indexPath = options.indexPath ?? DEFAULT_INDEX_PATH\n ensureFile(indexPath)\n const records = new Map<string, AssetRecord>()\n let persistTimer: NodeJS.Timeout | null = null\n\n function loadExisting(): void {\n const list = readIndex(indexPath)\n for (const record of list) {\n if (record?.hash && record?.filePath) {\n records.set(record.hash, record)\n }\n }\n }\n\n function persist(): void {\n if (persistTimer) return\n persistTimer = setTimeout(() => {\n persistTimer = null\n writeIndex(indexPath, [...records.values()])\n }, 5000)\n if (typeof persistTimer.unref === 'function') {\n persistTimer.unref()\n }\n }\n\n function flush(): void {\n if (persistTimer) {\n clearTimeout(persistTimer)\n persistTimer = null\n }\n writeIndex(indexPath, [...records.values()])\n }\n\n function list(): AssetRecord[] {\n return [...records.values()]\n }\n\n function has(hash: string): boolean {\n return records.has(hash)\n }\n\n function get(hash: string): AssetRecord | undefined {\n return records.get(hash)\n }\n\n function getMany(hashes: string[]): AssetRecord[] {\n return hashes\n .map((hash) => records.get(hash))\n .filter((record): record is AssetRecord => !!record)\n }\n\n function upsert(\n input: Omit<AssetRecord, 'uploadedAt' | 'lastAccess'> &\n Partial<Pick<AssetRecord, 'uploadedAt' | 'lastAccess'>>\n ): AssetRecord {\n const now = Date.now()\n const record: AssetRecord = {\n ...input,\n uploadedAt: input.uploadedAt ?? now,\n lastAccess: input.lastAccess ?? now\n }\n records.set(record.hash, record)\n persist()\n return record\n }\n\n function touch(hash: string): AssetRecord | undefined {\n const existing = records.get(hash)\n if (!existing) return undefined\n existing.lastAccess = Date.now()\n persist()\n return existing\n }\n\n function remove(hash: string, { removeFile = true } = {}): void {\n const record = records.get(hash)\n if (!record) return\n records.delete(hash)\n persist()\n\n if (removeFile) {\n try {\n rmSync(record.filePath, { force: true })\n } catch (error) {\n log.warn({ hash, error }, 'Failed to remove asset file on delete.')\n }\n }\n }\n\n function reconcile(): void {\n let changed = false\n for (const [hash, record] of records) {\n if (!existsSync(record.filePath)) {\n records.delete(hash)\n changed = true\n }\n }\n\n try {\n const files = readdirSync(ASSET_DIR)\n const now = Date.now()\n for (const file of files) {\n if (file === INDEX_FILENAME) continue\n\n // Cleanup stale tmp files (> 1 hour)\n if (file.includes('.tmp.')) {\n try {\n const filePath = join(ASSET_DIR, file)\n const stat = statSync(filePath)\n if (now - stat.mtimeMs > 3600 * 1000) {\n rmSync(filePath, { force: true })\n log.info({ file }, 'Cleaned up stale temp file.')\n }\n } catch (e) {\n // Ignore errors during cleanup\n log.debug({ error: e, file }, 'Failed to cleanup stale temp file.')\n }\n continue\n }\n\n if (!/^[a-f0-9]{64}$/i.test(file)) continue\n\n if (!records.has(file)) {\n const filePath = join(ASSET_DIR, file)\n try {\n const stat = statSync(filePath)\n records.set(file, {\n hash: file,\n filePath,\n mimeType: 'application/octet-stream',\n size: stat.size,\n uploadedAt: stat.birthtimeMs,\n lastAccess: stat.atimeMs\n })\n changed = true\n log.info({ hash: file }, 'Recovered orphan asset file.')\n } catch (e) {\n log.warn({ error: e, file }, 'Failed to stat orphan file.')\n }\n }\n }\n } catch (error) {\n log.warn({ error }, 'Failed to scan asset directory for orphans.')\n }\n\n if (changed) flush()\n }\n\n loadExisting()\n reconcile()\n\n return {\n list,\n has,\n get,\n getMany,\n upsert,\n touch,\n remove,\n reconcile,\n flush\n }\n}\n", "import { z } from 'zod'\n\n// Messages from hub to extension\nexport const RegisteredMessageSchema = z.object({\n type: z.literal('registered'),\n id: z.string()\n})\n\nexport const StateMessageSchema = z.object({\n type: z.literal('state'),\n activeId: z.string().nullable(),\n count: z.number().nonnegative(),\n port: z.number().positive(),\n assetServerUrl: z.string().url()\n})\n\nexport const ToolCallPayloadSchema = z.object({\n name: z.string(),\n args: z.unknown()\n})\n\nexport const ToolCallMessageSchema = z.object({\n type: z.literal('toolCall'),\n id: z.string(),\n payload: ToolCallPayloadSchema\n})\n\nexport const MessageToExtensionSchema = z.discriminatedUnion('type', [\n RegisteredMessageSchema,\n StateMessageSchema,\n ToolCallMessageSchema\n])\n\n// Messages from extension to hub\nexport const ActivateMessageSchema = z.object({\n type: z.literal('activate')\n})\n\nexport const ToolResultMessageSchema = z.object({\n type: z.literal('toolResult'),\n id: z.string(),\n payload: z.unknown().optional(),\n error: z.unknown().optional()\n})\n\nexport const MessageFromExtensionSchema = z.discriminatedUnion('type', [\n ActivateMessageSchema,\n ToolResultMessageSchema\n])\n\nexport type RegisteredMessage = z.infer<typeof RegisteredMessageSchema>\nexport type StateMessage = z.infer<typeof StateMessageSchema>\nexport type ToolCallPayload = z.infer<typeof ToolCallPayloadSchema>\nexport type ToolCallMessage = z.infer<typeof ToolCallMessageSchema>\nexport type MessageToExtension = z.infer<typeof MessageToExtensionSchema>\nexport type ActivateMessage = z.infer<typeof ActivateMessageSchema>\nexport type ToolResultMessage = z.infer<typeof ToolResultMessageSchema>\nexport type MessageFromExtension = z.infer<typeof MessageFromExtensionSchema>\n\nexport function parseMessageToExtension(data: string): MessageToExtension | null {\n let parsed: unknown\n try {\n parsed = JSON.parse(data)\n } catch {\n return null\n }\n const result = MessageToExtensionSchema.safeParse(parsed)\n return result.success ? result.data : null\n}\n\nexport function parseMessageFromExtension(data: string): MessageFromExtension | null {\n let parsed: unknown\n try {\n parsed = JSON.parse(data)\n } catch {\n return null\n }\n const result = MessageFromExtensionSchema.safeParse(parsed)\n return result.success ? result.data : null\n}\n", "import { nanoid } from 'nanoid'\n\nimport type { PendingToolCall } from './types'\n\nimport { log } from './shared'\n\nconst pendingCalls = new Map<string, PendingToolCall>()\n\nexport function register<T>(\n extensionId: string,\n timeout: number\n): { promise: Promise<T>; requestId: string } {\n const requestId = nanoid()\n const promise = new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingCalls.delete(requestId)\n reject(new Error(`Extension did not respond within ${timeout / 1000}s.`))\n }, timeout)\n\n pendingCalls.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timer,\n extensionId\n })\n })\n return { promise, requestId }\n}\n\nexport function resolve(requestId: string, payload: unknown): void {\n const call = pendingCalls.get(requestId)\n if (call) {\n const { timer, resolve: finish } = call\n clearTimeout(timer)\n finish(payload)\n pendingCalls.delete(requestId)\n } else {\n log.warn({ reqId: requestId }, 'Received result for unknown/timed-out call.')\n }\n}\n\nexport function reject(requestId: string, error: Error): void {\n const call = pendingCalls.get(requestId)\n if (call) {\n const { timer, reject: fail } = call\n clearTimeout(timer)\n fail(error)\n pendingCalls.delete(requestId)\n } else {\n log.warn({ reqId: requestId }, 'Received error for unknown/timed-out call.')\n }\n}\n\nexport function cleanupForExtension(extensionId: string): void {\n for (const [reqId, call] of pendingCalls.entries()) {\n const { timer, reject: fail, extensionId: extId } = call\n if (extId === extensionId) {\n clearTimeout(timer)\n fail(new Error('Extension disconnected before providing a result.'))\n pendingCalls.delete(reqId)\n log.warn({ reqId, extId: extensionId }, 'Rejected pending call from disconnected extension.')\n }\n }\n}\n\nexport function cleanupAll(): void {\n pendingCalls.forEach((call, reqId) => {\n const { timer, reject: fail } = call\n clearTimeout(timer)\n fail(new Error('Hub is shutting down.'))\n log.debug({ reqId }, 'Rejected pending tool call due to shutdown.')\n })\n pendingCalls.clear()\n}\n", "import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodType } from 'zod'\n\nimport { z } from 'zod'\n\nimport type { AssetDescriptor } from '../../mcp/shared/types'\n\nimport { MCP_HASH_PATTERN } from '../../mcp/shared/constants'\n\nexport type { AssetDescriptor }\n\n// get_code\nexport const GetCodeParametersSchema = z.object({\n nodeId: z\n .string()\n .describe('Optional node id to target; defaults to the current single selection.')\n .optional(),\n preferredLang: z\n .enum(['jsx', 'vue'])\n .describe('Preferred output language; otherwise uses the design\u2019s hint/detected language, then JSX.')\n .optional(),\n resolveTokens: z\n .boolean()\n .describe('Resolve token references to concrete values; default false returns token metadata.')\n .optional()\n})\n\nexport type GetCodeParametersInput = z.input<typeof GetCodeParametersSchema>\nexport type GetCodeResult = {\n code: string\n lang: 'vue' | 'jsx'\n message?: string\n usedTokens?: GetTokenDefsResult['tokens']\n assets: AssetDescriptor[]\n codegen: {\n preset: string\n config: {\n cssUnit: 'px' | 'rem'\n rootFontSize: number\n scale: number\n }\n }\n}\n\n// get_token_defs\nexport const GetTokenDefsParametersSchema = z.object({\n names: z\n .array(z.string().regex(/^--[a-zA-Z0-9-_]+$/))\n .min(1)\n .describe('Canonical token names (CSS variable form) to resolve, e.g., --color-primary.'),\n includeAllModes: z\n .boolean()\n .describe('Include all token modes instead of just the active one; default false.')\n .optional()\n})\n\nexport type GetTokenDefsParametersInput = z.input<typeof GetTokenDefsParametersSchema>\nexport type GetTokenDefsResult = {\n tokens: Array<{\n name: string\n value: string | Record<string, unknown> | null\n current: {\n modeId: string\n value?: string | Record<string, unknown>\n aliasTo?: string\n resolved: string | Record<string, unknown> | null\n aliasChain?: string[]\n }\n modes?: Array<{\n modeId: string\n value?: string | Record<string, unknown>\n aliasTo?: string\n resolved: string | Record<string, unknown> | null\n }>\n collection?: {\n id?: string\n name?: string\n activeModeId?: string\n defaultModeId?: string\n }\n kind: 'color' | 'spacing' | 'typography' | 'effect' | 'other'\n }>\n}\n\nexport const AssetDescriptorSchema = z.object({\n hash: z.string().min(1),\n url: z.string().url(),\n mimeType: z.string().min(1),\n size: z.number().int().nonnegative(),\n resourceUri: z.string().regex(/^asset:\\/\\/tempad\\/[a-f0-9]{64}$/i),\n width: z.number().int().positive().optional(),\n height: z.number().int().positive().optional()\n})\n\n// get_screenshot\nexport const GetScreenshotParametersSchema = z.object({\n nodeId: z\n .string()\n .describe('Optional node id to screenshot; defaults to the current single selection.')\n .optional()\n})\n\nexport type GetScreenshotParametersInput = z.input<typeof GetScreenshotParametersSchema>\nexport type GetScreenshotResult = {\n format: 'png'\n width: number\n height: number\n scale: number\n bytes: number\n asset: AssetDescriptor\n}\n\n// get_structure\nexport const GetStructureParametersSchema = z.object({\n nodeId: z\n .string()\n .describe('Optional node id to outline; defaults to the current single selection.')\n .optional(),\n options: z\n .object({\n depth: z\n .number()\n .int()\n .positive()\n .describe('Limit traversal depth; defaults to full tree (subject to safety caps).')\n .optional()\n })\n .optional()\n})\n\nexport type GetStructureParametersInput = z.input<typeof GetStructureParametersSchema>\nexport type OutlineNode = {\n id: string\n name: string\n type: string\n x: number\n y: number\n width: number\n height: number\n children?: OutlineNode[]\n}\nexport type GetStructureResult = {\n roots: OutlineNode[]\n}\n\n// get_assets (hub only)\nexport const GetAssetsParametersSchema = z.object({\n hashes: z\n .array(z.string().regex(MCP_HASH_PATTERN))\n .min(1)\n .describe('Asset hashes returned from other tools to download/resolve.')\n})\n\nexport const GetAssetsResultSchema = z.object({\n assets: z.array(AssetDescriptorSchema),\n missing: z.array(z.string().min(1))\n})\n\nexport type GetAssetsParametersInput = z.input<typeof GetAssetsParametersSchema>\nexport type GetAssetsResult = z.infer<typeof GetAssetsResultSchema>\n\nexport type ToolResultMap = {\n get_code: GetCodeResult\n get_token_defs: GetTokenDefsResult\n get_screenshot: GetScreenshotResult\n get_structure: GetStructureResult\n get_assets: GetAssetsResult\n}\n\nexport type ToolName = keyof ToolResultMap\n\nexport { MCP_INSTRUCTIONS } from './instructions'\n\ntype BaseToolMetadata<Name extends ToolName, Schema extends ZodType> = {\n name: Name\n description: string\n parameters: Schema\n exposed?: boolean\n format?: (payload: ToolResultMap[Name]) => CallToolResult\n}\n\ntype ExtensionToolMetadata<Name extends ToolName, Schema extends ZodType> = BaseToolMetadata<\n Name,\n Schema\n> & {\n target: 'extension'\n}\n\ntype HubToolMetadata<Name extends ToolName, Schema extends ZodType> = BaseToolMetadata<\n Name,\n Schema\n> & {\n target: 'hub'\n outputSchema?: ZodType\n}\n\nfunction extTool<Name extends ToolName, Schema extends ZodType>(\n definition: ExtensionToolMetadata<Name, Schema>\n): ExtensionToolMetadata<Name, Schema> {\n return definition\n}\n\nfunction hubTool<Name extends ToolName, Schema extends ZodType>(\n definition: HubToolMetadata<Name, Schema>\n): HubToolMetadata<Name, Schema> {\n return definition\n}\n\nexport const TOOL_DEFS = [\n extTool({\n name: 'get_code',\n description:\n 'Get a high-fidelity code snapshot for a nodeId (or current selection), including assets/usedTokens and `codegen` preset/config.',\n parameters: GetCodeParametersSchema,\n target: 'extension',\n format: createCodeToolResponse\n }),\n extTool({\n name: 'get_token_defs',\n description:\n 'Resolve canonical token names to values (including modes) for tokens referenced by `get_code`.',\n parameters: GetTokenDefsParametersSchema,\n target: 'extension',\n exposed: false\n }),\n extTool({\n name: 'get_screenshot',\n description:\n 'Capture a rendered screenshot for a nodeId (or current selection) for visual verification.',\n parameters: GetScreenshotParametersSchema,\n target: 'extension',\n format: createScreenshotToolResponse\n }),\n extTool({\n name: 'get_structure',\n description:\n 'Get a structural + geometry outline for a nodeId (or current selection) to understand hierarchy and layout intent.',\n parameters: GetStructureParametersSchema,\n target: 'extension'\n }),\n hubTool({\n name: 'get_assets',\n description:\n 'Resolve asset hashes to downloadable URLs/URIs for assets referenced by `get_code`.',\n parameters: GetAssetsParametersSchema,\n target: 'hub',\n outputSchema: GetAssetsResultSchema,\n exposed: false\n })\n] as const\n\nfunction createToolErrorResponse(toolName: string, error: unknown): CallToolResult {\n const message =\n error instanceof Error\n ? error.message || 'Unknown error occurred.'\n : typeof error === 'string'\n ? error\n : 'Unknown error occurred.'\n return {\n content: [\n {\n type: 'text' as const,\n text: `Tool \"${toolName}\" failed: ${message}`\n }\n ]\n }\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport function createCodeToolResponse(payload: ToolResultMap['get_code']): CallToolResult {\n if (!isCodeResult(payload)) {\n throw new Error('Invalid get_code payload received from extension.')\n }\n\n const normalized = normalizeCodeResult(payload)\n const summary: string[] = []\n const codeSize = Buffer.byteLength(normalized.code, 'utf8')\n summary.push(`Generated ${normalized.lang.toUpperCase()} snippet (${formatBytes(codeSize)}).`)\n if (normalized.message) {\n summary.push(normalized.message)\n }\n summary.push(\n normalized.assets.length\n ? `Assets attached: ${normalized.assets.length}. Fetch bytes via resources/read using resourceUri.`\n : 'No binary assets were attached to this response.'\n )\n if (normalized.usedTokens?.length) {\n summary.push(`Token references included: ${normalized.usedTokens.length}.`)\n }\n summary.push('Read structuredContent for the full code string and asset metadata.')\n\n const assetLinks =\n normalized.assets.length > 0\n ? normalized.assets.map((asset) => createAssetResourceLinkBlock(asset))\n : []\n\n return {\n content: [\n {\n type: 'text' as const,\n text: summary.join('\\n')\n },\n ...assetLinks\n ],\n structuredContent: normalized\n }\n}\n\nexport function createScreenshotToolResponse(\n payload: ToolResultMap['get_screenshot']\n): CallToolResult {\n if (!isScreenshotResult(payload)) {\n throw new Error('Invalid get_screenshot payload received from extension.')\n }\n\n const descriptionBlock = {\n type: 'text' as const,\n text: describeScreenshot(payload)\n }\n\n return {\n content: [\n descriptionBlock,\n {\n type: 'text' as const,\n text: `![Screenshot](${payload.asset.url})`\n },\n createResourceLinkBlock(payload.asset, payload)\n ],\n structuredContent: payload\n }\n}\n\nfunction createResourceLinkBlock(asset: AssetDescriptor, result: GetScreenshotResult) {\n return {\n type: 'resource_link' as const,\n name: 'Screenshot',\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `Screenshot ${result.width}x${result.height} @${result.scale}x - Download: ${asset.url}`\n }\n}\n\nfunction describeScreenshot(result: GetScreenshotResult): string {\n return `Screenshot ${result.width}x${result.height} @${result.scale}x (${formatBytes(result.bytes)})`\n}\n\nfunction isScreenshotResult(payload: unknown): payload is GetScreenshotResult {\n if (typeof payload !== 'object' || !payload) return false\n const candidate = payload as Partial<GetScreenshotResult & Record<string, unknown>>\n return (\n typeof candidate.asset === 'object' &&\n candidate.asset !== null &&\n typeof candidate.width === 'number' &&\n typeof candidate.height === 'number' &&\n typeof candidate.scale === 'number' &&\n typeof candidate.bytes === 'number' &&\n typeof candidate.format === 'string'\n )\n}\n\nfunction isCodeResult(payload: unknown): payload is ToolResultMap['get_code'] {\n if (typeof payload !== 'object' || !payload) return false\n const candidate = payload as Partial<ToolResultMap['get_code'] & Record<string, unknown>>\n return (\n typeof candidate.code === 'string' &&\n typeof candidate.lang === 'string' &&\n Array.isArray(candidate.assets)\n )\n}\n\nfunction normalizeCodeResult(result: ToolResultMap['get_code']): ToolResultMap['get_code'] {\n const rewrittenCode = rewriteCodeAssetUrls(result.code, result.assets)\n return {\n ...result,\n code: rewrittenCode\n }\n}\n\nfunction rewriteCodeAssetUrls(code: string, assets: AssetDescriptor[]): string {\n let updatedCode = code\n for (const asset of assets) {\n const uriPattern = new RegExp(escapeRegExp(asset.resourceUri), 'g')\n updatedCode = updatedCode.replace(uriPattern, asset.url)\n }\n return updatedCode\n}\n\nfunction createAssetResourceLinkBlock(asset: AssetDescriptor) {\n return {\n type: 'resource_link' as const,\n name: formatAssetResourceName(asset.hash),\n uri: asset.resourceUri,\n mimeType: asset.mimeType,\n description: `${describeAsset(asset)} - Download: ${asset.url}`\n }\n}\n\nfunction describeAsset(asset: AssetDescriptor): string {\n return `${asset.mimeType} (${formatBytes(asset.size)})`\n}\n\nfunction formatAssetResourceName(hash: string): string {\n return `asset:${hash.slice(0, 8)}`\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function coercePayloadToToolResponse(payload: unknown): CallToolResult {\n if (\n payload &&\n typeof payload === 'object' &&\n Array.isArray((payload as CallToolResult).content)\n ) {\n return payload as CallToolResult\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2)\n }\n ]\n }\n}\n\nexport { createToolErrorResponse }\n", "export const MCP_INSTRUCTIONS = `\n## MCP Server Instructions (Design to Code)\n\nYou are connected to a Figma design file via the MCP server. Help convert design elements into code, preserving design intent and fitting the user\u2019s codebase conventions.\n\n### P0 (must)\n\n- Do not output \\`data-hint*\\` attributes. They are guidance only.\n- For SVG/vector assets: use the exact provided asset (preserve \\`path\\` data and \\`viewBox\\`). Never redraw or approximate vectors.\n\n### P1 (policy)\n\n- Prefer calling \\`get_structure\\` early to understand hierarchy and layout intent.\n- Treat \\`get_code\\` as the implementation baseline; refine it to match the current project\u2019s conventions.\n- Use \\`get_screenshot\\` only when structure and hints cannot resolve major ambiguities, or to sanity-check the final result.\n\n### Layout uncertainty (\\`data-hint-auto-layout\\`)\n\n- If \\`data-hint-auto-layout\\` is \\`none\\` or \\`inferred\\`, treat layout as uncertain.\n- Use \\`get_structure\\` geometry (positions, sizes, gaps, alignment, bounds) to choose layout. Prefer flex/grid when patterns support it; use absolute only when necessary.\n\n### Component intent (\\`data-hint-component\\`)\n\n- If \\`data-hint-component\\` suggests a reusable component/variant and repetition supports it, factor it into a component API (props/variants). Do not preserve the hint string in output.\n\n### Assets and tokens\n\n- If \\`get_code\\` references assets or tokens, handle them according to the current project\u2019s conventions (local asset paths, existing token/variable systems, theming rules).\n`.trim()\n"],
5
+ "mappings": "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",
6
+ "names": ["nanoid", "existsSync", "rmSync", "readFileSync", "statSync", "createServer", "join", "port", "resolve", "reject", "join", "existsSync", "statSync", "join", "join", "existsSync", "list", "statSync", "nanoid", "nanoid", "resolve", "reject", "z", "z", "existsSync", "formatAssetResourceName", "formatBytes", "statSync", "readFileSync", "createAssetResourceLinkBlock", "describeAsset", "rmSync", "createServer", "resolve", "reject", "nanoid"]
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tempad-dev/mcp",
3
3
  "description": "MCP server for TemPad Dev.",
4
- "version": "0.2.1",
4
+ "version": "0.3.0",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
7
7
  "bin": "dist/cli.js",