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/README.md +65 -11
- package/dist/cli.js +495 -79
- package/dist/start-relay-server.js +72 -50
- package/docs/skills/framer-canvas-editing-project.md +69 -0
- package/docs/{property-controls.md → skills/framer-code-components.md} +991 -0
- package/docs/{server-api.md → skills/framer.md} +103 -123
- package/package.json +2 -5
- package/docs/all-skills.md +0 -6
- package/docs/code-components.md +0 -115
- package/docs/component-examples.md +0 -869
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
|
|
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.
|
|
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
|
|
15
|
+
return path3.join(process.env.XDG_CONFIG_HOME, "framer");
|
|
16
16
|
}
|
|
17
17
|
if (process.platform === "win32") {
|
|
18
|
-
return
|
|
18
|
+
return path3.join(process.env.APPDATA || os.homedir(), "framer");
|
|
19
19
|
}
|
|
20
|
-
return
|
|
20
|
+
return path3.join(os.homedir(), ".config", "framer");
|
|
21
21
|
}
|
|
22
22
|
__name(getConfigDir, "getConfigDir");
|
|
23
23
|
function getCredentialsPath() {
|
|
24
|
-
return
|
|
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 (
|
|
31
|
-
return JSON.parse(
|
|
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 (!
|
|
42
|
-
|
|
41
|
+
if (!fs2.existsSync(configDir)) {
|
|
42
|
+
fs2.mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
43
43
|
}
|
|
44
|
-
|
|
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 =
|
|
14284
|
-
var VERSION = "0.0.
|
|
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
|
|
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 ?
|
|
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(
|
|
14368
|
-
var
|
|
14369
|
-
var
|
|
14370
|
-
|
|
14371
|
-
|
|
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(
|
|
14374
|
-
|
|
14375
|
-
|
|
14376
|
-
"
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
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(
|
|
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
|
-
|
|
14417
|
-
const
|
|
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
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
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
|
|
14944
|
+
await ensureRelayForCli();
|
|
14523
14945
|
});
|
|
14524
|
-
program.command("
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
}
|
|
14531
|
-
|
|
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"
|