framer-dalton 0.0.4 → 0.0.6

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/dist/cli.js CHANGED
@@ -1,34 +1,34 @@
1
1
  #!/usr/bin/env node
2
+ import path3 from 'path';
2
3
  import { Command } from 'commander';
3
- import fs, { readFileSync } from 'fs';
4
+ import fs2 from 'fs';
4
5
  import os from 'os';
5
- import path, { dirname, join } from 'path';
6
6
  import { spawn } from 'child_process';
7
7
  import { fileURLToPath } from 'url';
8
8
  import { createTRPCClient, httpLink } from '@trpc/client';
9
9
 
10
- /* @framer/ai CLI v0.0.4 */
10
+ /* @framer/ai CLI v0.0.6 */
11
11
  var __defProp = Object.defineProperty;
12
12
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
13
13
  function getConfigDir() {
14
14
  if (process.env.XDG_CONFIG_HOME) {
15
- return path.join(process.env.XDG_CONFIG_HOME, "framer");
15
+ return path3.join(process.env.XDG_CONFIG_HOME, "framer");
16
16
  }
17
17
  if (process.platform === "win32") {
18
- return path.join(process.env.APPDATA || os.homedir(), "framer");
18
+ return path3.join(process.env.APPDATA || os.homedir(), "framer");
19
19
  }
20
- return path.join(os.homedir(), ".config", "framer");
20
+ return path3.join(os.homedir(), ".config", "framer");
21
21
  }
22
22
  __name(getConfigDir, "getConfigDir");
23
23
  function getCredentialsPath() {
24
- return path.join(getConfigDir(), "credentials.json");
24
+ return path3.join(getConfigDir(), "credentials.json");
25
25
  }
26
26
  __name(getCredentialsPath, "getCredentialsPath");
