framer-dalton 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/cli.js +237 -7
- package/dist/start-relay-server.js +72 -49
- package/docs/server-api.md +70 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,12 +14,22 @@ Then, simply open your preferred agent, ask to interact with your Framer project
|
|
|
14
14
|
|
|
15
15
|
See [skills/framer/SKILL.md](skills/framer/SKILL.md) for full CLI usage and API documentation.
|
|
16
16
|
|
|
17
|
-
## Development
|
|
17
|
+
## Local Development
|
|
18
|
+
|
|
19
|
+
Build and symlink to PATH + install skill locally:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
make install-dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you want to hit a local FramerHeadlessAPI instance, when interacting with your agent, tell it something like this:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Use the framer skill, but use `FRAMER_HEADLESS_SERVER_URL=ws://localhost:8080/channel/headless-plugin framer` (never with @latest) for all commands instead of `npx framer-dalton`
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Remove local install:
|
|
18
32
|
|
|
19
33
|
```bash
|
|
20
|
-
make
|
|
21
|
-
make build # Build (installs deps automatically)
|
|
22
|
-
make check # Type check + lint
|
|
23
|
-
make format # Auto-format
|
|
24
|
-
make clean # Clean build artifacts
|
|
34
|
+
make uninstall-dev
|
|
25
35
|
```
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ 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.5 */
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
12
12
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
13
13
|
function getConfigDir() {
|
|
@@ -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",
|
|
@@ -14281,7 +14512,7 @@ ${typeDef}`);
|
|
|
14281
14512
|
__name(renderDocs, "renderDocs");
|
|
14282
14513
|
var __filename$1 = fileURLToPath(import.meta.url);
|
|
14283
14514
|
var __dirname$1 = path.dirname(__filename$1);
|
|
14284
|
-
var VERSION = "0.0.
|
|
14515
|
+
var VERSION = "0.0.5" ;
|
|
14285
14516
|
var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
|
|
14286
14517
|
var client = createTRPCClient({
|
|
14287
14518
|
links: [
|
|
@@ -14413,8 +14644,8 @@ async function readStdin() {
|
|
|
14413
14644
|
return Buffer.concat(chunks).toString("utf-8");
|
|
14414
14645
|
}
|
|
14415
14646
|
__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)").
|
|
14417
|
-
const { session: sessionId, eval: evalCode
|
|
14647
|
+
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) => {
|
|
14648
|
+
const { session: sessionId, eval: evalCode } = options;
|
|
14418
14649
|
let code = evalCode;
|
|
14419
14650
|
if (!code && !process.stdin.isTTY) {
|
|
14420
14651
|
code = await readStdin();
|
|
@@ -14435,7 +14666,6 @@ program.option("-s, --session <id>", "Session ID (required for code execution)")
|
|
|
14435
14666
|
const result = await client.exec.mutate({
|
|
14436
14667
|
sessionId: String(sessionId),
|
|
14437
14668
|
code,
|
|
14438
|
-
timeout: parseInt(timeout, 10),
|
|
14439
14669
|
cwd: process.cwd()
|
|
14440
14670
|
});
|
|
14441
14671
|
for (const line of result.output) {
|
|
@@ -13,7 +13,7 @@ import { createRequire } from 'module';
|
|
|
13
13
|
import * as vm from 'vm';
|
|
14
14
|
import { connect } from 'framer-api';
|
|
15
15
|
|
|
16
|
-
/* @framer/ai relay server v0.0.
|
|
16
|
+
/* @framer/ai relay server v0.0.5 */
|
|
17
17
|
var __defProp = Object.defineProperty;
|
|
18
18
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
19
19
|
function getLogPath() {
|
|
@@ -50,7 +50,7 @@ function log(message) {
|
|
|
50
50
|
__name(log, "log");
|
|
51
51
|
var __filename$1 = fileURLToPath(import.meta.url);
|
|
52
52
|
path.dirname(__filename$1);
|
|
53
|
-
var VERSION = "0.0.
|
|
53
|
+
var VERSION = "0.0.5" ;
|
|
54
54
|
var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
|
|
55
55
|
createTRPCClient({
|
|
56
56
|
links: [
|
|
@@ -266,8 +266,8 @@ var ScopedFS = class {
|
|
|
266
266
|
constants = fs2.constants;
|
|
267
267
|
};
|
|
268
268
|
|
|
269
|
-
// src/
|
|
270
|
-
var
|
|
269
|
+
// src/execute.ts
|
|
270
|
+
var EXECUTION_TIMEOUT = 10 * 60 * 1e3;
|
|
271
271
|
var baseRequire = createRequire(import.meta.url);
|
|
272
272
|
var ALLOWED_MODULES = /* @__PURE__ */ new Set([
|
|
273
273
|
"path",
|
|
@@ -329,7 +329,7 @@ async function sandboxedImport(scopedFs, specifier) {
|
|
|
329
329
|
}
|
|
330
330
|
__name(sandboxedImport, "sandboxedImport");
|
|
331
331
|
async function execute(session, framer, code, options = {}) {
|
|
332
|
-
const {
|
|
332
|
+
const { cwd } = options;
|
|
333
333
|
const output = [];
|
|
334
334
|
const customConsole = {
|
|
335
335
|
log: /* @__PURE__ */ __name((...args) => {
|
|
@@ -376,22 +376,24 @@ async function execute(session, framer, code, options = {}) {
|
|
|
376
376
|
};
|
|
377
377
|
const vmContext = vm.createContext(vmContextObj);
|
|
378
378
|
const wrappedCode = `(async () => { ${code} })()`;
|
|
379
|
+
let timeoutId;
|
|
379
380
|
try {
|
|
380
381
|
const script = new vm.Script(wrappedCode, {
|
|
381
382
|
filename: "framer-exec.js"
|
|
382
383
|
});
|
|
383
384
|
const resultPromise = script.runInContext(vmContext, {
|
|
384
385
|
timeout: 5e3
|
|
385
|
-
// Short timeout for sync part
|
|
386
386
|
});
|
|
387
387
|
const result = await Promise.race([
|
|
388
388
|
resultPromise,
|
|
389
|
-
new Promise(
|
|
390
|
-
|
|
391
|
-
() => reject(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
389
|
+
new Promise((_, reject) => {
|
|
390
|
+
timeoutId = setTimeout(
|
|
391
|
+
() => reject(
|
|
392
|
+
new Error(`Execution timed out after ${EXECUTION_TIMEOUT}ms`)
|
|
393
|
+
),
|
|
394
|
+
EXECUTION_TIMEOUT
|
|
395
|
+
);
|
|
396
|
+
})
|
|
395
397
|
]);
|
|
396
398
|
if (result !== void 0) {
|
|
397
399
|
output.push(formatValue(result));
|
|
@@ -403,9 +405,42 @@ async function execute(session, framer, code, options = {}) {
|
|
|
403
405
|
output,
|
|
404
406
|
error: errorMessage
|
|
405
407
|
};
|
|
408
|
+
} finally {
|
|
409
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
406
410
|
}
|
|
407
411
|
}
|
|
408
412
|
__name(execute, "execute");
|
|
413
|
+
async function executeWithReconnect(session, framer, code, options, reconnect) {
|
|
414
|
+
const result = await tryExecute(session, framer, code, options);
|
|
415
|
+
if (!result.error || !isConnectionError(result.error)) {
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
log(
|
|
419
|
+
`reconnect session=${session.id} project=${session.projectId} reason="${result.error}"`
|
|
420
|
+
);
|
|
421
|
+
const newFramer = await reconnect();
|
|
422
|
+
if (!newFramer) {
|
|
423
|
+
log(
|
|
424
|
+
`reconnect.failed session=${session.id} error="no connection returned"`
|
|
425
|
+
);
|
|
426
|
+
return {
|
|
427
|
+
output: [],
|
|
428
|
+
error: "Connection lost and failed to reconnect"
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
log(`reconnect.success session=${session.id}`);
|
|
432
|
+
return tryExecute(session, newFramer, code, options);
|
|
433
|
+
}
|
|
434
|
+
__name(executeWithReconnect, "executeWithReconnect");
|
|
435
|
+
async function tryExecute(session, framer, code, options) {
|
|
436
|
+
try {
|
|
437
|
+
return await execute(session, framer, code, options);
|
|
438
|
+
} catch (err) {
|
|
439
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
440
|
+
return { output: [], error };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
__name(tryExecute, "tryExecute");
|
|
409
444
|
function formatValue(value) {
|
|
410
445
|
if (value === null) return "null";
|
|
411
446
|
if (value === void 0) return "undefined";
|
|
@@ -431,6 +466,7 @@ var ConnectionPool = class {
|
|
|
431
466
|
__name(this, "ConnectionPool");
|
|
432
467
|
}
|
|
433
468
|
pool = /* @__PURE__ */ new Map();
|
|
469
|
+
reconnectPromises = /* @__PURE__ */ new Map();
|
|
434
470
|
/**
|
|
435
471
|
* Acquire a connection for a session.
|
|
436
472
|
* If a connection already exists for the project, the session is added to it.
|
|
@@ -458,15 +494,26 @@ var ConnectionPool = class {
|
|
|
458
494
|
}
|
|
459
495
|
/**
|
|
460
496
|
* Reconnect a project's connection (call after catching a connection error).
|
|
461
|
-
*
|
|
497
|
+
* Concurrent callers for the same project share a single reconnect attempt.
|
|
462
498
|
*/
|
|
463
499
|
async reconnect(projectId) {
|
|
500
|
+
const existingPromise = this.reconnectPromises.get(projectId);
|
|
501
|
+
if (existingPromise) return existingPromise;
|
|
502
|
+
const promise = this.doReconnect(projectId).finally(() => {
|
|
503
|
+
this.reconnectPromises.delete(projectId);
|
|
504
|
+
});
|
|
505
|
+
this.reconnectPromises.set(projectId, promise);
|
|
506
|
+
return promise;
|
|
507
|
+
}
|
|
508
|
+
async doReconnect(projectId) {
|
|
464
509
|
const entry = this.pool.get(projectId);
|
|
465
|
-
if (!entry)
|
|
510
|
+
if (!entry) return null;
|
|
511
|
+
try {
|
|
512
|
+
await entry.connection.reconnect();
|
|
513
|
+
return entry.connection;
|
|
514
|
+
} catch {
|
|
466
515
|
return null;
|
|
467
516
|
}
|
|
468
|
-
await entry.connection.reconnect();
|
|
469
|
-
return entry.connection;
|
|
470
517
|
}
|
|
471
518
|
/**
|
|
472
519
|
* Release a session from a connection.
|
|
@@ -570,11 +617,10 @@ var appRouter = t.router({
|
|
|
570
617
|
z.object({
|
|
571
618
|
sessionId: z.string(),
|
|
572
619
|
code: z.string(),
|
|
573
|
-
timeout: z.number().default(3e4),
|
|
574
620
|
cwd: z.string().optional()
|
|
575
621
|
})
|
|
576
622
|
).mutation(async ({ input }) => {
|
|
577
|
-
const { sessionId, code,
|
|
623
|
+
const { sessionId, code, cwd } = input;
|
|
578
624
|
const session = sessionManager.get(sessionId);
|
|
579
625
|
if (!session) {
|
|
580
626
|
throw new TRPCError({
|
|
@@ -585,43 +631,20 @@ var appRouter = t.router({
|
|
|
585
631
|
log(
|
|
586
632
|
`exec session=${sessionId} code=${JSON.stringify(code).slice(0, 100)}`
|
|
587
633
|
);
|
|
588
|
-
|
|
634
|
+
const framer = sessionManager.getFramer(session);
|
|
589
635
|
if (!framer) {
|
|
590
636
|
return {
|
|
591
637
|
output: [],
|
|
592
638
|
error: "Failed to get connection for session"
|
|
593
639
|
};
|
|
594
640
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
if (result.error && isConnectionError(result.error)) {
|
|
603
|
-
log(
|
|
604
|
-
`reconnect session=${sessionId} project=${session.projectId} reason="${result.error}"`
|
|
605
|
-
);
|
|
606
|
-
framer = await sessionManager.reconnect(session);
|
|
607
|
-
if (framer) {
|
|
608
|
-
try {
|
|
609
|
-
result = await execute(session, framer, code, {
|
|
610
|
-
timeout,
|
|
611
|
-
cwd
|
|
612
|
-
});
|
|
613
|
-
log(`reconnect.success session=${sessionId}`);
|
|
614
|
-
} catch (retryErr) {
|
|
615
|
-
const errMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
616
|
-
log(`reconnect.failed session=${sessionId} error="${errMsg}"`);
|
|
617
|
-
result = { output: [], error: errMsg };
|
|
618
|
-
}
|
|
619
|
-
} else {
|
|
620
|
-
log(
|
|
621
|
-
`reconnect.failed session=${sessionId} error="no connection returned"`
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
641
|
+
const result = await executeWithReconnect(
|
|
642
|
+
session,
|
|
643
|
+
framer,
|
|
644
|
+
code,
|
|
645
|
+
{ cwd },
|
|
646
|
+
() => sessionManager.reconnect(session)
|
|
647
|
+
);
|
|
625
648
|
if (result.error) {
|
|
626
649
|
log(`exec.error session=${sessionId} error="${result.error}"`);
|
|
627
650
|
}
|
package/docs/server-api.md
CHANGED
|
@@ -73,8 +73,6 @@ npx framer-dalton session list
|
|
|
73
73
|
npx framer-dalton -s <sessionId> -e "<code>"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
Default timeout is 30 seconds. Increase with `--timeout <ms>`.
|
|
77
|
-
|
|
78
76
|
**Escaping:** For code with HTML, quotes, or special characters, use a heredoc (see below). For simple strings, use `$'...'` syntax.
|
|
79
77
|
|
|
80
78
|
**Examples:**
|
|
@@ -606,7 +604,10 @@ Server API exclusive methods for capturing visual output from nodes.
|
|
|
606
604
|
const result = await framer.screenshot(node.id);
|
|
607
605
|
console.log(result.mimeType); // "image/png"
|
|
608
606
|
const os = require("os");
|
|
609
|
-
await require("fs").promises.writeFile(
|
|
607
|
+
await require("fs").promises.writeFile(
|
|
608
|
+
os.tmpdir() + "/screenshot.png",
|
|
609
|
+
result.data,
|
|
610
|
+
);
|
|
610
611
|
|
|
611
612
|
// With options
|
|
612
613
|
const jpg = await framer.screenshot(node.id, {
|
|
@@ -667,12 +668,75 @@ const contributors = await framer.getChangeContributors();
|
|
|
667
668
|
|
|
668
669
|
---
|
|
669
670
|
|
|
671
|
+
## Canvas Editing
|
|
672
|
+
|
|
673
|
+
**Use this for all design tasks** — creating pages, building sections, recreating designs from screenshots, or any task that involves layout or visual styling on the canvas.
|
|
674
|
+
|
|
675
|
+
**Hard rule:** For design/layout work, do **not** use low-level node APIs (`createNode`, `setAttributes`, `setRect`, etc.). Always use the canvas editing flow (`getAgentSystemPrompt` + `getAgentContext` + `readProjectForAgent` + `applyAgentChanges`). If you start writing low-level node code for design work, stop and switch to canvas editing methods.
|
|
676
|
+
|
|
677
|
+
**Access note:** Canvas editing `agent` methods are employee-only. If these methods fail or are unavailable, the account likely does not have employee access.
|
|
678
|
+
|
|
679
|
+
### Methods
|
|
680
|
+
|
|
681
|
+
**`framer.getAgentSystemPrompt()`** — Returns the command reference, design rules, layout patterns, and examples. This is the sole documentation for the command syntax and query types. It is static (same for every project) — fetch once per session and persist to a file.
|
|
682
|
+
|
|
683
|
+
**`framer.getAgentContext({ pagePath })`** — Returns the project's available fonts, components, color tokens, text style presets, and icon sets for the target page scope. Fetch before generating commands and use the same `pagePath` across context/read/apply calls.
|
|
684
|
+
|
|
685
|
+
**`framer.readProjectForAgent(queries, { pagePath })`** — Reads project state. Query types are documented in the system prompt. Use liberally — query the page tree, icon sets, components, and examples before generating commands. Multiple queries can be batched in a single call. Never guess at names for examples, icon sets, or fonts — always look them up first.
|
|
686
|
+
|
|
687
|
+
**`framer.applyAgentChanges(dsl, { pagePath })`** — Applies commands to the canvas. Node IDs you assign are temporary — re-read the page tree via `readProjectForAgent` if you need actual IDs after applying.
|
|
688
|
+
|
|
689
|
+
### Workflow
|
|
690
|
+
|
|
691
|
+
```js
|
|
692
|
+
// 1. Save the system prompt to a file (once per session).
|
|
693
|
+
const fs = require("fs");
|
|
694
|
+
const prompt = await framer.getAgentSystemPrompt();
|
|
695
|
+
fs.writeFileSync("/tmp/framer-canvas-reference.txt", prompt);
|
|
696
|
+
console.log("Saved to /tmp/framer-canvas-reference.txt —", prompt.length, "chars");
|
|
697
|
+
|
|
698
|
+
// 2. Get project context
|
|
699
|
+
const projectCtx = await framer.getAgentContext({ pagePath: "/" });
|
|
700
|
+
console.log(projectCtx);
|
|
701
|
+
|
|
702
|
+
// 3. Read project state (query types are in the prompt)
|
|
703
|
+
const { results } = await framer.readProjectForAgent(
|
|
704
|
+
[{ type: "page", path: "/" }],
|
|
705
|
+
{ pagePath: "/" }
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
// 4. Apply changes
|
|
709
|
+
await framer.applyAgentChanges(dsl, { pagePath: "/" });
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
**You must read the entire system prompt file before writing any commands.** It contains command syntax, design rules, layout patterns, examples, and query documentation. Skipping sections will cause incorrect output.
|
|
713
|
+
|
|
714
|
+
After applying changes, take screenshots to inspect the result. Check padding, spacing, typography, icon choice, and alignment. Iterate with additional `readProjectForAgent` + `applyAgentChanges` passes until visually accurate.
|
|
715
|
+
|
|
716
|
+
When setting text content, use raw Unicode characters directly (e.g. `→` not `\u2192`).
|
|
717
|
+
|
|
718
|
+
Always fetch fresh context per session — the format may change between versions.
|
|
719
|
+
|
|
720
|
+
### What canvas editing can do
|
|
721
|
+
|
|
722
|
+
Beyond basic page layout, the command language supports:
|
|
723
|
+
|
|
724
|
+
- **Colour tokens** — Create color tokens (`ColorStyleTokenNode`) with light/dark mode variants. Reference them across the project for consistent theming.
|
|
725
|
+
- **Text style presets** — Create reusable typography presets (`TextStylePresetNode`) and apply them to text nodes. Build full typographic systems (headings, body, captions, etc.).
|
|
726
|
+
- **Smart components** — Author reusable components (`ComponentNode`) with multiple visual variants, scoped variables, and property controls. Instantiate them anywhere with `ComponentInstanceNode`.
|
|
727
|
+
- **Interactive effects** — Add hover effects (scale, opacity, color), tap effects, scroll-triggered appear animations, transitions between component variants, and event handlers.
|
|
728
|
+
- **Icon sets** — Insert icons from named vector sets. Query available sets and icons via `readProjectForAgent`.
|
|
729
|
+
- **Responsive breakpoints** — Create page breakpoints (Desktop, Tablet, Mobile) using the replica/variant system, with per-breakpoint overrides.
|
|
730
|
+
- **Complex layouts** — Stack and grid layouts with auto-fill, fractional units, space-between distribution, and nested grids for asymmetric layouts.
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
670
734
|
## Capabilities
|
|
671
735
|
|
|
672
736
|
What you can do with the Framer CLI:
|
|
673
737
|
|
|
738
|
+
- **Canvas Editing** For design tasks — creating or editing pages, sections, layouts, recreating designs from screenshots, etc.
|
|
674
739
|
- **CMS**: Create, read, update, delete collections and items. Sync external databases.
|
|
675
|
-
- **Canvas**: Create and modify frames, text, images, SVGs. Build layouts programmatically.
|
|
676
740
|
- **Styles**: Manage color and text styles. Sync design systems.
|
|
677
741
|
- **Code Components**: Create, edit, type-check, and add custom React components to the canvas.
|
|
678
742
|
- **Assets**: Upload and manage images and files.
|
|
@@ -680,12 +744,12 @@ What you can do with the Framer CLI:
|
|
|
680
744
|
- **Data**: Store metadata on nodes and projects for plugin state.
|
|
681
745
|
- **Screenshots**: Capture node screenshots as PNG/JPEG. Export nodes as SVG.
|
|
682
746
|
- **Publishing**: Publish projects, manage deployments, track changes.
|
|
747
|
+
- **Low-level Node APIs**: Create and modify individual nodes. Only use these for targeted, surgical edits to specific nodes — not for building pages or layouts.
|
|
683
748
|
|
|
684
749
|
---
|
|
685
750
|
|
|
686
751
|
## Known Limitations
|
|
687
752
|
|
|
688
753
|
- **Pages**: No list, delete, update, move, or settings APIs (create only)
|
|
689
|
-
- **Canvas/design work**: Not viable via API. Can create/read nodes but limited modification support (transforms, constraints, layout)
|
|
690
754
|
- **Code overrides**: Cannot assign overrides to nodes
|
|
691
|
-
|
|
755
|
+
- **Analytics**: No APIs exist for accessing analytics data
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "framer-dalton",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"framer-dalton": "./dist/cli.js"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@trpc/client": "^11.9.0",
|
|
26
26
|
"@trpc/server": "^11.9.0",
|
|
27
27
|
"commander": "^12.1.0",
|
|
28
|
-
"framer-api": "
|
|
28
|
+
"framer-api": "https://pkg.pr.new/framer/FramerStudio/framer-api@5804b52.tgz",
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|