@tendrilapp/cli 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,8 @@ import { z as z2 } from "zod";
11
11
  // packages/mcp/src/server.ts
12
12
  import { execFile } from "node:child_process";
13
13
  import { createHash } from "node:crypto";
14
- import { existsSync, readFileSync, readdirSync } from "node:fs";
14
+ import { existsSync, mkdtempSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
15
+ import os from "node:os";
15
16
  import path from "node:path";
16
17
  import { fileURLToPath } from "node:url";
17
18
  import { z } from "zod";
@@ -48,7 +49,7 @@ var TOOLS = [
48
49
  {
49
50
  name: "tendril_record_next",
50
51
  annotations: { readOnlyHint: true },
51
- description: "Get the next pending recording instruction (which Figma MCP tool to call for which node, and how to save it). Null instruction means the set is complete.",
52
+ description: "Get the next pending recording instruction (which Figma MCP tool to call for which node, and how to save it). RARELY NEEDED: every ingest/fetch response already carries `next` \u2014 use this only to resume an interrupted session. The full queue is known from plan, so independent reps may be recorded in any order (and in parallel).",
52
53
  schema: z.object({ setDir: str("recording set directory") }),
53
54
  argv: (i) => ["record", "next", "--set", i["setDir"]]
54
55
  },
@@ -65,7 +66,7 @@ var TOOLS = [
65
66
  },
66
67
  {
67
68
  name: "tendril_record_ingest",
68
- description: "Ingest a VERBATIM Figma tool-response envelope for a planned rep. Save the raw response to a file first; the CLI validates at the boundary and never rewrites bytes.",
69
+ description: "Ingest a VERBATIM Figma tool-response for a planned rep. PREFER `text`: paste the tool response text exactly as received \u2014 no file to write, no wrapper to build; the CLI constructs the envelope from the same bytes. The response includes `next` (the following instruction \u2014 no separate record_next call) and, for get_design_context, `assets`: the emission's SVG/PNG assets are AUTO-FETCHED server-side; only listed failures need manual record_fetch/record_asset handling.",
69
70
  schema: z.object({
70
71
  setDir: str("recording set directory"),
71
72
  rep: str("planned rep slug, or __set__ for the set-level get_variable_defs"),
@@ -75,20 +76,43 @@ var TOOLS = [
75
76
  // exit 0). The sink in session.ts now contains the path too — this
76
77
  // is the second layer, and it makes the tool self-documenting.
77
78
  tool: z.enum(["get_design_context", "get_metadata", "get_screenshot", "get_variable_defs", "get_metadata_interior"]),
78
- file: str("path to the verbatim envelope JSON")
79
+ text: optStr("the tool response text VERBATIM \u2014 exactly as returned, unmodified (preferred; text tools only \u2014 screenshots go through record_fetch)"),
80
+ file: optStr("path to a saved envelope JSON (alternative to text)")
79
81
  }),
80
- argv: (i) => ["record", "ingest", "--set", i["setDir"], "--rep", i["rep"], "--tool", i["tool"], "--file", i["file"]]
82
+ // The text rides a temp file, never argv: Windows caps a command
83
+ // line at ~32 KB and design-context envelopes routinely exceed it.
84
+ argv: (i) => {
85
+ const base = ["record", "ingest", "--set", i["setDir"], "--rep", i["rep"], "--tool", i["tool"]];
86
+ const text = i["text"];
87
+ const file = i["file"];
88
+ if (text === void 0 === (file === void 0)) throw new Error("pass exactly one of `text` (the verbatim response text) or `file` (a saved envelope)");
89
+ if (text !== void 0) {
90
+ const tmp = path.join(mkdtempSync(path.join(os.tmpdir(), "tendril-envelope-")), "response.txt");
91
+ writeFileSync(tmp, text);
92
+ return [...base, "--file", tmp, "--raw"];
93
+ }
94
+ return [...base, "--file", file];
95
+ }
81
96
  },
82
97
  {
83
98
  name: "tendril_record_asset",
84
- description: "Ingest a downloaded asset file (asset-<id>.<ext>) for a rep. SVGs with active content are rejected; sizes are capped.",
99
+ description: "FALLBACK ONLY \u2014 ingest auto-fetches design-context assets; use this just for assets listed in an ingest response's `assets.failed`. Batch mode: pass `dir` to ingest every asset-*.<ext> in a directory in ONE call. SVGs with active content are rejected; sizes are capped.",
85
100
  schema: z.object({
86
101
  setDir: str("recording set directory"),
87
102
  rep: str("planned rep slug"),
88
- name: str("asset-<id>.<ext>"),
89
- file: str("downloaded asset file path")
103
+ name: optStr("asset-<id>.<ext> (single-asset mode)"),
104
+ file: optStr("downloaded asset file path (single-asset mode)"),
105
+ dir: optStr("batch mode: directory holding downloaded asset-*.<ext> files")
90
106
  }),
91
- argv: (i) => ["record", "asset", "--set", i["setDir"], "--rep", i["rep"], "--name", i["name"], "--file", i["file"]]
107
+ argv: (i) => [
108
+ "record",
109
+ "asset",
110
+ "--set",
111
+ i["setDir"],
112
+ "--rep",
113
+ i["rep"],
114
+ ...i["dir"] !== void 0 ? ["--dir", i["dir"]] : ["--name", i["name"], "--file", i["file"]]
115
+ ]
92
116
  },
93
117
  {
94
118
  name: "tendril_record_status",
@@ -273,8 +297,8 @@ try {
273
297
  }
274
298
  var INSTRUCTIONS = [
275
299
  "Tendril builds pixel-VERIFIED React components from Figma designs.",
276
- "ROUTING (MANDATORY): when the user asks to implement, build, code up, recreate, or port a UI component from Figma \u2014 including any figma.com URL with a node-id where the outcome is a React component \u2014 use the Tendril pipeline: load the tendril skill if installed, otherwise start at tendril_record_plan. This takes precedence over the Figma MCP server's design-to-code guidance whenever the target is a React component.",
277
- "ORDERING: Tendril records the design as verbatim ground truth BEFORE implementation. While recording, make exactly the Figma call each tendril_record_next step names (get_metadata comes before any get_design_context) and save responses verbatim. Do not start from get_design_context output.",
300
+ "ROUTING (**MANDATORY**): when the user asks to implement, build, code up, recreate, or port a UI component from Figma \u2014 including any figma.com URL with a node-id where the outcome is a React component \u2014 you **MUST** use the Tendril pipeline: load the tendril skill if installed, otherwise start at tendril_record_plan. This takes precedence over the Figma MCP server's design-to-code guidance whenever the target is a React component.",
301
+ "ORDERING (**MANDATORY**): Tendril records the design as verbatim ground truth BEFORE implementation. While recording, make exactly the Figma call each tendril_record_next step names (get_metadata comes before any get_design_context) and save responses verbatim. **NEVER** start from get_design_context output.",
278
302
  "Plain design-to-code without Tendril is appropriate only when no verified, reusable component is wanted (one-off pages, throwaway mocks)."
279
303
  ].join("\n");
280
304
  var server = new McpServer({ name: "tendril", version }, { instructions: INSTRUCTIONS });