27
27
  function readCredentials() {
28
28
  const credPath = getCredentialsPath();
29
29
  try {
30
- if (fs.existsSync(credPath)) {
31
- return JSON.parse(fs.readFileSync(credPath, "utf-8"));
30
+ if (fs2.existsSync(credPath)) {
31
+ return JSON.parse(fs2.readFileSync(credPath, "utf-8"));
32
32
  }
33
33
  } catch {
34
34
  }
@@ -38,10 +38,10 @@ __name(readCredentials, "readCredentials");
38
38
  function writeCredentials(creds) {
39
39
  const credPath = getCredentialsPath();
40
40
  const configDir = getConfigDir();
41
- if (!fs.existsSync(configDir)) {
42
- fs.mkdirSync(configDir, { recursive: true, mode: 448 });
41
+ if (!fs2.existsSync(configDir)) {
42
+ fs2.mkdirSync(configDir, { recursive: true, mode: 448 });
43
43
  }
44
- fs.writeFileSync(credPath, JSON.stringify(creds, null, " "), {
44
+ fs2.writeFileSync(credPath, JSON.stringify(creds, null, " "), {
45
45
  mode: 384
46
46
  });
47
47
  }
@@ -1412,7 +1412,7 @@ var types = {
1412
1412
  name: "Control",
1413
1413
  description: "",
1414
1414
  kind: "alias",
1415
- alias: "EnumControl | BooleanControl | BorderControl | ShadowControl | DateControl | NumberControl | TransitionControl | StringControl | ColorControl | FormattedTextControl | LinkControl | LinkRelControl | FontControl | PageScopeControl | ScrollSectionControl | CustomCursorControl | CursorControl | FileControl | GapControl | PaddingControl | BorderRadiusControl | CollectionReferenceControl | MultiCollectionReferenceControl | VectorSetItemControl | TrackingIdControl | ImageControl | FusedNumberControl | ObjectControl | ArrayControl | EventHandlerControl | SlotControl",
1415
+ alias: "EnumControl | BooleanControl | BorderControl | ShadowControl | DateControl | NumberControl | TransitionControl | StringControl | ColorControl | FormattedTextControl | LinkControl | LinkRelControl | FontControl | PageScopeControl | ScrollSectionControl | CustomCursorControl | CursorControl | FileControl | GapControl | PaddingControl | BorderRadiusControl | CollectionReferenceControl | MultiCollectionReferenceControl | VectorSetItemControl | TrackingIdControl | ImageControl | FusedNumberControl | ObjectControl | ArrayControl | EventHandlerControl | SlotControl | LocationControl",
1416
1416
  references: [
1417
1417
  "EnumControl",
1418
1418
  "BooleanControl",
@@ -1444,7 +1444,8 @@ var types = {
1444
1444
  "ObjectControl",
1445
1445
  "ArrayControl",
1446
1446
  "EventHandlerControl",
1447
- "SlotControl"
1447
+ "SlotControl",
1448
+ "LocationControl"
1448
1449
  ]
1449
1450
  },
1450
1451
  controlattributes: {
@@ -1461,6 +1462,26 @@ var types = {
1461
1462
  references: ["WithKey"],
1462
1463
  extends: ["WithKey", "Partial", "Partial"]
1463
1464
  },
1465
+ coordinate: {
1466
+ name: "Coordinate",
1467
+ description: "",
1468
+ kind: "interface",
1469
+ references: [],
1470
+ members: [
1471
+ {
1472
+ name: "latitude",
1473
+ type: "number",
1474
+ description: "",
1475
+ optional: false
1476
+ },
1477
+ {
1478
+ name: "longitude",
1479
+ type: "number",
1480
+ description: "",
1481
+ optional: false
1482
+ }
1483
+ ]
1484
+ },
1464
1485
  createarrayfield: {
1465
1486
  name: "CreateArrayField",
1466
1487
  description: "",
@@ -1803,6 +1824,50 @@ var types = {
1803
1824
  references: ["WithLinkVariableType", "CreateVariableBase"],
1804
1825
  extends: ["WithLinkVariableType", "CreateVariableBase"]
1805
1826
  },
1827
+ createlocaleinput: {
1828
+ name: "CreateLocaleInput",
1829
+ description: "Input for creating a new locale.\n@alpha",
1830
+ kind: "interface",
1831
+ references: ["LocaleId"],
1832
+ members: [
1833
+ {
1834
+ name: "language",
1835
+ type: "string",
1836
+ description: 'The language code (e.g., "en", "fr", "zh-Hans"). Use `getLocaleLanguages()` to get the list of valid codes.',
1837
+ optional: false
1838
+ },
1839
+ {
1840
+ name: "region",
1841
+ type: "string",
1842
+ description: 'The optional region code (e.g., "US", "CA"). Use `getLocaleRegions(language)` to get the list of valid codes.',
1843
+ optional: true
1844
+ },
1845
+ {
1846
+ name: "fallbackLocaleId",
1847
+ type: "LocaleId",
1848
+ description: "ID of the fallback locale. Must reference an existing locale.",
1849
+ optional: true
1850
+ },
1851
+ {
1852
+ name: "slug",
1853
+ type: "string",
1854
+ description: 'URL slug for the locale (e.g., "en"). If not provided, one is derived from the code.',
1855
+ optional: true
1856
+ },
1857
+ {
1858
+ name: "name",
1859
+ type: "string",
1860
+ description: 'Display Name for the locale (e.g., "English (US)"). If not provided, one is derived from the code.',
1861
+ optional: true
1862
+ },
1863
+ {
1864
+ name: "draft",
1865
+ type: "boolean",
1866
+ description: "Flag to mark the locale as a draft. Defaults to `false`.",
1867
+ optional: true
1868
+ }
1869
+ ]
1870
+ },
1806
1871
  createmulticollectionreferencefield: {
1807
1872
  name: "CreateMultiCollectionReferenceField",
1808
1873
  description: "",
@@ -4319,6 +4384,53 @@ var types = {
4319
4384
  alias: '{\n action: "set";\n value: string;\n needsReview?: boolean;\n} | {\n action: "clear";\n} | {\n action: "ignore";\n needsReview?: boolean;\n}',
4320
4385
  references: []
4321
4386
  },
4387
+ location: {
4388
+ name: "Location",
4389
+ description: "",
4390
+ kind: "interface",
4391
+ references: ["Coordinate"],
4392
+ members: [
4393
+ {
4394
+ name: "coordinate",
4395
+ type: "Coordinate",
4396
+ description: "",
4397
+ optional: false
4398
+ },
4399
+ {
4400
+ name: "title",
4401
+ type: "string",
4402
+ description: 'Place name, e.g. "Eiffel Tower" or "Framer".',
4403
+ optional: true
4404
+ },
4405
+ {
4406
+ name: "address",
4407
+ type: "string",
4408
+ description: 'Formatted address string, e.g. "Rozengracht 207, 1016 LZ Amsterdam, Netherlands".',
4409
+ optional: true
4410
+ }
4411
+ ]
4412
+ },
4413
+ locationcontrol: {
4414
+ name: "LocationControl",
4415
+ description: "",
4416
+ kind: "interface",
4417
+ references: ["ControlBase", "Location"],
4418
+ members: [
4419
+ {
4420
+ name: "type",
4421
+ type: '"location"',
4422
+ description: "",
4423
+ optional: false
4424
+ },
4425
+ {
4426
+ name: "value",
4427
+ type: "Location | undefined",
4428
+ description: "",
4429
+ optional: true
4430
+ }
4431
+ ],
4432
+ extends: ["ControlBase"]
4433
+ },
4322
4434
  managedarrayfieldinput: {
4323
4435
  name: "ManagedArrayFieldInput",
4324
4436
  description: "",
@@ -5254,6 +5366,24 @@ var types = {
5254
5366
  description: "",
5255
5367
  optional: false
5256
5368
  },
5369
+ {
5370
+ name: "createLocale",
5371
+ type: "(input: CreateLocaleInput) => Promise<Locale>",
5372
+ description: "@alpha",
5373
+ optional: false
5374
+ },
5375
+ {
5376
+ name: "getLocaleLanguages",
5377
+ type: "() => Promise<{\n code: string;\n name: string;\n }[]>",
5378
+ description: "@alpha",
5379
+ optional: false
5380
+ },
5381
+ {
5382
+ name: "getLocaleRegions",
5383
+ type: "(language: string) => Promise<{\n code: string;\n name: string;\n isCommon: boolean;\n }[]>",
5384
+ description: "@alpha",
5385
+ optional: false
5386
+ },
5257
5387
  {
5258
5388
  name: "unstable_ensureMinimumDependencyVersion",
5259
5389
  type: 'FramerPluginAPI["unstable_ensureMinimumDependencyVersion"]',
@@ -6058,6 +6188,30 @@ var types = {
6058
6188
  description: "@alpha",
6059
6189
  optional: false
6060
6190
  },
6191
+ {
6192
+ name: "getAgentSystemPrompt",
6193
+ type: "() => Promise<string>",
6194
+ description: "@alpha",
6195
+ optional: false
6196
+ },
6197
+ {
6198
+ name: "getAgentContext",
6199
+ type: "(options?: {\n pagePath?: string;\n }) => Promise<string>",
6200
+ description: "@alpha",
6201
+ optional: false
6202
+ },
6203
+ {
6204
+ name: "readProjectForAgent",
6205
+ type: "(queries: Record<string, unknown>[], options?: {\n pagePath?: string;\n }) => Promise<{\n results: unknown[];\n }>",
6206
+ description: "@alpha",
6207
+ optional: false
6208
+ },
6209
+ {
6210
+ name: "applyAgentChanges",
6211
+ type: "(dsl: string, options?: {\n pagePath?: string;\n }) => Promise<void>",
6212
+ description: "@alpha",
6213
+ optional: false
6214
+ },
6061
6215
  {
6062
6216
  name: "[getAiServiceInfoMessageType]",
6063
6217
  type: "() => Promise<AiServiceInfo>",
@@ -11648,6 +11802,34 @@ var methodsByCategory = {
11648
11802
  }
11649
11803
  ],
11650
11804
  framer: [
11805
+ {
11806
+ name: "[$framerApiOnly.applyAgentChanges]",
11807
+ category: "framer",
11808
+ signature: "[$framerApiOnly.applyAgentChanges](dsl: string, options?: { pagePath?: string; }): Promise<void>",
11809
+ description: 'Applies commands to the canvas to create, update, remove, move, or duplicate nodes.\n\nThe command syntax is documented in the string returned by {@link getAgentSystemPrompt}.\nEach call is scoped to a single page.\n\n@param dsl - A string of commands separated by `;`. See {@link getAgentSystemPrompt} for syntax.\n@param options.pagePath - Target page path (e.g. `"/about"`). Defaults to the active page.',
11810
+ references: []
11811
+ },
11812
+ {
11813
+ name: "[$framerApiOnly.getAgentContext]",
11814
+ category: "framer",
11815
+ signature: "[$framerApiOnly.getAgentContext](options?: { pagePath?: string; }): Promise<string>",
11816
+ description: 'Returns the dynamic project context as a string.\n\nThe context includes project-specific data:\n- **Available fonts** \u2014 font families loaded in the project.\n- **Components** \u2014 component names and their controls.\n- **Design tokens** \u2014 color tokens defined in the project.\n- **Style presets** \u2014 text style presets defined in the project.\n- **Icon sets** \u2014 available icon sets and their definitions.\n\nThis data changes per project and page. Pair with the static prompt\nfrom {@link getAgentSystemPrompt} for complete agent context.\n\n@param options.pagePath - Target page path (e.g. `"/about"`). Defaults to the active page.\n@returns A string containing the project context.',
11817
+ references: []
11818
+ },
11819
+ {
11820
+ name: "[$framerApiOnly.getAgentSystemPrompt]",
11821
+ category: "framer",
11822
+ signature: "[$framerApiOnly.getAgentSystemPrompt](): Promise<string>",
11823
+ description: "Returns the static agent system prompt as a string.\n\nThe prompt includes:\n- **Command reference** \u2014 syntax for adding, updating, removing, moving, and duplicating nodes.\n- **Design rules** \u2014 spacing, layout, typography, and responsive design guidance.\n- **Examples** \u2014 common UI patterns expressed as commands.\n- **`readProjectForAgent` query reference** \u2014 available query types and their parameters.\n\nThis is the sole documentation for the command syntax used by {@link applyAgentChanges}\nand the query types used by {@link readProjectForAgent}.\n\nThe prompt is static and does not depend on any specific project.\nCall {@link getAgentContext} to get the project-specific context.\n\n@returns A string containing the agent system prompt.",
11824
+ references: []
11825
+ },
11826
+ {
11827
+ name: "[$framerApiOnly.readProjectForAgent]",
11828
+ category: "framer",
11829
+ signature: "[$framerApiOnly.readProjectForAgent](queries: Record<string, unknown>[], options?: { pagePath?: string; }): Promise<{ results: unknown[]; }>",
11830
+ description: 'Reads project state by executing an array of queries against the project.\n\nReturns one result per query. Available query types and their parameters\nare documented in the string returned by {@link getAgentSystemPrompt}.\n\n@param queries - Array of query objects. See {@link getAgentSystemPrompt} for available types.\n@param options.pagePath - Target page path (e.g. `"/about"`). Defaults to the active page.\n@returns An object with a `results` array, one entry per query.',
11831
+ references: []
11832
+ },
11651
11833
  {
11652
11834
  name: "[$framerInternal.initialState]",
11653
11835
  category: "framer",
@@ -11728,6 +11910,13 @@ var methodsByCategory = {
11728
11910
  description: "Add a new text node to the canvas.",
11729
11911
  references: ["AddTextOptions"]
11730
11912
  },
11913
+ {
11914
+ name: "applyAgentChanges",
11915
+ category: "framer",
11916
+ signature: "applyAgentChanges(dsl: string, options?: { pagePath?: string; }): Promise<void>",
11917
+ description: 'Applies commands to the canvas to create, update, remove, move, or duplicate nodes.\n\nThe command syntax is documented in the string returned by {@link getAgentSystemPrompt}.\nEach call is scoped to a single page.\n\n@param dsl - A string of commands separated by `;`. See {@link getAgentSystemPrompt} for syntax.\n@param options.pagePath - Target page path (e.g. `"/about"`). Defaults to the active page.',
11918
+ references: []
11919
+ },
11731
11920
  {
11732
11921
  name: "cloneNode",
11733
11922
  category: "framer",
@@ -11777,6 +11966,13 @@ var methodsByCategory = {
11777
11966
  description: "Create a new node on the canvas.",
11778
11967
  references: ["EditableFrameNodeAttributes", "FrameNode"]
11779
11968
  },
11969
+ {
11970
+ name: "createLocale",
11971
+ category: "framer",
11972
+ signature: "createLocale(input: CreateLocaleInput): Promise<Locale>",
11973
+ description: "Create a new locale in the project.\n\n@alpha\n@param input - The locale configuration, use `getLocaleLanguages` and `getLocaleRegions` to get valid language and region codes.\n@returns The created locale.",
11974
+ references: ["CreateLocaleInput", "Locale"]
11975
+ },
11780
11976
  {
11781
11977
  name: "createManagedCollection",
11782
11978
  category: "framer",
@@ -11826,6 +12022,20 @@ var methodsByCategory = {
11826
12022
  description: "",
11827
12023
  references: []
11828
12024
  },
12025
+ {
12026
+ name: "getAgentContext",
12027
+ category: "framer",
12028
+ signature: "getAgentContext(options?: { pagePath?: string; }): Promise<string>",
12029
+ description: 'Returns the dynamic project context as a string.\n\nThe context includes project-specific data:\n- **Available fonts** \u2014 font families loaded in the project.\n- **Components** \u2014 component names and their controls.\n- **Design tokens** \u2014 color tokens defined in the project.\n- **Style presets** \u2014 text style presets defined in the project.\n- **Icon sets** \u2014 available icon sets and their definitions.\n\nThis data changes per project and page. Pair with the static prompt\nfrom {@link getAgentSystemPrompt} for complete agent context.\n\n@param options.pagePath - Target page path (e.g. `"/about"`). Defaults to the active page.\n@returns A string containing the project context.',
12030
+ references: []
12031
+ },
12032
+ {
12033
+ name: "getAgentSystemPrompt",
12034
+ category: "framer",
12035
+ signature: "getAgentSystemPrompt(): Promise<string>",
12036
+ description: "Returns the static agent system prompt as a string.\n\nThe prompt includes:\n- **Command reference** \u2014 syntax for adding, updating, removing, moving, and duplicating nodes.\n- **Design rules** \u2014 spacing, layout, typography, and responsive design guidance.\n- **Examples** \u2014 common UI patterns expressed as commands.\n- **`readProjectForAgent` query reference** \u2014 available query types and their parameters.\n\nThis is the sole documentation for the command syntax used by {@link applyAgentChanges}\nand the query types used by {@link readProjectForAgent}.\n\nThe prompt is static and does not depend on any specific project.\nCall {@link getAgentContext} to get the project-specific context.\n\n@returns A string containing the agent system prompt.",
12037
+ references: []
12038
+ },
11829
12039
  {
11830
12040
  name: "getCanvasRoot",
11831
12041
  category: "framer",
@@ -11945,6 +12155,20 @@ var methodsByCategory = {
11945
12155
  description: "Get the image of the current selection or `null` if there is no image.\n\nIn `editImage` mode, this returns the image the user already has set,\nwhich your plugin can then modify.",
11946
12156
  references: ["ImageAsset"]
11947
12157
  },
12158
+ {
12159
+ name: "getLocaleLanguages",
12160
+ category: "framer",
12161
+ signature: "getLocaleLanguages(): Promise<{ code: string; name: string; }[]>",
12162
+ description: "Get all available locale languages.\n\n@alpha\n@returns A list of language codes and their display names, sorted by name.",
12163
+ references: []
12164
+ },
12165
+ {
12166
+ name: "getLocaleRegions",
12167
+ category: "framer",
12168
+ signature: "getLocaleRegions(languageCode: string): Promise<{ code: string; name: string; isCommon: boolean; }[]>",
12169
+ description: "Get all available locale regions for a given language.\n\n@alpha\n@param languageCode - The language code to get regions for. Use `getLocaleLanguages` to get valid language codes.\n@returns A list of region codes, their display names, and whether they are commonly paired with the given language.",
12170
+ references: []
12171
+ },
11948
12172
  {
11949
12173
  name: "getLocales",
11950
12174
  category: "framer",
@@ -12071,6 +12295,13 @@ var methodsByCategory = {
12071
12295
  description: "",
12072
12296
  references: ["PublishResult"]
12073
12297
  },
12298
+ {
12299
+ name: "readProjectForAgent",
12300
+ category: "framer",
12301
+ signature: "readProjectForAgent(queries: Record<string, unknown>[], options?: { pagePath?: string; }): Promise<{ results: unknown[]; }>",
12302
+ description: 'Reads project state by executing an array of queries against the project.\n\nReturns one result per query. Available query types and their parameters\nare documented in the string returned by {@link getAgentSystemPrompt}.\n\n@param queries - Array of query objects. See {@link getAgentSystemPrompt} for available types.\n@param options.pagePath - Target page path (e.g. `"/about"`). Defaults to the active page.\n@returns An object with a `results` array, one entry per query.',
12303
+ references: []
12304
+ },
12074
12305
  {
12075
12306
  name: "rejectAllPending",
12076
12307
  category: "framer",
@@ -14229,6 +14460,7 @@ __name(expandReferences, "expandReferences");
14229
14460
  function renderDocs(queries) {
14230
14461
  const lines = [];
14231
14462
  const errors = [];
14463
+ const framerClass = getClass("framer");
14232
14464
  if (queries.length === 0) {
14233
14465
  queries = ["framer"];
14234
14466
  }
@@ -14251,6 +14483,20 @@ function renderDocs(queries) {
14251
14483
  ${typeDef}`);
14252
14484
  }
14253
14485
  } else {
14486
+ if (framerClass) {
14487
+ const method = framerClass.methods.find((m) => m.name === query);
14488
+ if (method) {
14489
+ if (method.description)
14490
+ lines.push(formatDocComment(method.description));
14491
+ lines.push(`${method.category}.${method.signature}`);
14492
+ const seen = /* @__PURE__ */ new Set();
14493
+ for (const typeDef of expandReferences(method.references, seen)) {
14494
+ lines.push(`
14495
+ ${typeDef}`);
14496
+ }
14497
+ continue;
14498
+ }
14499
+ }
14254
14500
  const classData = getClass(query);
14255
14501
  if (classData) {
14256
14502
  lines.push(
@@ -14280,8 +14526,8 @@ ${typeDef}`);
14280
14526
  }
14281
14527
  __name(renderDocs, "renderDocs");
14282
14528
  var __filename$1 = fileURLToPath(import.meta.url);
14283
- var __dirname$1 = path.dirname(__filename$1);
14284
- var VERSION = "0.0.4" ;
14529
+ var __dirname$1 = path3.dirname(__filename$1);
14530
+ var VERSION = "0.0.6" ;
14285
14531
  var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
14286
14532
  var client = createTRPCClient({
14287
14533
  links: [
@@ -14317,7 +14563,7 @@ function compareVersions(v1, v2) {
14317
14563
  return 0;
14318
14564
  }
14319
14565
  __name(compareVersions, "compareVersions");
14320
- async function ensureRelayServer(options = {}) {
14566
+ async function ensureRelayServerRunning(options = {}) {
14321
14567
  const { logger, restartOnVersionMismatch = true } = options;
14322
14568
  const serverVersion = await getRelayServerVersion();
14323
14569
  if (serverVersion === VERSION) {
@@ -14343,7 +14589,7 @@ async function ensureRelayServer(options = {}) {
14343
14589
  logger?.log("Relay server not running, starting it...");
14344
14590
  }
14345
14591
  const isRunningFromSource = __filename$1.endsWith(".ts");
14346
- const scriptPath = isRunningFromSource ? path.resolve(__dirname$1, "./start-relay-server.ts") : path.resolve(__dirname$1, "./start-relay-server.js");
14592
+ const scriptPath = isRunningFromSource ? path3.resolve(__dirname$1, "./start-relay-server.ts") : path3.resolve(__dirname$1, "./start-relay-server.js");
14347
14593
  const serverProcess = spawn(
14348
14594
  isRunningFromSource ? "tsx" : process.execPath,
14349
14595
  [scriptPath],
@@ -14364,22 +14610,107 @@ async function ensureRelayServer(options = {}) {
14364
14610
  }
14365
14611
  throw new Error("Failed to start relay server after 5 seconds");
14366
14612
  }
14367
- __name(ensureRelayServer, "ensureRelayServer");
14368
- var __dirname2 = dirname(fileURLToPath(import.meta.url));
14369
- var docsDir = join(__dirname2, "..", "docs");
14370
- function readDoc(name) {
14371
- return readFileSync(join(docsDir, `${name}.md`), "utf-8").trimEnd();
14613
+ __name(ensureRelayServerRunning, "ensureRelayServerRunning");
14614
+ var META_SKILL_NAME = "framer";
14615
+ var CODE_COMPONENTS_SKILL_NAME = "framer-code-components";
14616
+ var __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
14617
+ var skillsDocsDir = path3.join(__dirname2, "..", "docs", "skills");
14618
+ function readSkillDoc(name) {
14619
+ return fs2.readFileSync(path3.join(skillsDocsDir, name), "utf-8").trimEnd();
14620
+ }
14621
+ __name(readSkillDoc, "readSkillDoc");
14622
+ function buildMetaSkill() {
14623
+ return `${readSkillDoc("framer.md")}
14624
+ `;
14625
+ }
14626
+ __name(buildMetaSkill, "buildMetaSkill");
14627
+ function buildCodeComponentsSkill() {
14628
+ return `${readSkillDoc("framer-code-components.md")}
14629
+ `;
14630
+ }
14631
+ __name(buildCodeComponentsSkill, "buildCodeComponentsSkill");
14632
+ function renderTemplate(template, values) {
14633
+ let rendered = template;
14634
+ for (const [key, value] of Object.entries(values)) {
14635
+ rendered = rendered.split(`{{${key}}}`).join(value);
14636
+ }
14637
+ return rendered;
14638
+ }
14639
+ __name(renderTemplate, "renderTemplate");
14640
+ function toProjectSkillName(projectId) {
14641
+ const safeProjectId = projectId.replace(/[^a-zA-Z0-9_-]/g, "-");
14642
+ return `framer-canvas-editing-project-${safeProjectId}`;
14372
14643
  }
14373
- __name(readDoc, "readDoc");
14374
- var skillTopics = [
14375
- "code-components",
14376
- "property-controls",
14377
- "component-examples"
14378
- ];
14379
- function isSkillTopic(topic) {
14380
- return skillTopics.some((name) => name === topic);
14644
+ __name(toProjectSkillName, "toProjectSkillName");
14645
+ function buildProjectCanvasSkill(projectId, agentContext, canvasPrompt) {
14646
+ const skillName = toProjectSkillName(projectId);
14647
+ const template = readSkillDoc("framer-canvas-editing-project.md");
14648
+ const content = `${renderTemplate(template, {
14649
+ SKILL_NAME: skillName,
14650
+ PROJECT_ID: projectId,
14651
+ GENERATED_AT: (/* @__PURE__ */ new Date()).toISOString(),
14652
+ CANVAS_PROMPT: canvasPrompt.trimEnd(),
14653
+ AGENT_CONTEXT: agentContext.trimEnd()
14654
+ })}
14655
+ `;
14656
+ return { skillName, content };
14381
14657
  }
14382
- __name(isSkillTopic, "isSkillTopic");
14658
+ __name(buildProjectCanvasSkill, "buildProjectCanvasSkill");
14659
+ function writeSkill(root, skillName, content) {
14660
+ fs2.mkdirSync(root, { recursive: true });
14661
+ const rootStat = fs2.statSync(root);
14662
+ if (!rootStat.isDirectory()) {
14663
+ throw new Error(`Skill root is not a directory: ${root}`);
14664
+ }
14665
+ const skillDir = path3.join(root, skillName);
14666
+ const filePath = path3.join(skillDir, "SKILL.md");
14667
+ if (fs2.existsSync(skillDir)) {
14668
+ const current = fs2.lstatSync(skillDir);
14669
+ if (current.isSymbolicLink() || !current.isDirectory()) {
14670
+ fs2.rmSync(skillDir, { recursive: true, force: true });
14671
+ }
14672
+ }
14673
+ fs2.mkdirSync(skillDir, { recursive: true });
14674
+ fs2.writeFileSync(filePath, content, "utf-8");
14675
+ return filePath;
14676
+ }
14677
+ __name(writeSkill, "writeSkill");
14678
+ function getDefaultSkillRoots() {
14679
+ const home = os.homedir();
14680
+ return [
14681
+ path3.join(home, ".agents", "skills"),
14682
+ path3.join(home, ".claude", "skills")
14683
+ ];
14684
+ }
14685
+ __name(getDefaultSkillRoots, "getDefaultSkillRoots");
14686
+ function installSkills(options = { type: "base" }) {
14687
+ const skillRoots = options.skillRoots ?? getDefaultSkillRoots();
14688
+ const skills = [
14689
+ { name: META_SKILL_NAME, content: buildMetaSkill() },
14690
+ {
14691
+ name: CODE_COMPONENTS_SKILL_NAME,
14692
+ content: buildCodeComponentsSkill()
14693
+ }
14694
+ ];
14695
+ if (options.type === "project") {
14696
+ const projectSkill = buildProjectCanvasSkill(
14697
+ options.projectId,
14698
+ options.agentContext,
14699
+ options.canvasPrompt
14700
+ );
14701
+ skills.push({
14702
+ name: projectSkill.skillName,
14703
+ content: projectSkill.content
14704
+ });
14705
+ }
14706
+ return skills.map((skill) => ({
14707
+ skillName: skill.name,
14708
+ paths: skillRoots.map(
14709
+ (root) => writeSkill(root, skill.name, skill.content)
14710
+ )
14711
+ }));
14712
+ }
14713
+ __name(installSkills, "installSkills");
14383
14714
 
14384
14715
  // src/utils.ts
14385
14716
  function formatError(error) {
@@ -14413,8 +14744,118 @@ async function readStdin() {
14413
14744
  return Buffer.concat(chunks).toString("utf-8");
14414
14745
  }
14415
14746
  __name(readStdin, "readStdin");
14416
- program.option("-s, --session <id>", "Session ID (required for code execution)").option("-e, --eval <code>", "Code to execute (or pipe via stdin)").option("--timeout <ms>", "Execution timeout in milliseconds", "30000").action(async (options) => {
14417
- const { session: sessionId, eval: evalCode, timeout } = options;
14747
+ function printSetupSummary(results) {
14748
+ const skillCount = results.length;
14749
+ const installLocations = /* @__PURE__ */ new Set();
14750
+ for (const result of results) {
14751
+ for (const filePath of result.paths) {
14752
+ const skillDir = path3.dirname(filePath);
14753
+ const root = path3.dirname(skillDir);
14754
+ installLocations.add(root);
14755
+ }
14756
+ }
14757
+ print(
14758
+ `Installed ${skillCount} skills to ${Array.from(installLocations).sort().join(", ")}`
14759
+ );
14760
+ }
14761
+ __name(printSetupSummary, "printSetupSummary");
14762
+ async function getAgentSystemPrompt(sessionId) {
14763
+ const result = await client.exec.mutate({
14764
+ sessionId,
14765
+ code: "return await framer.getAgentSystemPrompt();",
14766
+ cwd: process.cwd()
14767
+ });
14768
+ if (result.error) {
14769
+ throw new Error(result.error);
14770
+ }
14771
+ const prompt = result.output.at(-1);
14772
+ if (typeof prompt !== "string") {
14773
+ throw new Error("Did not receive agent prompt output.");
14774
+ }
14775
+ return prompt;
14776
+ }
14777
+ __name(getAgentSystemPrompt, "getAgentSystemPrompt");
14778
+ async function getAgentContext(sessionId) {
14779
+ const result = await client.exec.mutate({
14780
+ sessionId,
14781
+ code: "return await framer.getAgentContext({ pagePath: '/' });",
14782
+ cwd: process.cwd()
14783
+ });
14784
+ if (result.error) {
14785
+ throw new Error(result.error);
14786
+ }
14787
+ const context = result.output.at(-1);
14788
+ if (typeof context !== "string") {
14789
+ throw new Error("Did not receive agent context output.");
14790
+ }
14791
+ return context;
14792
+ }
14793
+ __name(getAgentContext, "getAgentContext");
14794
+ async function refreshSkillsFromSession(sessionId, projectId) {
14795
+ try {
14796
+ const [canvasPrompt, agentContext] = await Promise.all([
14797
+ getAgentSystemPrompt(sessionId),
14798
+ getAgentContext(sessionId)
14799
+ ]);
14800
+ installSkills({
14801
+ type: "project",
14802
+ canvasPrompt,
14803
+ projectId,
14804
+ agentContext
14805
+ });
14806
+ } catch (err) {
14807
+ printError(
14808
+ `Failed to refresh skills for session ${sessionId}: ${formatError(err)}`
14809
+ );
14810
+ process.exit(1);
14811
+ }
14812
+ }
14813
+ __name(refreshSkillsFromSession, "refreshSkillsFromSession");
14814
+ function resolveSessionCredentials(projectUrl, apiKeyArg) {
14815
+ try {
14816
+ const projectId = extractProjectId(projectUrl);
14817
+ if (!apiKeyArg) {
14818
+ const cachedApiKey = getApiKey(projectId);
14819
+ if (cachedApiKey) {
14820
+ return { projectId, apiKey: cachedApiKey };
14821
+ }
14822
+ printError("No API key provided and none cached for this project.");
14823
+ printError("");
14824
+ printError("Usage: framer session new <projectUrl> <apiKey>");
14825
+ process.exit(1);
14826
+ }
14827
+ saveApiKey(projectId, apiKeyArg);
14828
+ return { projectId, apiKey: apiKeyArg };
14829
+ } catch (err) {
14830
+ printError(`Failed to create session: ${formatError(err)}`);
14831
+ process.exit(1);
14832
+ }
14833
+ }
14834
+ __name(resolveSessionCredentials, "resolveSessionCredentials");
14835
+ async function createSession(projectId, apiKey) {
14836
+ try {
14837
+ const result = await client.createSession.mutate({
14838
+ projectId,
14839
+ apiKey
14840
+ });
14841
+ return result.id;
14842
+ } catch (err) {
14843
+ printError(`Failed to create session: ${formatError(err)}`);
14844
+ process.exit(1);
14845
+ }
14846
+ }
14847
+ __name(createSession, "createSession");
14848
+ async function ensureRelayForCli() {
14849
+ try {
14850
+ await ensureRelayServerRunning({ logger: { log: print } });
14851
+ } catch (err) {
14852
+ printError(`Failed to check relay status: ${formatError(err)}`);
14853
+ process.exit(1);
14854
+ }
14855
+ }
14856
+ __name(ensureRelayForCli, "ensureRelayForCli");
14857
+ program.option("-s, --session <id>", "Session ID (required for code execution)").option("-e, --eval <code>", "Code to execute (or pipe via stdin)").action(async (options) => {
14858
+ const { session: sessionId, eval: evalCode } = options;
14418
14859
  let code = evalCode;
14419
14860
  if (!code && !process.stdin.isTTY) {
14420
14861
  code = await readStdin();
@@ -14430,12 +14871,11 @@ program.option("-s, --session <id>", "Session ID (required for code execution)")
14430
14871
  );
14431
14872
  process.exit(1);
14432
14873
  }
14874
+ await ensureRelayForCli();
14433
14875
  try {
14434
- await ensureRelayServer({ logger: { log: print } });
14435
14876
  const result = await client.exec.mutate({
14436
14877
  sessionId: String(sessionId),
14437
14878
  code,
14438
- timeout: parseInt(timeout, 10),
14439
14879
  cwd: process.cwd()
14440
14880
  });
14441
14881
  for (const line of result.output) {
@@ -14452,36 +14892,18 @@ program.option("-s, --session <id>", "Session ID (required for code execution)")
14452
14892
  });
14453
14893
  var session = program.command("session").description("Manage sessions");
14454
14894
  session.command("new <projectUrl> [apiKey]").description("Create a new session and print the session ID").action(async (projectUrlArg, apiKeyArg) => {
14455
- try {
14456
- const projectId = extractProjectId(projectUrlArg);
14457
- let apiKey = apiKeyArg;
14458
- if (!apiKey) {
14459
- const cached = getApiKey(projectId);
14460
- if (cached) {
14461
- apiKey = cached;
14462
- } else {
14463
- printError("No API key provided and none cached for this project.");
14464
- printError("");
14465
- printError("Usage: framer session new <projectUrl> <apiKey>");
14466
- process.exit(1);
14467
- }
14468
- } else {
14469
- saveApiKey(projectId, apiKey);
14470
- }
14471
- await ensureRelayServer({ logger: { log: print } });
14472
- const result = await client.createSession.mutate({
14473
- projectId,
14474
- apiKey
14475
- });
14476
- print(result.id);
14477
- } catch (err) {
14478
- printError(`Failed to create session: ${formatError(err)}`);
14479
- process.exit(1);
14480
- }
14895
+ const { projectId, apiKey } = resolveSessionCredentials(
14896
+ projectUrlArg,
14897
+ apiKeyArg
14898
+ );
14899
+ await ensureRelayForCli();
14900
+ const sessionId = await createSession(projectId, apiKey);
14901
+ await refreshSkillsFromSession(sessionId, projectId);
14902
+ print(sessionId);
14481
14903
  });
14482
14904
  session.command("list").description("List all active sessions").action(async () => {
14905
+ await ensureRelayForCli();
14483
14906
  try {
14484
- await ensureRelayServer({ logger: { log: print } });
14485
14907
  const sessions = await client.listSessions.query();
14486
14908
  if (sessions.length === 0) {
14487
14909
  print("No active sessions");
@@ -14494,8 +14916,8 @@ session.command("list").description("List all active sessions").action(async ()
14494
14916
  }
14495
14917
  });
14496
14918
  session.command("destroy <sessionId>").description("Destroy a session").action(async (sessionId) => {
14919
+ await ensureRelayForCli();
14497
14920
  try {
14498
- await ensureRelayServer({ logger: { log: print } });
14499
14921
  await client.destroySession.mutate({ sessionId });
14500
14922
  print(`Session ${sessionId} destroyed`);
14501
14923
  } catch (err) {
@@ -14519,24 +14941,18 @@ relay.command("restart").description("Restart the relay server").action(async ()
14519
14941
  } catch {
14520
14942
  }
14521
14943
  await new Promise((resolve) => setTimeout(resolve, 500));
14522
- await ensureRelayServer({ logger: { log: print } });
14944
+ await ensureRelayForCli();
14523
14945
  });
14524
- program.command("skill [topic]").description("Output skill documentation").action((topic) => {
14525
- if (!topic) {
14526
- print(readDoc("server-api"));
14527
- print("");
14528
- print(readDoc("all-skills"));
14529
- return;
14530
- }
14531
- if (!isSkillTopic(topic)) {
14532
- const available = ["(no argument)", ...skillTopics];
14533
- printError(`Unknown skill topic: ${topic}`);
14534
- printError(`Available topics: ${available.join(", ")}`);
14946
+ program.command("setup").description(
14947
+ "Install Framer skills into ~/.agents/skills and ~/.claude/skills"
14948
+ ).action(() => {
14949
+ try {
14950
+ const results = installSkills();
14951
+ printSetupSummary(results);
14952
+ } catch (err) {
14953
+ printError(`Setup failed: ${formatError(err)}`);
14535
14954
  process.exit(1);
14536
14955
  }
14537
- print(readDoc(topic));
14538
- print("");
14539
- print(readDoc("all-skills"));
14540
14956
  });
14541
14957
  program.command("docs [queries...]").description(
14542
14958
  "Look up API documentation. Use: docs, docs ClassName, docs Class.method, or docs TypeName"